Commit 55901900 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-2.12-pull-request' into staging



# gpg: Signature made Tue 13 Mar 2018 17:33:03 GMT
# gpg:                using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-2.12-pull-request:
  linux-user: init_guest_space: Add a comment about search strategy
  linux-user: init_guest_space: Don't try to align if we'll reject it
  linux-user: init_guest_space: Clean up control flow a bit
  linux-user: init_guest_commpage: Add a comment about size check
  linux-user: init_guest_space: Clarify page alignment logic
  linux-user: init_guest_space: Correctly handle guest_start in commpage initialization
  linux-user: init_guest_space: Clean up if we can't initialize the commpage
  linux-user: Rename validate_guest_space => init_guest_commpage
  linux-user: Use #if to only call validate_guest_space for 32-bit ARM target
  qemu-binfmt-conf.sh: add qemu-xtensa
  linux-user: drop unused target_msync function
  linux-user: fix target_mprotect/target_munmap error return values
  linux-user: fix assertion in shmdt
  linux-user: fix mmap/munmap/mprotect/mremap/shmat
  linux-user: Support f_flags in statfs when available.
  linux-user: allows to use "--systemd ALL" with qemu-binfmt-conf.sh
  linux-user: Remove the unused "not implemented" signal handling stubs
  linux-user: Drop unicore32 code

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 5bdd3743 8c17d862
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -159,8 +159,12 @@ extern unsigned long guest_base;
extern int have_guest_base;
extern unsigned long reserved_va;

#define GUEST_ADDR_MAX (reserved_va ? reserved_va : \
#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
#define GUEST_ADDR_MAX (~0ul)
#else
#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : \
                                    (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
#endif
#else

#include "exec/hwaddr.h"
+7 −9
Original line number Diff line number Diff line
@@ -51,15 +51,13 @@
/* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))

#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
#define h2g_valid(x) 1
#else
#define h2g_valid(x) ({ \
    unsigned long __guest = (unsigned long)(x) - guest_base; \
    (__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) && \
    (!reserved_va || (__guest < reserved_va)); \
})
#endif
#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
#define h2g_valid(x) guest_addr_valid((unsigned long)(x) - guest_base)

static inline int guest_range_valid(unsigned long start, unsigned long len)
{
    return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
}

#define h2g_nocheck(x) ({ \
    unsigned long __ret = (unsigned long)(x) - guest_base; \
+65 −103
Original line number Diff line number Diff line
@@ -354,7 +354,6 @@ enum {

/* The commpage only exists for 32 bit kernels */

#define TARGET_HAS_VALIDATE_GUEST_SPACE
/* Return 1 if the proposed guest space is suitable for the guest.
 * Return 0 if the proposed guest space isn't suitable, but another
 * address space should be tried.
@@ -363,7 +362,7 @@ enum {
 * The guest code may leave a page mapped and populate it if the
 * address is suitable.
 */
static int validate_guest_space(unsigned long guest_base,
static int init_guest_commpage(unsigned long guest_base,
                               unsigned long guest_size)
{
    unsigned long real_start, test_page_addr;
@@ -375,6 +374,11 @@ static int validate_guest_space(unsigned long guest_base,

    /* If the commpage lies within the already allocated guest space,
     * then there is no way we can allocate it.
     *
     * You may be thinking that that this check is redundant because
     * we already validated the guest size against MAX_RESERVED_VA;
     * but if qemu_host_page_mask is unusually large, then
     * test_page_addr may be lower.
     */
    if (test_page_addr >= guest_base
        && test_page_addr < (guest_base + guest_size)) {
@@ -563,78 +567,6 @@ static uint32_t get_elf_hwcap(void)
#endif /* not TARGET_AARCH64 */
#endif /* TARGET_ARM */

#ifdef TARGET_UNICORE32

#define ELF_START_MMAP          0x80000000

#define ELF_CLASS               ELFCLASS32
#define ELF_DATA                ELFDATA2LSB
#define ELF_ARCH                EM_UNICORE32

static inline void init_thread(struct target_pt_regs *regs,
        struct image_info *infop)
{
    abi_long stack = infop->start_stack;
    memset(regs, 0, sizeof(*regs));
    regs->UC32_REG_asr = 0x10;
    regs->UC32_REG_pc = infop->entry & 0xfffffffe;
    regs->UC32_REG_sp = infop->start_stack;
    /* FIXME - what to for failure of get_user()? */
    get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
    get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
    /* XXX: it seems that r0 is zeroed after ! */
    regs->UC32_REG_00 = 0;
}

#define ELF_NREG    34
typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];

static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUUniCore32State *env)
{
    (*regs)[0] = env->regs[0];
    (*regs)[1] = env->regs[1];
    (*regs)[2] = env->regs[2];
    (*regs)[3] = env->regs[3];
    (*regs)[4] = env->regs[4];
    (*regs)[5] = env->regs[5];
    (*regs)[6] = env->regs[6];
    (*regs)[7] = env->regs[7];
    (*regs)[8] = env->regs[8];
    (*regs)[9] = env->regs[9];
    (*regs)[10] = env->regs[10];
    (*regs)[11] = env->regs[11];
    (*regs)[12] = env->regs[12];
    (*regs)[13] = env->regs[13];
    (*regs)[14] = env->regs[14];
    (*regs)[15] = env->regs[15];
    (*regs)[16] = env->regs[16];
    (*regs)[17] = env->regs[17];
    (*regs)[18] = env->regs[18];
    (*regs)[19] = env->regs[19];
    (*regs)[20] = env->regs[20];
    (*regs)[21] = env->regs[21];
    (*regs)[22] = env->regs[22];
    (*regs)[23] = env->regs[23];
    (*regs)[24] = env->regs[24];
    (*regs)[25] = env->regs[25];
    (*regs)[26] = env->regs[26];
    (*regs)[27] = env->regs[27];
    (*regs)[28] = env->regs[28];
    (*regs)[29] = env->regs[29];
    (*regs)[30] = env->regs[30];
    (*regs)[31] = env->regs[31];

    (*regs)[32] = cpu_asr_read((CPUUniCore32State *)env);
    (*regs)[33] = env->regs[0]; /* XXX */
}

#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE               4096

#define ELF_HWCAP                       (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)

#endif

#ifdef TARGET_SPARC
#ifdef TARGET_SPARC64

@@ -1869,21 +1801,12 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
    return sp;
}

#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE
/* If the guest doesn't have a validation function just agree */
static int validate_guest_space(unsigned long guest_base,
                                unsigned long guest_size)
{
    return 1;
}
#endif

unsigned long init_guest_space(unsigned long host_start,
                               unsigned long host_size,
                               unsigned long guest_start,
                               bool fixed)
{
    unsigned long current_start, real_start;
    unsigned long current_start, aligned_start;
    int flags;

    assert(host_start || host_size);
@@ -1891,11 +1814,12 @@ unsigned long init_guest_space(unsigned long host_start,
    /* If just a starting address is given, then just verify that
     * address.  */
    if (host_start && !host_size) {
        if (validate_guest_space(host_start, host_size) == 1) {
            return host_start;
        } else {
#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
        if (init_guest_commpage(host_start, host_size) != 1) {
            return (unsigned long)-1;
        }
#endif
        return host_start;
    }

    /* Setup the initial flags and start address.  */
@@ -1908,7 +1832,8 @@ unsigned long init_guest_space(unsigned long host_start,
    /* Otherwise, a non-zero size region of memory needs to be mapped
     * and validated.  */
    while (1) {
        unsigned long real_size = host_size;
        unsigned long real_start, real_size, aligned_size;
        aligned_size = real_size = host_size;

        /* Do not use mmap_find_vma here because that is limited to the
         * guest address space.  We are going to make the
@@ -1920,30 +1845,63 @@ unsigned long init_guest_space(unsigned long host_start,
            return (unsigned long)-1;
        }

        /* Check to see if the address is valid.  */
        if (host_start && real_start != current_start) {
            goto try_again;
        }

        /* Ensure the address is properly aligned.  */
        if (real_start & ~qemu_host_page_mask) {
            /* Ideally, we adjust like
             *
             *    pages: [  ][  ][  ][  ][  ]
             *      old:   [   real   ]
             *             [ aligned  ]
             *      new:   [     real     ]
             *               [ aligned  ]
             *
             * But if there is something else mapped right after it,
             * then obviously it won't have room to grow, and the
             * kernel will put the new larger real someplace else with
             * unknown alignment (if we made it to here, then
             * fixed=false).  Which is why we grow real by a full page
             * size, instead of by part of one; so that even if we get
             * moved, we can still guarantee alignment.  But this does
             * mean that there is a padding of < 1 page both before
             * and after the aligned range; the "after" could could
             * cause problems for ARM emulation where it could butt in
             * to where we need to put the commpage.
             */
            munmap((void *)real_start, host_size);
            real_size = host_size + qemu_host_page_size;
            real_size = aligned_size + qemu_host_page_size;
            real_start = (unsigned long)
                mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
            if (real_start == (unsigned long)-1) {
                return (unsigned long)-1;
            }
            real_start = HOST_PAGE_ALIGN(real_start);
            aligned_start = HOST_PAGE_ALIGN(real_start);
        } else {
            aligned_start = real_start;
        }

        /* Check to see if the address is valid.  */
        if (!host_start || real_start == current_start) {
            int valid = validate_guest_space(real_start - guest_start,
                                             real_size);
            if (valid == 1) {
                break;
            } else if (valid == -1) {
#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
        /* On 32-bit ARM, we need to also be able to map the commpage.  */
        int valid = init_guest_commpage(aligned_start - guest_start,
                                        aligned_size + guest_start);
        if (valid == -1) {
            munmap((void *)real_start, real_size);
            return (unsigned long)-1;
        } else if (valid == 0) {
            goto try_again;
        }
            /* valid == 0, so try again. */
        }
#endif

        /* If nothing has said `return -1` or `goto try_again` yet,
         * then the address we have is good.
         */
        break;

    try_again:
        /* That address didn't work.  Unmap and try a different one.
         * The address the host picked because is typically right at
         * the top of the host address space and leaves the guest with
@@ -1952,8 +1910,12 @@ unsigned long init_guest_space(unsigned long host_start,
         * happen often.  Probably means we got unlucky and host
         * address space randomization put a shared library somewhere
         * inconvenient.
         *
         * This is probably a good strategy if host_start, but is
         * probably a bad strategy if not, which means we got here
         * because of trouble with ARM commpage setup.
         */
        munmap((void *)real_start, host_size);
        munmap((void *)real_start, real_size);
        current_start += qemu_host_page_size;
        if (host_start == current_start) {
            /* Theoretically possible if host doesn't have any suitably
@@ -1965,7 +1927,7 @@ unsigned long init_guest_space(unsigned long host_start,

    qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size);

    return real_start;
    return aligned_start;
}

static void probe_guest_base(const char *image_name,
+1 −98
Original line number Diff line number Diff line
@@ -884,95 +884,6 @@ void cpu_loop(CPUARMState *env)

#endif

#ifdef TARGET_UNICORE32

void cpu_loop(CPUUniCore32State *env)
{
    CPUState *cs = CPU(uc32_env_get_cpu(env));
    int trapnr;
    unsigned int n, insn;
    target_siginfo_t info;

    for (;;) {
        cpu_exec_start(cs);
        trapnr = cpu_exec(cs);
        cpu_exec_end(cs);
        process_queued_cpu_work(cs);

        switch (trapnr) {
        case UC32_EXCP_PRIV:
            {
                /* system call */
                get_user_u32(insn, env->regs[31] - 4);
                n = insn & 0xffffff;

                if (n >= UC32_SYSCALL_BASE) {
                    /* linux syscall */
                    n -= UC32_SYSCALL_BASE;
                    if (n == UC32_SYSCALL_NR_set_tls) {
                            cpu_set_tls(env, env->regs[0]);
                            env->regs[0] = 0;
                    } else {
                        abi_long ret = do_syscall(env,
                                                  n,
                                                  env->regs[0],
                                                  env->regs[1],
                                                  env->regs[2],
                                                  env->regs[3],
                                                  env->regs[4],
                                                  env->regs[5],
                                                  0, 0);
                        if (ret == -TARGET_ERESTARTSYS) {
                            env->regs[31] -= 4;
                        } else if (ret != -TARGET_QEMU_ESIGRETURN) {
                            env->regs[0] = ret;
                        }
                    }
                } else {
                    goto error;
                }
            }
            break;
        case UC32_EXCP_DTRAP:
        case UC32_EXCP_ITRAP:
            info.si_signo = TARGET_SIGSEGV;
            info.si_errno = 0;
            /* XXX: check env->error_code */
            info.si_code = TARGET_SEGV_MAPERR;
            info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
            break;
        case EXCP_INTERRUPT:
            /* just indicate that signals should be handled asap */
            break;
        case EXCP_DEBUG:
            {
                int sig;

                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
                if (sig) {
                    info.si_signo = sig;
                    info.si_errno = 0;
                    info.si_code = TARGET_TRAP_BRKPT;
                    queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
                }
            }
            break;
        case EXCP_ATOMIC:
            cpu_exec_step_atomic(cs);
            break;
        default:
            goto error;
        }
        process_pending_signals(env);
    }

error:
    EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
    abort();
}
#endif

#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047

@@ -4737,14 +4648,6 @@ int main(int argc, char **argv, char **envp)
        }
#endif
    }
#elif defined(TARGET_UNICORE32)
    {
        int i;
        cpu_asr_write(env, regs->uregs[32], 0xffffffff);
        for (i = 0; i < 32; i++) {
            env->regs[i] = regs->uregs[i];
        }
    }
#elif defined(TARGET_SPARC)
    {
        int i;
@@ -4974,7 +4877,7 @@ int main(int argc, char **argv, char **envp)
#error unsupported target CPU
#endif

#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
#if defined(TARGET_ARM) || defined(TARGET_M68K)
    ts->stack_base = info->start_stack;
    ts->heap_base = info->brk;
    /* This will be filled in on the first SYS_HEAPINFO call.  */
+18 −25
Original line number Diff line number Diff line
@@ -77,11 +77,12 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
#endif

    if ((start & ~TARGET_PAGE_MASK) != 0)
        return -EINVAL;
        return -TARGET_EINVAL;
    len = TARGET_PAGE_ALIGN(len);
    end = start + len;
    if (end < start)
        return -EINVAL;
    if (!guest_range_valid(start, len)) {
        return -TARGET_ENOMEM;
    }
    prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
    if (len == 0)
        return 0;
@@ -481,8 +482,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
	 * It can fail only on 64-bit host with 32-bit target.
	 * On any other target/host host mmap() handles this error correctly.
	 */
        if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
            errno = EINVAL;
        if (!guest_range_valid(start, len)) {
            errno = ENOMEM;
            goto fail;
        }

@@ -620,10 +621,12 @@ int target_munmap(abi_ulong start, abi_ulong len)
           start, len);
#endif
    if (start & ~TARGET_PAGE_MASK)
        return -EINVAL;
        return -TARGET_EINVAL;
    len = TARGET_PAGE_ALIGN(len);
    if (len == 0)
        return -EINVAL;
    if (len == 0 || !guest_range_valid(start, len)) {
        return -TARGET_EINVAL;
    }

    mmap_lock();
    end = start + len;
    real_start = start & qemu_host_page_mask;
@@ -678,6 +681,13 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
    int prot;
    void *host_addr;

    if (!guest_range_valid(old_addr, old_size) ||
        ((flags & MREMAP_FIXED) &&
         !guest_range_valid(new_addr, new_size))) {
        errno = ENOMEM;
        return -1;
    }

    mmap_lock();

    if (flags & MREMAP_FIXED) {
@@ -744,20 +754,3 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
    mmap_unlock();
    return new_addr;
}

int target_msync(abi_ulong start, abi_ulong len, int flags)
{
    abi_ulong end;

    if (start & ~TARGET_PAGE_MASK)
        return -EINVAL;
    len = TARGET_PAGE_ALIGN(len);
    end = start + len;
    if (end < start)
        return -EINVAL;
    if (end == start)
        return 0;

    start &= qemu_host_page_mask;
    return msync(g2h(start), end - start, flags);
}
Loading