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

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



Add /proc/hardware and /proc/cpuinfo,
update SIOCXXX ioctls,
fix shmat emulation,
add nanoseconds in stat,
init field fp_abi on mips

# gpg: Signature made Fri 24 May 2019 12:24:36 BST
# gpg:                using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-4.1-pull-request:
  linux-user: Pass through nanosecond timestamp components for stat syscalls
  linux-user: Align mmap_find_vma to host page size
  linux-user: Fix shmat emulation by honoring host SHMLBA
  linux-user: Sanitize interp_info and, for mips only, init field fp_abi
  linux-user: Add support for SIOC<G|S>IFPFLAGS ioctls for all targets
  linux-user: Add support for SIOCSPGRP ioctl for all targets
  linux-user: Fix support for SIOCATMARK and SIOCGPGRP ioctls for xtensa
  linux-user: add pseudo /proc/hardware for m68k
  linux-user: add pseudo /proc/cpuinfo for sparc

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 40575757 5f992db6
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include <sys/param.h>

#include <sys/resource.h>
#include <sys/shm.h>

#include "qemu.h"
#include "disas/disas.h"
@@ -2010,6 +2011,8 @@ unsigned long init_guest_space(unsigned long host_start,
                               unsigned long guest_start,
                               bool fixed)
{
    /* In order to use host shmat, we must be able to honor SHMLBA.  */
    unsigned long align = MAX(SHMLBA, qemu_host_page_size);
    unsigned long current_start, aligned_start;
    int flags;

@@ -2027,7 +2030,7 @@ unsigned long init_guest_space(unsigned long host_start,
    }

    /* Setup the initial flags and start address.  */
    current_start = host_start & qemu_host_page_mask;
    current_start = host_start & -align;
    flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
    if (fixed) {
        flags |= MAP_FIXED;
@@ -2063,8 +2066,8 @@ unsigned long init_guest_space(unsigned long host_start,
            return (unsigned long)-1;
        }
        munmap((void *)real_start, host_full_size);
        if (real_start & ~qemu_host_page_mask) {
            /* The same thing again, but with an extra qemu_host_page_size
        if (real_start & (align - 1)) {
            /* The same thing again, but with extra
             * so that we can shift around alignment.
             */
            unsigned long real_size = host_full_size + qemu_host_page_size;
@@ -2077,7 +2080,7 @@ unsigned long init_guest_space(unsigned long host_start,
                return (unsigned long)-1;
            }
            munmap((void *)real_start, real_size);
            real_start = HOST_PAGE_ALIGN(real_start);
            real_start = ROUND_UP(real_start, align);
        }
        current_start = real_start;
    }
@@ -2104,7 +2107,7 @@ unsigned long init_guest_space(unsigned long host_start,
        }

        /* Ensure the address is properly aligned.  */
        if (real_start & ~qemu_host_page_mask) {
        if (real_start & (align - 1)) {
            /* Ideally, we adjust like
             *
             *    pages: [  ][  ][  ][  ][  ]
@@ -2132,7 +2135,7 @@ unsigned long init_guest_space(unsigned long host_start,
            if (real_start == (unsigned long)-1) {
                return (unsigned long)-1;
            }
            aligned_start = HOST_PAGE_ALIGN(real_start);
            aligned_start = ROUND_UP(real_start, align);
        } else {
            aligned_start = real_start;
        }
@@ -2169,7 +2172,7 @@ unsigned long init_guest_space(unsigned long host_start,
         * because of trouble with ARM commpage setup.
         */
        munmap((void *)real_start, real_size);
        current_start += qemu_host_page_size;
        current_start += align;
        if (host_start == current_start) {
            /* Theoretically possible if host doesn't have any suitably
             * aligned areas.  Normally the first mmap will fail.
@@ -2704,6 +2707,11 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
    char *elf_interpreter = NULL;
    char *scratch;

    memset(&interp_info, 0, sizeof(interp_info));
#ifdef TARGET_MIPS
    interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
#endif

    info->start_mmap = (abi_ulong)ELF_START_MMAP;

    load_elf_image(bprm->filename, bprm->fd, info,
+3 −0
Original line number Diff line number Diff line
@@ -206,6 +206,8 @@
  IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
  IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
  IOCTL(SIOCGIFINDEX, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
  IOCTL(SIOCSIFPFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
  IOCTL(SIOCGIFPFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
  IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
  IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
                MK_PTR(MK_STRUCT(STRUCT_ifconf)))
@@ -218,6 +220,7 @@
  IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
  IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
  IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
  IOCTL(SIOCSPGRP, IOC_W, MK_PTR(TYPE_INT)) /* pid_t */
  IOCTL(SIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) /* pid_t */
  IOCTL(SIOCGSTAMP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timeval)))
  IOCTL(SIOCGSTAMPNS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timespec)))
+39 −33
Original line number Diff line number Diff line
@@ -202,50 +202,53 @@ unsigned long last_brk;

/* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
   of guest address space.  */
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
                                        abi_ulong align)
{
    abi_ulong addr;
    abi_ulong end_addr;
    abi_ulong addr, end_addr, incr = qemu_host_page_size;
    int prot;
    int looped = 0;
    bool looped = false;

    if (size > reserved_va) {
        return (abi_ulong)-1;
    }

    size = HOST_PAGE_ALIGN(size);
    /* Note that start and size have already been aligned by mmap_find_vma. */

    end_addr = start + size;
    if (end_addr > reserved_va) {
        end_addr = reserved_va;
    if (start > reserved_va - size) {
        /* Start at the top of the address space.  */
        end_addr = ((reserved_va - size) & -align) + size;
        looped = true;
    }
    addr = end_addr - qemu_host_page_size;

    /* Search downward from END_ADDR, checking to see if a page is in use.  */
    addr = end_addr;
    while (1) {
        addr -= incr;
        if (addr > end_addr) {
            if (looped) {
                /* Failure.  The entire address space has been searched.  */
                return (abi_ulong)-1;
            }
            end_addr = reserved_va;
            addr = end_addr - qemu_host_page_size;
            looped = 1;
            continue;
        }
            /* Re-start at the top of the address space.  */
            addr = end_addr = ((reserved_va - size) & -align) + size;
            looped = true;
        } else {
            prot = page_get_flags(addr);
            if (prot) {
            end_addr = addr;
        }
        if (addr && addr + size == end_addr) {
            break;
        }
        addr -= qemu_host_page_size;
    }

                /* Page in use.  Restart below this page.  */
                addr = end_addr = ((addr - size) & -align) + size;
            } else if (addr && addr + size == end_addr) {
                /* Success!  All pages between ADDR and END_ADDR are free.  */
                if (start == mmap_next_start) {
                    mmap_next_start = addr;
                }

                return addr;
            }
        }
    }
}

/*
 * Find and reserve a free memory area of size 'size'. The search
@@ -253,23 +256,26 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
 * It must be called with mmap_lock() held.
 * Return -1 if error.
 */
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
{
    void *ptr, *prev;
    abi_ulong addr;
    int wrapped, repeat;

    align = MAX(align, qemu_host_page_size);

    /* If 'start' == 0, then a default start address is used. */
    if (start == 0) {
        start = mmap_next_start;
    } else {
        start &= qemu_host_page_mask;
    }
    start = ROUND_UP(start, align);

    size = HOST_PAGE_ALIGN(size);

    if (reserved_va) {
        return mmap_find_vma_reserved(start, size);
        return mmap_find_vma_reserved(start, size, align);
    }

    addr = start;
@@ -299,7 +305,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
        if (h2g_valid(ptr + size - 1)) {
            addr = h2g(ptr);

            if ((addr & ~TARGET_PAGE_MASK) == 0) {
            if ((addr & (align - 1)) == 0) {
                /* Success.  */
                if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
                    mmap_next_start = addr + size;
@@ -313,12 +319,12 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
                /* Assume the result that the kernel gave us is the
                   first with enough free space, so start again at the
                   next higher target page.  */
                addr = TARGET_PAGE_ALIGN(addr);
                addr = ROUND_UP(addr, align);
                break;
            case 1:
                /* Sometimes the kernel decides to perform the allocation
                   at the top end of memory instead.  */
                addr &= TARGET_PAGE_MASK;
                addr &= -align;
                break;
            case 2:
                /* Start over at low memory.  */
@@ -416,7 +422,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
    if (!(flags & MAP_FIXED)) {
        host_len = len + offset - host_offset;
        host_len = HOST_PAGE_ALIGN(host_len);
        start = mmap_find_vma(real_start, host_len);
        start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE);
        if (start == (abi_ulong)-1) {
            errno = ENOMEM;
            goto fail;
@@ -710,7 +716,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
    } else if (flags & MREMAP_MAYMOVE) {
        abi_ulong mmap_start;

        mmap_start = mmap_find_vma(0, new_size);
        mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);

        if (mmap_start == -1) {
            errno = ENOMEM;
+1 −1
Original line number Diff line number Diff line
@@ -443,7 +443,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
                       abi_ulong new_addr);
extern unsigned long last_brk;
extern abi_ulong mmap_next_start;
abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong);
void mmap_fork_start(void);
void mmap_fork_end(int child);

+47 −2
Original line number Diff line number Diff line
@@ -3914,7 +3914,8 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
    else {
        abi_ulong mmap_start;

        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
        /* In order to use the host shmat, we need to honor host SHMLBA.  */
        mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));

        if (mmap_start == -1) {
            errno = ENOMEM;
@@ -6412,6 +6413,11 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
        __put_user(host_st->st_atime, &target_st->target_st_atime);
        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
        __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
        __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
        __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
#endif
        unlock_user_struct(target_st, target_addr, 1);
    } else
#endif
@@ -6442,6 +6448,11 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
        __put_user(host_st->st_atime, &target_st->target_st_atime);
        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
        __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
        __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
        __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
#endif
        unlock_user_struct(target_st, target_addr, 1);
    }

@@ -6790,12 +6801,15 @@ static int is_proc_myself(const char *filename, const char *entry)
    return 0;
}

#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \
    defined(TARGET_SPARC) || defined(TARGET_M68K)
static int is_proc(const char *filename, const char *entry)
{
    return strcmp(filename, entry) == 0;
}
#endif

#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
static int open_net_route(void *cpu_env, int fd)
{
    FILE *fp;
@@ -6840,6 +6854,22 @@ static int open_net_route(void *cpu_env, int fd)
}
#endif

#if defined(TARGET_SPARC)
static int open_cpuinfo(void *cpu_env, int fd)
{
    dprintf(fd, "type\t\t: sun4u\n");
    return 0;
}
#endif

#if defined(TARGET_M68K)
static int open_hardware(void *cpu_env, int fd)
{
    dprintf(fd, "Model:\t\tqemu-m68k\n");
    return 0;
}
#endif

static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
{
    struct fake_open {
@@ -6855,6 +6885,12 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
        { "cmdline", open_self_cmdline, is_proc_myself },
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
        { "/proc/net/route", open_net_route, is_proc },
#endif
#if defined(TARGET_SPARC)
        { "/proc/cpuinfo", open_cpuinfo, is_proc },
#endif
#if defined(TARGET_M68K)
        { "/proc/hardware", open_hardware, is_proc },
#endif
        { NULL, NULL, NULL }
    };
@@ -8870,6 +8906,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                __put_user(st.st_atime, &target_st->target_st_atime);
                __put_user(st.st_mtime, &target_st->target_st_mtime);
                __put_user(st.st_ctime, &target_st->target_st_ctime);
#if (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) && \
    defined(TARGET_STAT_HAVE_NSEC)
                __put_user(st.st_atim.tv_nsec,
                           &target_st->target_st_atime_nsec);
                __put_user(st.st_mtim.tv_nsec,
                           &target_st->target_st_mtime_nsec);
                __put_user(st.st_ctim.tv_nsec,
                           &target_st->target_st_ctime_nsec);
#endif
                unlock_user_struct(target_st, arg2, 1);
            }
        }
Loading