-----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>
master
Peter Maydell 2018-01-25 09:53:53 +00:00
commit 0f79bfe38a
10 changed files with 328 additions and 149 deletions

View File

@ -2181,29 +2181,41 @@ int page_unprotect(target_ulong address, uintptr_t pc)
/* if the page was really writable, then we change its /* if the page was really writable, then we change its
protection back to writable */ protection back to writable */
if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) { if (p->flags & PAGE_WRITE_ORG) {
host_start = address & qemu_host_page_mask;
host_end = host_start + qemu_host_page_size;
prot = 0;
current_tb_invalidated = false; current_tb_invalidated = false;
for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) { if (p->flags & PAGE_WRITE) {
p = page_find(addr >> TARGET_PAGE_BITS); /* If the page is actually marked WRITE then assume this is because
p->flags |= PAGE_WRITE; * this thread raced with another one which got here first and
prot |= p->flags; * set the page to PAGE_WRITE and did the TB invalidate for us.
*/
/* and since the content will be modified, we must invalidate #ifdef TARGET_HAS_PRECISE_SMC
the corresponding translated code. */ TranslationBlock *current_tb = tb_find_pc(pc);
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc); if (current_tb) {
#ifdef CONFIG_USER_ONLY current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID;
if (DEBUG_TB_CHECK_GATE) {
tb_invalidate_check(addr);
} }
#endif #endif
} } else {
mprotect((void *)g2h(host_start), qemu_host_page_size, host_start = address & qemu_host_page_mask;
prot & PAGE_BITS); 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(); mmap_unlock();
/* If current TB was invalidated return to main loop */ /* If current TB was invalidated return to main loop */
return current_tb_invalidated ? 2 : 1; return current_tb_invalidated ? 2 : 1;

View File

@ -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 the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */ 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) int is_write, sigset_t *old_set)
{ {
CPUState *cpu = current_cpu; CPUState *cpu = current_cpu;
CPUClass *cc; CPUClass *cc;
int ret; int ret;
unsigned long address = (unsigned long)info->si_addr;
/* We must handle PC addresses from two different sources: /* We must handle PC addresses from two different sources:
* a call return address and a signal frame address. * 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); pc, address, is_write, *(unsigned long *)old_set);
#endif #endif
/* XXX: locking issue */ /* 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)) { switch (page_unprotect(h2g(address), pc)) {
case 0: case 0:
/* Fault not caused by a page marked unwritable to protect /* Fault not caused by a page marked unwritable to protect
@ -215,9 +227,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#endif #endif
pc = EIP_sig(uc); pc = EIP_sig(uc);
trapno = TRAP_sig(uc); trapno = TRAP_sig(uc);
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info,
trapno == 0xe ? trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
(ERROR_sig(uc) >> 1) & 1 : 0,
&MASK_sig(uc)); &MASK_sig(uc));
} }
@ -261,9 +272,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#endif #endif
pc = PC_sig(uc); pc = PC_sig(uc);
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info,
TRAP_sig(uc) == 0xe ? TRAP_sig(uc) == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
(ERROR_sig(uc) >> 1) & 1 : 0,
&MASK_sig(uc)); &MASK_sig(uc));
} }
@ -341,8 +351,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
is_write = 1; is_write = 1;
} }
#endif #endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask);
} }
#elif defined(__alpha__) #elif defined(__alpha__)
@ -372,8 +381,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
is_write = 1; is_write = 1;
} }
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask);
} }
#elif defined(__sparc__) #elif defined(__sparc__)
@ -432,8 +440,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
break; break;
} }
} }
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, sigmask);
is_write, sigmask);
} }
#elif defined(__arm__) #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). * later processor; on v5 we will always report this as a read).
*/ */
is_write = extract32(uc->uc_mcontext.error_code, 11, 1); is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write,
&uc->uc_sigmask);
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
@ -495,8 +500,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
/* Ignore bits 23 & 24, controlling indexing. */ /* Ignore bits 23 & 24, controlling indexing. */
|| (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */ || (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
return handle_cpu_signal(pc, (uintptr_t)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask);
} }
#elif defined(__ia64) #elif defined(__ia64)
@ -529,9 +533,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
default: default:
break; break;
} }
return handle_cpu_signal(ip, (unsigned long)info->si_addr, return handle_cpu_signal(ip, info, is_write, (sigset_t *)&uc->uc_sigmask);
is_write,
(sigset_t *)&uc->uc_sigmask);
} }
#elif defined(__s390__) #elif defined(__s390__)
@ -583,8 +585,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
} }
break; break;
} }
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask);
} }
#elif defined(__mips__) #elif defined(__mips__)
@ -599,8 +600,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
/* XXX: compute is_write */ /* XXX: compute is_write */
is_write = 0; is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr, return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask);
} }
#else #else

View File

@ -1,11 +1,12 @@
# core qdev-related obj files, also used by *-user: # core qdev-related obj files, also used by *-user:
common-obj-y += qdev.o qdev-properties.o common-obj-y += qdev.o qdev-properties.o
common-obj-y += bus.o reset.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: # irq.o needed for qdev GPIO handling:
common-obj-y += irq.o common-obj-y += irq.o
common-obj-y += hotplug.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_EMPTY_SLOT) += empty_slot.o
common-obj-$(CONFIG_XILINX_AXI) += stream.o common-obj-$(CONFIG_XILINX_AXI) += stream.o

96
hw/core/qdev-fw.c Normal file
View 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);
}

View File

@ -27,7 +27,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "hw/fw-path-provider.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
@ -48,17 +47,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
return dc->vmsd; 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) static void bus_remove_child(BusState *bus, DeviceState *child)
{ {
BusChild *kid; BusChild *kid;
@ -631,71 +619,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
return NULL; 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) char *qdev_get_dev_path(DeviceState *dev)
{ {
BusClass *bc; BusClass *bc;

View File

@ -1354,7 +1354,7 @@ struct exec
~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1)) ~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (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) 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_HWCAP, (abi_ulong) ELF_HWCAP);
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); 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_RANDOM, (abi_ulong) u_rand_bytes);
NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
#ifdef ELF_HWCAP2 #ifdef ELF_HWCAP2
NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);

View File

@ -127,9 +127,10 @@ int cpu_get_pic_interrupt(CPUX86State *env)
/* Make sure everything is in a consistent state for calling fork(). */ /* Make sure everything is in a consistent state for calling fork(). */
void fork_start(void) void fork_start(void)
{ {
cpu_list_lock(); start_exclusive();
qemu_mutex_lock(&tb_ctx.tb_lock);
mmap_fork_start(); mmap_fork_start();
qemu_mutex_lock(&tb_ctx.tb_lock);
cpu_list_lock();
} }
void fork_end(int child) void fork_end(int child)
@ -147,9 +148,13 @@ void fork_end(int child)
qemu_mutex_init(&tb_ctx.tb_lock); qemu_mutex_init(&tb_ctx.tb_lock);
qemu_init_cpu_list(); qemu_init_cpu_list();
gdbserver_fork(thread_cpu); 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 { } else {
qemu_mutex_unlock(&tb_ctx.tb_lock); qemu_mutex_unlock(&tb_ctx.tb_lock);
cpu_list_unlock(); cpu_list_unlock();
end_exclusive();
} }
} }

View File

@ -234,7 +234,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
if (prot) { if (prot) {
end_addr = addr; end_addr = addr;
} }
if (addr + size == end_addr) { if (addr && addr + size == end_addr) {
break; break;
} }
addr -= qemu_host_page_size; addr -= qemu_host_page_size;

View File

@ -296,6 +296,8 @@ _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
#define __NR_sys_sched_setaffinity __NR_sched_setaffinity #define __NR_sys_sched_setaffinity __NR_sched_setaffinity
_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len, _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr); 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, _syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
void *, arg); void *, arg);
_syscall2(int, capget, struct __user_cap_header_struct *, header, _syscall2(int, capget, struct __user_cap_header_struct *, header,
@ -598,6 +600,24 @@ static int sys_utimensat(int dirfd, const char *pathname,
#endif #endif
#endif /* TARGET_NR_utimensat */ #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 #ifdef CONFIG_INOTIFY
#include <sys/inotify.h> #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); void *target_data = TARGET_CMSG_DATA(target_cmsg);
int len = tswapal(target_cmsg->cmsg_len) int len = tswapal(target_cmsg->cmsg_len)
- TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); - sizeof(struct target_cmsghdr);
space += CMSG_SPACE(len); space += CMSG_SPACE(len);
if (space > msgh->msg_controllen) { 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 *data = CMSG_DATA(cmsg);
void *target_data = TARGET_CMSG_DATA(target_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; int tgt_len, tgt_space;
/* We never copy a half-header but may copy half-data; /* 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 * to the guest via the CTRUNC bit), unlike truncation
* in target_to_host_cmsg, which is a QEMU bug. * 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); target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
break; 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); target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
tgt_len = TARGET_CMSG_LEN(len);
/* Payload types which need a different size of payload on /* Payload types which need a different size of payload on
* the target must adjust tgt_len here. * 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; break;
} }
default: default:
tgt_len = len;
break; break;
} }
if (msg_controllen < tgt_len) { if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
target_msgh->msg_flags |= tswap32(MSG_CTRUNC); 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 /* 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 *v = (uint32_t *)data;
uint32_t *t_int = (uint32_t *)target_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); __put_user(*v, t_int);
break; 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_errh =
(struct errhdr_t *)target_data; (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_errno, &target_errh->ee.ee_errno);
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __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 *v = (uint32_t *)data;
uint32_t *t_int = (uint32_t *)target_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); __put_user(*v, t_int);
break; 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_errh =
(struct errhdr6_t *)target_data; (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_errno, &target_errh->ee.ee_errno);
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __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); target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
tgt_space = TARGET_CMSG_SPACE(len); tgt_space = TARGET_CMSG_SPACE(tgt_len);
if (msg_controllen < tgt_space) { if (msg_controllen < tgt_space) {
tgt_space = msg_controllen; tgt_space = msg_controllen;
} }
@ -7716,6 +7751,73 @@ static TargetFdTrans target_inotify_trans = {
}; };
#endif #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 /* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed. that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */ 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; break;
#endif #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 #ifdef TARGET_NR_mkdir
case TARGET_NR_mkdir: case TARGET_NR_mkdir:
if (!(p = lock_user_string(arg1))) if (!(p = lock_user_string(arg1)))
@ -8475,11 +8593,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3) #if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
case 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) { if (ret >= 0) {
fd_trans_dup(arg1, arg2); fd_trans_dup(arg1, arg2);
} }
break; break;
}
#endif #endif
#ifdef TARGET_NR_getppid /* not on alpha */ #ifdef TARGET_NR_getppid /* not on alpha */
case TARGET_NR_getppid: 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_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
mask = alloca(mask_size); mask = alloca(mask_size);
memset(mask, 0, mask_size);
ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask)); ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
if (!is_error(ret)) { if (!is_error(ret)) {
@ -10372,9 +10499,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = arg2; ret = arg2;
} }
if (copy_to_user(arg3, mask, ret)) { ret = host_to_target_cpu_mask(mask, mask_size, arg3, arg2);
goto efault;
}
} }
} }
break; break;
@ -10392,17 +10517,33 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break; break;
} }
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1); mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
mask = alloca(mask_size); 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)); ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
} }
break; 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: case TARGET_NR_sched_setparam:
{ {
struct sched_param *target_schp; struct sched_param *target_schp;

View File

@ -303,9 +303,9 @@ struct target_cmsghdr {
__target_cmsg_nxthdr(mhdr, cmsg, cmsg_start) __target_cmsg_nxthdr(mhdr, cmsg, cmsg_start)
#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \ #define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \
& (size_t) ~(sizeof (abi_long) - 1)) & (size_t) ~(sizeof (abi_long) - 1))
#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ #define TARGET_CMSG_SPACE(len) (sizeof(struct target_cmsghdr) + \
+ TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr))) TARGET_CMSG_ALIGN(len))
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) #define TARGET_CMSG_LEN(len) (sizeof(struct target_cmsghdr) + (len))
static __inline__ struct target_cmsghdr * static __inline__ struct target_cmsghdr *
__target_cmsg_nxthdr(struct target_msghdr *__mhdr, __target_cmsg_nxthdr(struct target_msghdr *__mhdr,