Commit 945507d6 authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 37dd86a4 86abac06
Loading
Loading
Loading
Loading
+55 −58
Original line number Diff line number Diff line
@@ -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);

            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);

+1 −1
Original line number Diff line number Diff line
@@ -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;
+0 −7
Original line number Diff line number Diff line
@@ -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);
}
+49 −39
Original line number Diff line number Diff line
@@ -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);
    }
+1 −4
Original line number Diff line number Diff line
@@ -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;
        }
Loading