diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-10-02 16:04:25 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-10-02 16:04:26 +0100 |
commit | 945507d6bcde334f42b00cae134b4d47301d1821 (patch) | |
tree | 17def01738f02281bb54424f3021be8a57d884ac | |
parent | 37dd86a44cc4298f58ac370e0190b069469b6d25 (diff) | |
parent | 86abac06c142d20772b3f2e04c9bf02b7936a0b3 (diff) | |
download | qemu-945507d6bcde334f42b00cae134b4d47301d1821.zip qemu-945507d6bcde334f42b00cae134b4d47301d1821.tar.gz qemu-945507d6bcde334f42b00cae134b4d47301d1821.tar.bz2 |
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20151002' into staging
First set of Linux-user que patches for 2.5
# gpg: Signature made Fri 02 Oct 2015 13:38:00 BST using RSA key ID DE3C9BC0
# gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>"
# gpg: aka "Riku Voipio <riku.voipio@linaro.org>"
* remotes/riku/tags/pull-linux-user-20151002:
linux-user: assert that target_mprotect cannot fail
linux-user/signal.c: Use setup_rt_frame() instead of setup_frame() for target openrisc
linux-user/syscall.c: Add EAGAIN to host_to_target_errno_table for
linux-user: add name_to_handle_at/open_by_handle_at
linux-user: Return target error number in do_fork()
linux-user: fix cmsg conversion in case of multiple headers
linux-user: remove MAX_ARG_PAGES limit
linux-user: remove unused image_info members
linux-user: Treat --foo options the same as -foo
linux-user: use EXIT_SUCCESS and EXIT_FAILURE
linux-user: Add proper error messages for bad options
linux-user: Add -help
linux-user: Exit 0 when -h is used
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | linux-user/elfload.c | 113 | ||||
-rw-r--r-- | linux-user/flatload.c | 2 | ||||
-rw-r--r-- | linux-user/linuxload.c | 7 | ||||
-rw-r--r-- | linux-user/main.c | 88 | ||||
-rw-r--r-- | linux-user/mmap.c | 5 | ||||
-rw-r--r-- | linux-user/qemu.h | 9 | ||||
-rw-r--r-- | linux-user/signal.c | 9 | ||||
-rw-r--r-- | linux-user/syscall.c | 124 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 14 |
9 files changed, 228 insertions, 143 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index a7ff58c..fdae6a6 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1373,66 +1373,69 @@ static bool elf_check_ehdr(struct elfhdr *ehdr) * to be put directly into the top of new user memory. * */ -static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, - abi_ulong p) +static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch, + abi_ulong p, abi_ulong stack_limit) { - char *tmp, *tmp1, *pag = NULL; - int len, offset = 0; + char *tmp; + int len, offset; + abi_ulong top = p; if (!p) { return 0; /* bullet-proofing */ } + + offset = ((p - 1) % TARGET_PAGE_SIZE) + 1; + while (argc-- > 0) { tmp = argv[argc]; if (!tmp) { fprintf(stderr, "VFS: argc is wrong"); exit(-1); } - tmp1 = tmp; - while (*tmp++); - len = tmp - tmp1; - if (p < len) { /* this shouldn't happen - 128kB */ + len = strlen(tmp) + 1; + tmp += len; + + if (len > (p - stack_limit)) { return 0; } while (len) { - --p; --tmp; --len; - if (--offset < 0) { - offset = p % TARGET_PAGE_SIZE; - pag = (char *)page[p/TARGET_PAGE_SIZE]; - if (!pag) { - pag = g_try_malloc0(TARGET_PAGE_SIZE); - page[p/TARGET_PAGE_SIZE] = pag; - if (!pag) - return 0; - } - } - if (len == 0 || offset == 0) { - *(pag + offset) = *tmp; - } - else { - int bytes_to_copy = (len > offset) ? offset : len; - tmp -= bytes_to_copy; - p -= bytes_to_copy; - offset -= bytes_to_copy; - len -= bytes_to_copy; - memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + + memcpy_fromfs(scratch + offset, tmp, bytes_to_copy); + + if (offset == 0) { + memcpy_to_target(p, scratch, top - p); + top = p; + offset = TARGET_PAGE_SIZE; } } } + if (offset) { + memcpy_to_target(p, scratch + offset, top - p); + } + return p; } -static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, +/* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of + * argument/environment space. Newer kernels (>2.6.33) allow more, + * dependent on stack size, but guarantee at least 32 pages for + * backwards compatibility. + */ +#define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE) + +static abi_ulong setup_arg_pages(struct linux_binprm *bprm, struct image_info *info) { - abi_ulong stack_base, size, error, guard; - int i; + abi_ulong size, error, guard; - /* Create enough stack to hold everything. If we don't use - it for args, we'll use it for something else. */ size = guest_stack_size; - if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) { - size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + if (size < STACK_LOWER_LIMIT) { + size = STACK_LOWER_LIMIT; } guard = TARGET_PAGE_SIZE; if (guard < qemu_real_host_page_size) { @@ -1450,19 +1453,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, target_mprotect(error, guard, PROT_NONE); info->stack_limit = error + guard; - stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; - p += stack_base; - - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - info->rss++; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); - g_free(bprm->page[i]); - } - stack_base += TARGET_PAGE_SIZE; - } - return p; + + return info->stack_limit + size - sizeof(void *); } /* Map and zero the bss. We need to explicitly zero any fractional pages @@ -2204,10 +2196,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) struct image_info interp_info; struct elfhdr elf_ex; char *elf_interpreter = NULL; + char *scratch; info->start_mmap = (abi_ulong)ELF_START_MMAP; - info->mmap = 0; - info->rss = 0; load_elf_image(bprm->filename, bprm->fd, info, &elf_interpreter, bprm->buf); @@ -2217,18 +2208,24 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) when we load the interpreter. */ elf_ex = *(struct elfhdr *)bprm->buf; - bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); - bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); - bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + bprm->p = setup_arg_pages(bprm, info); + + scratch = g_new0(char, TARGET_PAGE_SIZE); + bprm->p = copy_elf_strings(1, &bprm->filename, scratch, + bprm->p, info->stack_limit); + bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch, + bprm->p, info->stack_limit); + bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch, + bprm->p, info->stack_limit); + g_free(scratch); + if (!bprm->p) { fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG)); exit(-1); } - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ - bprm->p = setup_arg_pages(bprm->p, bprm, info); - if (elf_interpreter) { load_elf_interp(elf_interpreter, &interp_info, bprm->buf); diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 566a7a8..ceacb98 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -707,7 +707,7 @@ static int load_flat_shared_library(int id, struct lib_info *libs) int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) { struct lib_info libinfo[MAX_SHARED_LIBS]; - abi_ulong p = bprm->p; + abi_ulong p; abi_ulong stack_len; abi_ulong start_addr; abi_ulong sp; diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 506e837..dbaf0ec 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -135,10 +135,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, struct linux_binprm *bprm) { int retval; - int i; - bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); - memset(bprm->page, 0, sizeof(bprm->page)); bprm->fd = fdexec; bprm->filename = (char *)filename; bprm->argc = count(argv); @@ -172,9 +169,5 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, return retval; } - /* Something went wrong, return the inode and free the argument pages*/ - for (i=0 ; i<MAX_ARG_PAGES ; i++) { - g_free(bprm->page[i]); - } return(retval); } diff --git a/linux-user/main.c b/linux-user/main.c index 25cf875..6599a41 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -63,7 +63,7 @@ unsigned long reserved_va = 0xf7000000; unsigned long reserved_va; #endif -static void usage(void); +static void usage(int exitcode); static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; @@ -1414,7 +1414,7 @@ void cpu_loop (CPUSPARCState *env) default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -2662,7 +2662,7 @@ void cpu_loop(CPUOpenRISCState *env) switch (trapnr) { case EXCP_RESET: qemu_log("\nReset request, exit, pc is %#x\n", env->pc); - exit(1); + exit(EXIT_FAILURE); break; case EXCP_BUSERR: qemu_log("\nBus error, exit, pc is %#x\n", env->pc); @@ -2726,7 +2726,7 @@ void cpu_loop(CPUOpenRISCState *env) if (gdbsig) { gdb_handlesig(cs, gdbsig); if (gdbsig != TARGET_SIGTRAP) { - exit(1); + exit(EXIT_FAILURE); } } @@ -2791,7 +2791,7 @@ void cpu_loop(CPUSH4State *env) default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -2852,7 +2852,7 @@ void cpu_loop(CPUCRISState *env) default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -2933,7 +2933,7 @@ void cpu_loop(CPUMBState *env) printf ("Unhandled hw-exception: 0x%x\n", env->sregs[SR_ESR] & ESR_EC_MASK); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); break; } break; @@ -2954,7 +2954,7 @@ void cpu_loop(CPUMBState *env) default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -3123,17 +3123,17 @@ void cpu_loop(CPUAlphaState *env) switch (trapnr) { case EXCP_RESET: fprintf(stderr, "Reset requested. Exit\n"); - exit(1); + exit(EXIT_FAILURE); break; case EXCP_MCHK: fprintf(stderr, "Machine check exception. Exit\n"); - exit(1); + exit(EXIT_FAILURE); break; case EXCP_SMP_INTERRUPT: case EXCP_CLK_INTERRUPT: case EXCP_DEV_INTERRUPT: fprintf(stderr, "External interrupt. Exit\n"); - exit(1); + exit(EXIT_FAILURE); break; case EXCP_MMFAULT: env->lock_addr = -1; @@ -3283,7 +3283,7 @@ void cpu_loop(CPUAlphaState *env) default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit (1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -3387,7 +3387,7 @@ void cpu_loop(CPUS390XState *env) default: fprintf(stderr, "Unhandled program exception: %#x\n", n); cpu_dump_state(cs, stderr, fprintf, 0); - exit(1); + exit(EXIT_FAILURE); } break; @@ -3404,7 +3404,7 @@ void cpu_loop(CPUS390XState *env) default: fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); - exit(1); + exit(EXIT_FAILURE); } process_pending_signals (env); } @@ -3700,7 +3700,7 @@ CPUArchState *cpu_copy(CPUArchState *env) static void handle_arg_help(const char *arg) { - usage(); + usage(EXIT_SUCCESS); } static void handle_arg_log(const char *arg) @@ -3710,7 +3710,7 @@ static void handle_arg_log(const char *arg) mask = qemu_str_to_log_mask(arg); if (!mask) { qemu_print_log_usage(stdout); - exit(1); + exit(EXIT_FAILURE); } qemu_set_log(mask); } @@ -3726,7 +3726,7 @@ static void handle_arg_set_env(const char *arg) r = p = strdup(arg); while ((token = strsep(&p, ",")) != NULL) { if (envlist_setenv(envlist, token) != 0) { - usage(); + usage(EXIT_FAILURE); } } free(r); @@ -3738,7 +3738,7 @@ static void handle_arg_unset_env(const char *arg) r = p = strdup(arg); while ((token = strsep(&p, ",")) != NULL) { if (envlist_unsetenv(envlist, token) != 0) { - usage(); + usage(EXIT_FAILURE); } } free(r); @@ -3754,7 +3754,7 @@ static void handle_arg_stack_size(const char *arg) char *p; guest_stack_size = strtoul(arg, &p, 0); if (guest_stack_size == 0) { - usage(); + usage(EXIT_FAILURE); } if (*p == 'M') { @@ -3775,7 +3775,7 @@ static void handle_arg_pagesize(const char *arg) if (qemu_host_page_size == 0 || (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { fprintf(stderr, "page size must be a power of two\n"); - exit(1); + exit(EXIT_FAILURE); } } @@ -3785,7 +3785,7 @@ static void handle_arg_randseed(const char *arg) if (parse_uint_full(arg, &seed, 0) != 0 || seed > UINT_MAX) { fprintf(stderr, "Invalid seed number: %s\n", arg); - exit(1); + exit(EXIT_FAILURE); } srand(seed); } @@ -3808,7 +3808,7 @@ static void handle_arg_cpu(const char *arg) #if defined(cpu_list) cpu_list(stdout, &fprintf); #endif - exit(1); + exit(EXIT_FAILURE); } } @@ -3845,12 +3845,12 @@ static void handle_arg_reserved_va(const char *arg) #endif ) { fprintf(stderr, "Reserved virtual address too big\n"); - exit(1); + exit(EXIT_FAILURE); } } if (*p) { fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p); - exit(1); + exit(EXIT_FAILURE); } } @@ -3868,7 +3868,7 @@ static void handle_arg_version(const char *arg) { printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"); - exit(0); + exit(EXIT_SUCCESS); } struct qemu_argument { @@ -3883,6 +3883,8 @@ struct qemu_argument { static const struct qemu_argument arg_table[] = { {"h", "", false, handle_arg_help, "", "print this help"}, + {"help", "", false, handle_arg_help, + "", ""}, {"g", "QEMU_GDB", true, handle_arg_gdb, "port", "wait gdb connection to 'port'"}, {"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix, @@ -3921,7 +3923,7 @@ static const struct qemu_argument arg_table[] = { {NULL, NULL, false, NULL, NULL, NULL} }; -static void usage(void) +static void usage(int exitcode) { const struct qemu_argument *arginfo; int maxarglen; @@ -3988,7 +3990,7 @@ static void usage(void) "Note that if you provide several changes to a single variable\n" "the last change will stay in effect.\n"); - exit(1); + exit(exitcode); } static int parse_args(int argc, char **argv) @@ -4022,12 +4024,18 @@ static int parse_args(int argc, char **argv) if (!strcmp(r, "-")) { break; } + /* Treat --foo the same as -foo. */ + if (r[0] == '-') { + r++; + } for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { if (!strcmp(r, arginfo->argv)) { if (arginfo->has_arg) { if (optind >= argc) { - usage(); + (void) fprintf(stderr, + "qemu: missing argument for option '%s'\n", r); + exit(EXIT_FAILURE); } arginfo->handle_opt(argv[optind]); optind++; @@ -4040,12 +4048,14 @@ static int parse_args(int argc, char **argv) /* no option matched the current argv */ if (arginfo->handle_opt == NULL) { - usage(); + (void) fprintf(stderr, "qemu: unknown option '%s'\n", r); + exit(EXIT_FAILURE); } } if (optind >= argc) { - usage(); + (void) fprintf(stderr, "qemu: no user program specified\n"); + exit(EXIT_FAILURE); } filename = argv[optind]; @@ -4074,7 +4084,7 @@ int main(int argc, char **argv, char **envp) if ((envlist = envlist_create()) == NULL) { (void) fprintf(stderr, "Unable to allocate envlist\n"); - exit(1); + exit(EXIT_FAILURE); } /* add current environment into the list */ @@ -4160,7 +4170,7 @@ int main(int argc, char **argv, char **envp) cpu = cpu_init(cpu_model); if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); + exit(EXIT_FAILURE); } env = cpu->env_ptr; cpu_reset(cpu); @@ -4192,7 +4202,7 @@ int main(int argc, char **argv, char **envp) "space for use as guest address space (check your virtual " "memory ulimit setting or reserve less using -R option)\n", reserved_va); - exit(1); + exit(EXIT_FAILURE); } if (reserved_va) { @@ -4225,7 +4235,7 @@ int main(int argc, char **argv, char **envp) target_argv = calloc(target_argc + 1, sizeof (char *)); if (target_argv == NULL) { (void) fprintf(stderr, "Unable to allocate memory for target_argv\n"); - exit(1); + exit(EXIT_FAILURE); } /* @@ -4254,7 +4264,7 @@ int main(int argc, char **argv, char **envp) execfd = open(filename, O_RDONLY); if (execfd < 0) { printf("Error while loading %s: %s\n", filename, strerror(errno)); - _exit(1); + _exit(EXIT_FAILURE); } } @@ -4262,7 +4272,7 @@ int main(int argc, char **argv, char **envp) info, &bprm); if (ret != 0) { printf("Error while loading %s: %s\n", filename, strerror(-ret)); - _exit(1); + _exit(EXIT_FAILURE); } for (wrk = target_environ; *wrk; wrk++) { @@ -4308,7 +4318,7 @@ int main(int argc, char **argv, char **envp) /* enable 64 bit mode if possible */ if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); - exit(1); + exit(EXIT_FAILURE); } env->cr[4] |= CR4_PAE_MASK; env->efer |= MSR_EFER_LMA | MSR_EFER_LME; @@ -4418,7 +4428,7 @@ int main(int argc, char **argv, char **envp) if (!(arm_feature(env, ARM_FEATURE_AARCH64))) { fprintf(stderr, "The selected ARM CPU does not support 64 bit mode\n"); - exit(1); + exit(EXIT_FAILURE); } for (i = 0; i < 31; i++) { @@ -4630,7 +4640,7 @@ int main(int argc, char **argv, char **envp) if (gdbserver_start(gdbstub_port) < 0) { fprintf(stderr, "qemu: could not open gdbserver on port %d\n", gdbstub_port); - exit(1); + exit(EXIT_FAILURE); } gdb_handlesig(cpu, 0); } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index b2126c7..5606bcd 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -514,10 +514,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, goto fail; if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); - if (ret != 0) { - start = ret; - goto the_end; - } + assert(ret == 0); } goto the_end; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index e8606b2..bd90cc3 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -36,8 +36,6 @@ struct image_info { abi_ulong start_brk; abi_ulong brk; abi_ulong start_mmap; - abi_ulong mmap; - abi_ulong rss; abi_ulong start_stack; abi_ulong stack_limit; abi_ulong entry; @@ -145,12 +143,6 @@ extern const char *qemu_uname_release; extern unsigned long mmap_min_addr; /* ??? See if we can avoid exposing so much of the loader internals. */ -/* - * MAX_ARG_PAGES defines the number of pages allocated for arguments - * and envelope for the new program. 32 should suffice, this gives - * a maximum env+arg of 128kB w/4KB pages! - */ -#define MAX_ARG_PAGES 33 /* Read a good amount of data initially, to hopefully get all the program headers loaded. */ @@ -162,7 +154,6 @@ extern unsigned long mmap_min_addr; */ struct linux_binprm { char buf[BPRM_BUF_SIZE] __attribute__((aligned)); - void *page[MAX_ARG_PAGES]; abi_ulong p; int fd; int e_uid, e_gid; diff --git a/linux-user/signal.c b/linux-user/signal.c index 502efd9..ac82baa 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -3900,12 +3900,6 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka, return sp; } -static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUOpenRISCState *env) -{ - qemu_log("Not implement.\n"); -} - static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUOpenRISCState *env) @@ -5662,7 +5656,8 @@ void process_pending_signals(CPUArchState *cpu_env) } #endif /* prepare the stack frame of the virtual CPU */ -#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ + || defined(TARGET_OPENRISC) /* These targets do not have traditional signals. */ setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env); #else diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d1d3eb2..98b5766 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -457,6 +457,7 @@ static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = { * minus the errnos that are not actually generic to all archs. */ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { + [EAGAIN] = TARGET_EAGAIN, [EIDRM] = TARGET_EIDRM, [ECHRNG] = TARGET_ECHRNG, [EL2NSYNC] = TARGET_EL2NSYNC, @@ -1181,7 +1182,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); abi_long msg_controllen; abi_ulong target_cmsg_addr; - struct target_cmsghdr *target_cmsg; + struct target_cmsghdr *target_cmsg, *target_cmsg_start; socklen_t space = 0; msg_controllen = tswapal(target_msgh->msg_controllen); @@ -1189,6 +1190,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, goto the_end; target_cmsg_addr = tswapal(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); + target_cmsg_start = target_cmsg; if (!target_cmsg) return -TARGET_EFAULT; @@ -1247,7 +1249,8 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, } cmsg = CMSG_NXTHDR(msgh, cmsg); - target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg, + target_cmsg_start); } unlock_user(target_cmsg, target_cmsg_addr, 0); the_end: @@ -1261,7 +1264,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); abi_long msg_controllen; abi_ulong target_cmsg_addr; - struct target_cmsghdr *target_cmsg; + struct target_cmsghdr *target_cmsg, *target_cmsg_start; socklen_t space = 0; msg_controllen = tswapal(target_msgh->msg_controllen); @@ -1269,6 +1272,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, goto the_end; target_cmsg_addr = tswapal(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); + target_cmsg_start = target_cmsg; if (!target_cmsg) return -TARGET_EFAULT; @@ -1382,14 +1386,15 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, } target_cmsg->cmsg_len = tswapal(tgt_len); - tgt_space = TARGET_CMSG_SPACE(tgt_len); + tgt_space = TARGET_CMSG_SPACE(len); if (msg_controllen < tgt_space) { tgt_space = msg_controllen; } msg_controllen -= tgt_space; space += tgt_space; cmsg = CMSG_NXTHDR(msgh, cmsg); - target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg, + target_cmsg_start); } unlock_user(target_cmsg, target_cmsg_addr, space); the_end: @@ -4622,8 +4627,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_mutex_unlock(&clone_lock); } else { /* if no CLONE_VM, we consider it is a fork */ - if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) - return -EINVAL; + if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) { + return -TARGET_EINVAL; + } fork_start(); ret = fork(); if (ret == 0) { @@ -5246,6 +5252,94 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, return -TARGET_ENOSYS; } } +#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) +static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname, + abi_long handle, abi_long mount_id, + abi_long flags) +{ + struct file_handle *target_fh; + struct file_handle *fh; + int mid = 0; + abi_long ret; + char *name; + unsigned int size, total_size; + + if (get_user_s32(size, handle)) { + return -TARGET_EFAULT; + } + + name = lock_user_string(pathname); + if (!name) { + return -TARGET_EFAULT; + } + + total_size = sizeof(struct file_handle) + size; + target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0); + if (!target_fh) { + unlock_user(name, pathname, 0); + return -TARGET_EFAULT; + } + + fh = g_malloc0(total_size); + fh->handle_bytes = size; + + ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags)); + unlock_user(name, pathname, 0); + + /* man name_to_handle_at(2): + * Other than the use of the handle_bytes field, the caller should treat + * the file_handle structure as an opaque data type + */ + + memcpy(target_fh, fh, total_size); + target_fh->handle_bytes = tswap32(fh->handle_bytes); + target_fh->handle_type = tswap32(fh->handle_type); + g_free(fh); + unlock_user(target_fh, handle, total_size); + + if (put_user_s32(mid, mount_id)) { + return -TARGET_EFAULT; + } + + return ret; + +} +#endif + +#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) +static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle, + abi_long flags) +{ + struct file_handle *target_fh; + struct file_handle *fh; + unsigned int size, total_size; + abi_long ret; + + if (get_user_s32(size, handle)) { + return -TARGET_EFAULT; + } + + total_size = sizeof(struct file_handle) + size; + target_fh = lock_user(VERIFY_READ, handle, total_size, 1); + if (!target_fh) { + return -TARGET_EFAULT; + } + + fh = g_malloc0(total_size); + memcpy(fh, target_fh, total_size); + fh->handle_bytes = size; + fh->handle_type = tswap32(target_fh->handle_type); + + ret = get_errno(open_by_handle_at(mount_fd, fh, + target_to_host_bitmask(flags, fcntl_flags_tbl))); + + g_free(fh); + + unlock_user(target_fh, handle, total_size); + + return ret; +} +#endif /* Map host to target signal numbers for the wait family of syscalls. Assume all other status bits are the same. */ @@ -5658,6 +5752,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, arg4)); unlock_user(p, arg2, 0); break; +#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) + case TARGET_NR_name_to_handle_at: + ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); + break; +#endif +#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) + case TARGET_NR_open_by_handle_at: + ret = do_open_by_handle_at(arg1, arg2, arg3); + break; +#endif case TARGET_NR_close: ret = get_errno(close(arg1)); break; @@ -5808,12 +5912,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } *q = NULL; - /* This case will not be caught by the host's execve() if its - page size is bigger than the target's. */ - if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { - ret = -TARGET_E2BIG; - goto execve_end; - } if (!(p = lock_user_string(arg1))) goto execve_efault; ret = get_errno(execve(p, argp, envp)); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index cdc8db4..7ca33a6 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -235,7 +235,8 @@ struct target_cmsghdr { }; #define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1)) -#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg) +#define TARGET_CMSG_NXTHDR(mhdr, cmsg, cmsg_start) \ + __target_cmsg_nxthdr(mhdr, cmsg, cmsg_start) #define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \ & (size_t) ~(sizeof (abi_long) - 1)) #define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ @@ -243,17 +244,20 @@ struct target_cmsghdr { #define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) static __inline__ struct target_cmsghdr * -__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg) +__target_cmsg_nxthdr(struct target_msghdr *__mhdr, + struct target_cmsghdr *__cmsg, + struct target_cmsghdr *__cmsg_start) { struct target_cmsghdr *__ptr; __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapal(__cmsg->cmsg_len))); - if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapal(__mhdr->msg_control)) - > tswapal(__mhdr->msg_controllen)) + if ((unsigned long)((char *)(__ptr+1) - (char *)__cmsg_start) + > tswapal(__mhdr->msg_controllen)) { /* No more entries. */ return (struct target_cmsghdr *)0; - return __cmsg; + } + return __ptr; } struct target_mmsghdr { |