-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJaZ0sNAAoJEPMMOL0/L7480bQP/i5QO0c4MrXJ7VaEa1u6ubfv AELpodvD6hm0qDT8OIH/4g1PRFZvB1OGg1wd8sZg/aLLbxfiKQ0kR+6Kq+W6LLJY qD4xddVZnBVlcSDwGn6Rg3bStgISOBr+Z7fAOtLOFc6BJz5JryU4PSPLXIb4gxtX 0DXPXnSSTj+yZUjoG408aqAAlFRgbbXcY9Yhx3hblEO3ZJWAv7qrtoL67PEgB4kh j2t/6SSpEvsrmsb1g4N0/NMb6csOAwcA3kiTiOE2fGhc6vS7hUpcQPDQi/FHfkWD Q9Qe5y1TUE+JCc1VAdjWy3+42yH+IFpJo8lshJZw0tSGk3GCXeRUI6jlsawMphq/ Xo9zrIcXcTY/1ZWB9FWypr0orFLMphQPY6cwEu/60QvzQA8coeJk27zqXgL/G78y 7bNqLhMVz1JkKO4uCkRGQVJuijLo3aO3OeFSEnl8QoZInoOaPd+aVh/FCs57hV3r mcXT+ab9lbNrx0BTMI8Cr4HzvHH5cAfNg8hK/hh9rVHkAopLGvHkNJWOLbtAawds MulpKlLMnuntU/LGfAVU+ccttWt8Hfd5vRwS3Ex99sTIU/yBYh8iSAHh0lweE00p RmGMuVn+aXwcnDAsTXR6+8Zn5GzK+o9eifwlFdhI7AkCPwhra4fVodi0d/0imvGE XHLy02hVBGUp+Hoyf0/r =2ycl -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0f79bfe38a
@ -2181,29 +2181,41 @@ 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)) {
|
||||
host_start = address & qemu_host_page_mask;
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
|
||||
prot = 0;
|
||||
if (p->flags & PAGE_WRITE_ORG) {
|
||||
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;
|
||||
prot |= p->flags;
|
||||
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_invalidate_check(addr);
|
||||
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
|
||||
}
|
||||
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
||||
prot & PAGE_BITS);
|
||||
} else {
|
||||
host_start = address & qemu_host_page_mask;
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
|
||||
prot = 0;
|
||||
for (addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||
p->flags |= PAGE_WRITE;
|
||||
prot |= p->flags;
|
||||
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_invalidate_check(addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -1,11 +1,12 @@
|
||||
# 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
|
||||
|
96
hw/core/qdev-fw.c
Normal file
96
hw/core/qdev-fw.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -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;
|
||||
|
@ -1354,7 +1354,7 @@ struct exec
|
||||
~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
|
||||
#define DLINFO_ITEMS 14
|
||||
#define DLINFO_ITEMS 15
|
||||
|
||||
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||||
{
|
||||
@ -1786,6 +1786,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
|
||||
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
|
||||
NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
|
||||
NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
|
||||
|
||||
#ifdef ELF_HWCAP2
|
||||
NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
|
||||
|
@ -127,9 +127,10 @@ int cpu_get_pic_interrupt(CPUX86State *env)
|
||||
/* Make sure everything is in a consistent state for calling fork(). */
|
||||
void fork_start(void)
|
||||
{
|
||||
cpu_list_lock();
|
||||
qemu_mutex_lock(&tb_ctx.tb_lock);
|
||||
start_exclusive();
|
||||
mmap_fork_start();
|
||||
qemu_mutex_lock(&tb_ctx.tb_lock);
|
||||
cpu_list_lock();
|
||||
}
|
||||
|
||||
void fork_end(int child)
|
||||
@ -147,9 +148,13 @@ void fork_end(int child)
|
||||
qemu_mutex_init(&tb_ctx.tb_lock);
|
||||
qemu_init_cpu_list();
|
||||
gdbserver_fork(thread_cpu);
|
||||
/* qemu_init_cpu_list() takes care of reinitializing the
|
||||
* exclusive state, so we don't need to end_exclusive() here.
|
||||
*/
|
||||
} else {
|
||||
qemu_mutex_unlock(&tb_ctx.tb_lock);
|
||||
cpu_list_unlock();
|
||||
end_exclusive();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
|
||||
if (prot) {
|
||||
end_addr = addr;
|
||||
}
|
||||
if (addr + size == end_addr) {
|
||||
if (addr && addr + size == end_addr) {
|
||||
break;
|
||||
}
|
||||
addr -= qemu_host_page_size;
|
||||
|
@ -296,6 +296,8 @@ _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
|
||||
#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
|
||||
_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
|
||||
unsigned long *, user_mask_ptr);
|
||||
#define __NR_sys_getcpu __NR_getcpu
|
||||
_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
|
||||
_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
|
||||
void *, arg);
|
||||
_syscall2(int, capget, struct __user_cap_header_struct *, header,
|
||||
@ -598,6 +600,24 @@ static int sys_utimensat(int dirfd, const char *pathname,
|
||||
#endif
|
||||
#endif /* TARGET_NR_utimensat */
|
||||
|
||||
#ifdef TARGET_NR_renameat2
|
||||
#if defined(__NR_renameat2)
|
||||
#define __NR_sys_renameat2 __NR_renameat2
|
||||
_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
|
||||
const char *, new, unsigned int, flags)
|
||||
#else
|
||||
static int sys_renameat2(int oldfd, const char *old,
|
||||
int newfd, const char *new, int flags)
|
||||
{
|
||||
if (flags == 0) {
|
||||
return renameat(oldfd, old, newfd, new);
|
||||
}
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif /* TARGET_NR_renameat2 */
|
||||
|
||||
#ifdef CONFIG_INOTIFY
|
||||
#include <sys/inotify.h>
|
||||
|
||||
@ -1692,7 +1712,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
|
||||
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
||||
|
||||
int len = tswapal(target_cmsg->cmsg_len)
|
||||
- TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
|
||||
- sizeof(struct target_cmsghdr);
|
||||
|
||||
space += CMSG_SPACE(len);
|
||||
if (space > msgh->msg_controllen) {
|
||||
@ -1773,7 +1793,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
void *data = CMSG_DATA(cmsg);
|
||||
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
||||
|
||||
int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
|
||||
int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
|
||||
int tgt_len, tgt_space;
|
||||
|
||||
/* We never copy a half-header but may copy half-data;
|
||||
@ -1782,7 +1802,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
* to the guest via the CTRUNC bit), unlike truncation
|
||||
* in target_to_host_cmsg, which is a QEMU bug.
|
||||
*/
|
||||
if (msg_controllen < sizeof(struct cmsghdr)) {
|
||||
if (msg_controllen < sizeof(struct target_cmsghdr)) {
|
||||
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
|
||||
break;
|
||||
}
|
||||
@ -1794,8 +1814,6 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
}
|
||||
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
|
||||
|
||||
tgt_len = TARGET_CMSG_LEN(len);
|
||||
|
||||
/* Payload types which need a different size of payload on
|
||||
* the target must adjust tgt_len here.
|
||||
*/
|
||||
@ -1809,12 +1827,13 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tgt_len = len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg_controllen < tgt_len) {
|
||||
if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
|
||||
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
|
||||
tgt_len = msg_controllen;
|
||||
tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
|
||||
}
|
||||
|
||||
/* We must now copy-and-convert len bytes of payload
|
||||
@ -1875,6 +1894,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
uint32_t *v = (uint32_t *)data;
|
||||
uint32_t *t_int = (uint32_t *)target_data;
|
||||
|
||||
if (len != sizeof(uint32_t) ||
|
||||
tgt_len != sizeof(uint32_t)) {
|
||||
goto unimplemented;
|
||||
}
|
||||
__put_user(*v, t_int);
|
||||
break;
|
||||
}
|
||||
@ -1888,6 +1911,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
struct errhdr_t *target_errh =
|
||||
(struct errhdr_t *)target_data;
|
||||
|
||||
if (len != sizeof(struct errhdr_t) ||
|
||||
tgt_len != sizeof(struct errhdr_t)) {
|
||||
goto unimplemented;
|
||||
}
|
||||
__put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
|
||||
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
|
||||
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
|
||||
@ -1911,6 +1938,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
uint32_t *v = (uint32_t *)data;
|
||||
uint32_t *t_int = (uint32_t *)target_data;
|
||||
|
||||
if (len != sizeof(uint32_t) ||
|
||||
tgt_len != sizeof(uint32_t)) {
|
||||
goto unimplemented;
|
||||
}
|
||||
__put_user(*v, t_int);
|
||||
break;
|
||||
}
|
||||
@ -1924,6 +1955,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||
struct errhdr6_t *target_errh =
|
||||
(struct errhdr6_t *)target_data;
|
||||
|
||||
if (len != sizeof(struct errhdr6_t) ||
|
||||
tgt_len != sizeof(struct errhdr6_t)) {
|
||||
goto unimplemented;
|
||||
}
|
||||
__put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
|
||||
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
|
||||
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
|
||||
@ -1950,8 +1985,8 @@ 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(len);
|
||||
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
|
||||
tgt_space = TARGET_CMSG_SPACE(tgt_len);
|
||||
if (msg_controllen < tgt_space) {
|
||||
tgt_space = msg_controllen;
|
||||
}
|
||||
@ -7716,6 +7751,73 @@ static TargetFdTrans target_inotify_trans = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static int target_to_host_cpu_mask(unsigned long *host_mask,
|
||||
size_t host_size,
|
||||
abi_ulong target_addr,
|
||||
size_t target_size)
|
||||
{
|
||||
unsigned target_bits = sizeof(abi_ulong) * 8;
|
||||
unsigned host_bits = sizeof(*host_mask) * 8;
|
||||
abi_ulong *target_mask;
|
||||
unsigned i, j;
|
||||
|
||||
assert(host_size >= target_size);
|
||||
|
||||
target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
|
||||
if (!target_mask) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
memset(host_mask, 0, host_size);
|
||||
|
||||
for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
|
||||
unsigned bit = i * target_bits;
|
||||
abi_ulong val;
|
||||
|
||||
__get_user(val, &target_mask[i]);
|
||||
for (j = 0; j < target_bits; j++, bit++) {
|
||||
if (val & (1UL << j)) {
|
||||
host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlock_user(target_mask, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host_to_target_cpu_mask(const unsigned long *host_mask,
|
||||
size_t host_size,
|
||||
abi_ulong target_addr,
|
||||
size_t target_size)
|
||||
{
|
||||
unsigned target_bits = sizeof(abi_ulong) * 8;
|
||||
unsigned host_bits = sizeof(*host_mask) * 8;
|
||||
abi_ulong *target_mask;
|
||||
unsigned i, j;
|
||||
|
||||
assert(host_size >= target_size);
|
||||
|
||||
target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
|
||||
if (!target_mask) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
|
||||
unsigned bit = i * target_bits;
|
||||
abi_ulong val = 0;
|
||||
|
||||
for (j = 0; j < target_bits; j++, bit++) {
|
||||
if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
|
||||
val |= 1UL << j;
|
||||
}
|
||||
}
|
||||
__put_user(val, &target_mask[i]);
|
||||
}
|
||||
|
||||
unlock_user(target_mask, target_addr, target_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do_syscall() should always have a single exit point at the end so
|
||||
that actions, such as logging of syscall results, can be performed.
|
||||
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
|
||||
@ -8342,6 +8444,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(TARGET_NR_renameat2)
|
||||
case TARGET_NR_renameat2:
|
||||
{
|
||||
void *p2;
|
||||
p = lock_user_string(arg2);
|
||||
p2 = lock_user_string(arg4);
|
||||
if (!p || !p2) {
|
||||
ret = -TARGET_EFAULT;
|
||||
} else {
|
||||
ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
|
||||
}
|
||||
unlock_user(p2, arg4, 0);
|
||||
unlock_user(p, arg2, 0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_mkdir
|
||||
case TARGET_NR_mkdir:
|
||||
if (!(p = lock_user_string(arg1)))
|
||||
@ -8475,11 +8593,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#endif
|
||||
#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
|
||||
case TARGET_NR_dup3:
|
||||
ret = get_errno(dup3(arg1, arg2, arg3));
|
||||
{
|
||||
int host_flags;
|
||||
|
||||
if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
|
||||
ret = get_errno(dup3(arg1, arg2, host_flags));
|
||||
if (ret >= 0) {
|
||||
fd_trans_dup(arg1, arg2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_NR_getppid /* not on alpha */
|
||||
case TARGET_NR_getppid:
|
||||
@ -10353,6 +10479,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
|
||||
|
||||
mask = alloca(mask_size);
|
||||
memset(mask, 0, mask_size);
|
||||
ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
|
||||
|
||||
if (!is_error(ret)) {
|
||||
@ -10372,9 +10499,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
ret = arg2;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg3, mask, ret)) {
|
||||
goto efault;
|
||||
}
|
||||
ret = host_to_target_cpu_mask(mask, mask_size, arg3, arg2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -10392,17 +10517,33 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
break;
|
||||
}
|
||||
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
|
||||
|
||||
mask = alloca(mask_size);
|
||||
if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
|
||||
goto efault;
|
||||
|
||||
ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
memcpy(mask, p, arg2);
|
||||
unlock_user_struct(p, arg2, 0);
|
||||
|
||||
ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getcpu:
|
||||
{
|
||||
unsigned cpu, node;
|
||||
ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
|
||||
arg2 ? &node : NULL,
|
||||
NULL));
|
||||
if (is_error(ret)) {
|
||||
goto fail;
|
||||
}
|
||||
if (arg1 && put_user_u32(cpu, arg1)) {
|
||||
goto efault;
|
||||
}
|
||||
if (arg2 && put_user_u32(node, arg2)) {
|
||||
goto efault;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_sched_setparam:
|
||||
{
|
||||
struct sched_param *target_schp;
|
||||
|
@ -303,9 +303,9 @@ struct target_cmsghdr {
|
||||
__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) \
|
||||
+ TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
|
||||
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
|
||||
#define TARGET_CMSG_SPACE(len) (sizeof(struct target_cmsghdr) + \
|
||||
TARGET_CMSG_ALIGN(len))
|
||||
#define TARGET_CMSG_LEN(len) (sizeof(struct target_cmsghdr) + (len))
|
||||
|
||||
static __inline__ struct target_cmsghdr *
|
||||
__target_cmsg_nxthdr(struct target_msghdr *__mhdr,
|
||||
|
Loading…
Reference in New Issue
Block a user