Commit 0f79bfe3 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 23 Jan 2018 14:47:41 GMT
# gpg:                using RSA key 0xF30C38BD3F2FBE3C
# 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: implement renameat2
  page_unprotect(): handle calls to pages that are PAGE_WRITE
  linux-user: Propagate siginfo_t through to handle_cpu_signal()
  linux-user: remove nmi.c and fw-path-provider.c
  linux-user: Add getcpu() support
  linux-user: Add AT_SECURE auxval
  linux-user: Fix sched_get/setaffinity conversion
  linux-user/mmap.c: Avoid choosing NULL as start address
  linux-user: Translate flags argument to dup3 syscall
  linux-user: Don't use CMSG_ALIGN(sizeof struct cmsghdr)
  linux-user: Fix length calculations in host_to_target_cmsg()
  linux-user: wrap fork() in a start/end exclusive section
  linux-user: Fix locking order in fork_start()

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents f78b6f9b 95d0307c
Loading
Loading
Loading
Loading
+31 −19
Original line number Diff line number Diff line
@@ -2181,12 +2181,24 @@ int page_unprotect(target_ulong address, uintptr_t pc)

    /* if the page was really writable, then we change its
       protection back to writable */
    if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) {
    if (p->flags & PAGE_WRITE_ORG) {
        current_tb_invalidated = false;
        if (p->flags & PAGE_WRITE) {
            /* If the page is actually marked WRITE then assume this is because
             * this thread raced with another one which got here first and
             * set the page to PAGE_WRITE and did the TB invalidate for us.
             */
#ifdef TARGET_HAS_PRECISE_SMC
            TranslationBlock *current_tb = tb_find_pc(pc);
            if (current_tb) {
                current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID;
            }
#endif
        } else {
            host_start = address & qemu_host_page_mask;
            host_end = host_start + qemu_host_page_size;

            prot = 0;
        current_tb_invalidated = false;
            for (addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) {
                p = page_find(addr >> TARGET_PAGE_BITS);
                p->flags |= PAGE_WRITE;
@@ -2203,7 +2215,7 @@ int page_unprotect(target_ulong address, uintptr_t pc)
            }
            mprotect((void *)g2h(host_start), qemu_host_page_size,
                     prot & PAGE_BITS);

        }
        mmap_unlock();
        /* If current TB was invalidated return to main loop */
        return current_tb_invalidated ? 2 : 1;
+26 −26
Original line number Diff line number Diff line
@@ -57,12 +57,13 @@ static void cpu_exit_tb_from_sighandler(CPUState *cpu, sigset_t *old_set)
   the effective address of the memory exception. 'is_write' is 1 if a
   write caused the exception and otherwise 0'. 'old_set' is the
   signal set which should be restored */
static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
                                    int is_write, sigset_t *old_set)
{
    CPUState *cpu = current_cpu;
    CPUClass *cc;
    int ret;
    unsigned long address = (unsigned long)info->si_addr;

    /* We must handle PC addresses from two different sources:
     * a call return address and a signal frame address.
@@ -103,7 +104,18 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
    if (is_write && h2g_valid(address)) {
    /* Note that it is important that we don't call page_unprotect() unless
     * this is really a "write to nonwriteable page" fault, because
     * page_unprotect() assumes that if it is called for an access to
     * a page that's writeable this means we had two threads racing and
     * another thread got there first and already made the page writeable;
     * so we will retry the access. If we were to call page_unprotect()
     * for some other kind of fault that should really be passed to the
     * guest, we'd end up in an infinite loop of retrying the faulting
     * access.
     */
    if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
        h2g_valid(address)) {
        switch (page_unprotect(h2g(address), pc)) {
        case 0:
            /* Fault not caused by a page marked unwritable to protect
@@ -215,9 +227,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#endif
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
    return handle_cpu_signal(pc, info,
                             trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc));
}

@@ -261,9 +272,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#endif

    pc = PC_sig(uc);
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
    return handle_cpu_signal(pc, info,
                             TRAP_sig(uc) == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc));
}

@@ -341,8 +351,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
        is_write = 1;
    }
#endif
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write, &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}

#elif defined(__alpha__)
@@ -372,8 +381,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
        is_write = 1;
    }

    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write, &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
#elif defined(__sparc__)

@@ -432,8 +440,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
            break;
        }
    }
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write, sigmask);
    return handle_cpu_signal(pc, info, is_write, sigmask);
}

#elif defined(__arm__)
@@ -466,9 +473,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
     * later processor; on v5 we will always report this as a read).
     */
    is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write,
                             &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}

#elif defined(__aarch64__)
@@ -495,8 +500,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
                /* Ignore bits 23 & 24, controlling indexing.  */
                || (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */

    return handle_cpu_signal(pc, (uintptr_t)info->si_addr,
                             is_write, &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}

#elif defined(__ia64)
@@ -529,9 +533,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
    default:
        break;
    }
    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
                             is_write,
                             (sigset_t *)&uc->uc_sigmask);
    return handle_cpu_signal(ip, info, is_write, (sigset_t *)&uc->uc_sigmask);
}

#elif defined(__s390__)
@@ -583,8 +585,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
        }
        break;
    }
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write, &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}

#elif defined(__mips__)
@@ -599,8 +600,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,

    /* XXX: compute is_write */
    is_write = 0;
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             is_write, &uc->uc_sigmask);
    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}

#else
+3 −2
Original line number Diff line number Diff line
# core qdev-related obj files, also used by *-user:
common-obj-y += qdev.o qdev-properties.o
common-obj-y += bus.o reset.o
common-obj-y += fw-path-provider.o
common-obj-$(CONFIG_SOFTMMU) += qdev-fw.o
common-obj-$(CONFIG_SOFTMMU) += fw-path-provider.o
# irq.o needed for qdev GPIO handling:
common-obj-y += irq.o
common-obj-y += hotplug.o
common-obj-y += nmi.o
common-obj-$(CONFIG_SOFTMMU) += nmi.o

common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
common-obj-$(CONFIG_XILINX_AXI) += stream.o

hw/core/qdev-fw.c

0 → 100644
+96 −0
Original line number Diff line number Diff line
/*
 *  qdev fw helpers
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License,
 *  or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include "qemu/osdep.h"
#include "hw/qdev.h"
#include "hw/fw-path-provider.h"

const char *qdev_fw_name(DeviceState *dev)
{
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

    if (dc->fw_name) {
        return dc->fw_name;
    }

    return object_get_typename(OBJECT(dev));
}

static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
{
    BusClass *bc = BUS_GET_CLASS(bus);

    if (bc->get_fw_dev_path) {
        return bc->get_fw_dev_path(dev);
    }

    return NULL;
}

static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
{
    Object *obj = OBJECT(dev);
    char *d = NULL;

    while (!d && obj->parent) {
        obj = obj->parent;
        d = fw_path_provider_try_get_dev_path(obj, bus, dev);
    }
    return d;
}

char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
{
    Object *obj = OBJECT(dev);

    return fw_path_provider_try_get_dev_path(obj, bus, dev);
}

static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
    int l = 0;

    if (dev && dev->parent_bus) {
        char *d;
        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
        d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
        if (!d) {
            d = bus_get_fw_dev_path(dev->parent_bus, dev);
        }
        if (d) {
            l += snprintf(p + l, size - l, "%s", d);
            g_free(d);
        } else {
            return l;
        }
    }
    l += snprintf(p + l , size - l, "/");

    return l;
}

char *qdev_get_fw_dev_path(DeviceState *dev)
{
    char path[128];
    int l;

    l = qdev_get_fw_dev_path_helper(dev, path, 128);

    path[l - 1] = '\0';

    return g_strdup(path);
}
+0 −77
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@

#include "qemu/osdep.h"
#include "hw/qdev.h"
#include "hw/fw-path-provider.h"
#include "sysemu/sysemu.h"
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
@@ -48,17 +47,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
    return dc->vmsd;
}

const char *qdev_fw_name(DeviceState *dev)
{
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

    if (dc->fw_name) {
        return dc->fw_name;
    }

    return object_get_typename(OBJECT(dev));
}

static void bus_remove_child(BusState *bus, DeviceState *child)
{
    BusChild *kid;
@@ -631,71 +619,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
    return NULL;
}

static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
{
    BusClass *bc = BUS_GET_CLASS(bus);

    if (bc->get_fw_dev_path) {
        return bc->get_fw_dev_path(dev);
    }

    return NULL;
}

static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
{
    Object *obj = OBJECT(dev);
    char *d = NULL;

    while (!d && obj->parent) {
        obj = obj->parent;
        d = fw_path_provider_try_get_dev_path(obj, bus, dev);
    }
    return d;
}

char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
{
    Object *obj = OBJECT(dev);

    return fw_path_provider_try_get_dev_path(obj, bus, dev);
}

static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
    int l = 0;

    if (dev && dev->parent_bus) {
        char *d;
        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
        d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
        if (!d) {
            d = bus_get_fw_dev_path(dev->parent_bus, dev);
        }
        if (d) {
            l += snprintf(p + l, size - l, "%s", d);
            g_free(d);
        } else {
            return l;
        }
    }
    l += snprintf(p + l , size - l, "/");

    return l;
}

char* qdev_get_fw_dev_path(DeviceState *dev)
{
    char path[128];
    int l;

    l = qdev_get_fw_dev_path_helper(dev, path, 128);

    path[l-1] = '\0';

    return g_strdup(path);
}

char *qdev_get_dev_path(DeviceState *dev)
{
    BusClass *bc;
Loading