diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-08-22 14:39:53 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-08-22 14:39:53 +0100 |
commit | 43fe62757b0b90af448e02c9bd55b62960556360 (patch) | |
tree | b7513ba75b7ee74c5ce4d184957cc91664abb1cc | |
parent | fd3cced366958cc90f0a8caa8213471afde9bf3c (diff) | |
parent | 29e03fcb62d413cf5fba06978346893ab72a1f64 (diff) |
Merge remote-tracking branch 'remotes/riku/linux-user-for-upstream' into staging
* remotes/riku/linux-user-for-upstream: (22 commits)
linux-user: check return value of malloc()
linux-user: writev Partial Writes
linux-user: Support target-to-host translation of mlockall argument
linux-user: clock_nanosleep errno Handling on PPC
linux-user: Minimum Sig Handler Stack Size for PPC64 ELF V2
linux-user: Move get_ppc64_abi
linux-user: Detect fault in sched_rr_get_interval
linux-user: Handle NULL sched_param argument to sched_*
linux-user: Detect Negative Message Sizes in msgsnd System Call
linux-user: Conditionally Pass Attribute Pointer to mq_open()
linux-user: Make ipc syscall's third argument an abi_long
linux-user: Properly Handle semun Structure In Cross-Endian Situations
linux-user: Dereference Pointer Argument to ipc/semctl Sys Call
linux-user: PPC64 semid_ds Doesnt Include _unused1 and _unused2
linux-user: add setns and unshare
linux-user: support ioprio_{get, set} syscalls
linux-user: support timerfd_{create, gettime, settime} syscalls
linux-user: fix readlink handling with magic exe symlink
linux-user: Fix conversion of sigevent argument to timer_create
linux-user: Fix syscall instruction usermode emulation on X86_64
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rwxr-xr-x | configure | 37 | ||||
-rw-r--r-- | include/exec/cpu-all.h | 2 | ||||
-rw-r--r-- | linux-user/aarch64/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/alpha/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/arm/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/cris/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/elfload.c | 9 | ||||
-rw-r--r-- | linux-user/i386/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/m68k/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/main.c | 1 | ||||
-rw-r--r-- | linux-user/microblaze/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/mips/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/mips64/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/openrisc/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/ppc/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/ppc/target_cpu.h | 10 | ||||
-rw-r--r-- | linux-user/s390x/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/sh4/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/signal.c | 12 | ||||
-rw-r--r-- | linux-user/sparc/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/sparc64/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/strace.list | 12 | ||||
-rw-r--r-- | linux-user/syscall.c | 279 | ||||
-rw-r--r-- | linux-user/unicore32/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/x86_64/syscall.h | 3 | ||||
-rw-r--r-- | target-i386/seg_helper.c | 4 |
26 files changed, 357 insertions, 66 deletions
@@ -3456,6 +3456,37 @@ if compile_prog "" "" ; then sendfile=yes fi +# check for timerfd support (glibc 2.8 and newer) +timerfd=no +cat > $TMPC << EOF +#include <sys/timerfd.h> + +int main(void) +{ + return(timerfd_create(CLOCK_REALTIME, 0)); +} +EOF +if compile_prog "" "" ; then + timerfd=yes +fi + +# check for setns and unshare support +setns=no +cat > $TMPC << EOF +#include <sched.h> + +int main(void) +{ + int ret; + ret = setns(0, 0); + ret = unshare(0); + return ret; +} +EOF +if compile_prog "" "" ; then + setns=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -4524,6 +4555,12 @@ fi if test "$sendfile" = "yes" ; then echo "CONFIG_SENDFILE=y" >> $config_host_mak fi +if test "$timerfd" = "yes" ; then + echo "CONFIG_TIMERFD=y" >> $config_host_mak +fi +if test "$setns" = "yes" ; then + echo "CONFIG_SETNS=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f91581fc65..f9d132fc0b 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -198,6 +198,8 @@ extern unsigned long reserved_va; #define RESERVED_VA 0ul #endif +#define GUEST_ADDR_MAX (RESERVED_VA ? RESERVED_VA : \ + (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1) #endif /* page related stuff */ diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/syscall.h index 18f44a8a40..dc72a15c5e 100644 --- a/linux-user/aarch64/syscall.h +++ b/linux-user/aarch64/syscall.h @@ -8,3 +8,6 @@ struct target_pt_regs { #define UNAME_MACHINE "aarch64" #define UNAME_MINIMUM_RELEASE "3.8.0" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index ed13d9a718..245cff2545 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -252,3 +252,6 @@ struct target_pt_regs { #define TARGET_UAC_NOPRINT 1 #define TARGET_UAC_NOFIX 2 #define TARGET_UAC_SIGBUS 4 +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index e0d2cc3e5d..3844a96112 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -44,3 +44,7 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index f5783c0557..2957b0d6ae 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -39,5 +39,8 @@ struct target_pt_regs { }; #define TARGET_CLONE_BACKWARDS2 +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 #endif diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 60777fecf6..bea803bd13 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -824,8 +824,6 @@ static uint32_t get_elf_hwcap2(void) NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0) -static inline uint32_t get_ppc64_abi(struct image_info *infop); - static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { _regs->gpr[1] = infop->start_stack; @@ -1205,13 +1203,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #include "elf.h" -#ifdef TARGET_PPC -static inline uint32_t get_ppc64_abi(struct image_info *infop) -{ - return infop->elf_flags & EF_PPC64_ABI; -} -#endif - struct exec { unsigned int a_info; /* Use macros N_MAGIC, etc for access */ diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 9bfc1ad8f7..906aaac0b1 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -147,3 +147,6 @@ struct target_vm86plus_struct { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index 889eaf7323..9218493a44 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -18,4 +18,8 @@ struct target_pt_regs { #define UNAME_MACHINE "m68k" #define UNAME_MINIMUM_RELEASE "2.6.32" +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 + void do_m68k_simcall(CPUM68KState *, int); diff --git a/linux-user/main.c b/linux-user/main.c index b453a39853..472a16d2db 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -309,7 +309,6 @@ void cpu_loop(CPUX86State *env) env->regs[8], env->regs[9], 0, 0); - env->eip = env->exception_next_eip; break; #endif case EXCP0B_NOSEG: diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index 5b5f6b447d..3c1ed27c04 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -49,5 +49,8 @@ struct target_pt_regs { }; #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 5bc56962a4..35ca23b166 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -228,3 +228,6 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index a7f5a5802a..6733107ddb 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -225,3 +225,6 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h index c3b36da83c..8ac03656d4 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/syscall.h @@ -23,3 +23,7 @@ struct target_pt_regs { #define UNAME_MACHINE "openrisc" #define UNAME_MINIMUM_RELEASE "2.6.32" + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index db92bbee17..0daf5cd2df 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -69,3 +69,7 @@ struct target_revectored_struct { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/ppc/target_cpu.h b/linux-user/ppc/target_cpu.h index 9cc0c3ba9c..26f4ba297f 100644 --- a/linux-user/ppc/target_cpu.h +++ b/linux-user/ppc/target_cpu.h @@ -38,4 +38,14 @@ static inline void cpu_set_tls(CPUPPCState *env, target_ulong newtls) #endif } +#ifndef EF_PPC64_ABI +#define EF_PPC64_ABI 0x3 +#endif + +static inline uint32_t get_ppc64_abi(struct image_info *infop) +{ + return infop->elf_flags & EF_PPC64_ABI; +} + + #endif diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index aaad512d4d..35f170af25 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -24,3 +24,6 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS2 +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h index ccd2216e38..7aa4f239c5 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/syscall.h @@ -11,3 +11,7 @@ struct target_pt_regs { #define UNAME_MACHINE "sh4" #define UNAME_MINIMUM_RELEASE "2.6.32" + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/signal.c b/linux-user/signal.c index 1141054be2..26929c59de 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -617,6 +617,15 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { struct target_sigaltstack *uss; struct target_sigaltstack ss; + size_t minstacksize = TARGET_MINSIGSTKSZ; + +#if defined(TARGET_PPC64) + /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */ + struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; + if (get_ppc64_abi(image) > 1) { + minstacksize = 4096; + } +#endif ret = -TARGET_EFAULT; if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { @@ -642,8 +651,9 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) ss.ss_sp = 0; } else { ret = -TARGET_ENOMEM; - if (ss.ss_size < MINSIGSTKSZ) + if (ss.ss_size < minstacksize) { goto out; + } } target_sigaltstack_used.ss_sp = ss.ss_sp; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 9549ea0a2f..58573b92ea 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -15,3 +15,6 @@ struct target_pt_regs { * and copy_thread(). */ #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index 82b1680cb6..8398d3f463 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -16,3 +16,6 @@ struct target_pt_regs { * and copy_thread(). */ #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/strace.list b/linux-user/strace.list index fcb258d348..aa0cd735cc 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1185,6 +1185,9 @@ #ifdef TARGET_NR_set_mempolicy { TARGET_NR_set_mempolicy, "set_mempolicy" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_setns +{ TARGET_NR_setns, "setns" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_setpgid { TARGET_NR_setpgid, "setpgid" , NULL, NULL, NULL }, #endif @@ -1404,6 +1407,15 @@ #ifdef TARGET_NR_timer_settime { TARGET_NR_timer_settime, "timer_settime" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_timerfd_create +{ TARGET_NR_timerfd_create, "timerfd_create" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_timerfd_gettime +{ TARGET_NR_timerfd_gettime, "timerfd_gettime" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_timerfd_settime +{ TARGET_NR_timerfd_settime, "timerfd_settime" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_times { TARGET_NR_times, "times" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a50229d0d7..7ff7c21255 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -58,6 +58,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <sys/shm.h> #include <sys/sem.h> #include <sys/statfs.h> +#include <sys/timerfd.h> #include <utime.h> #include <sys/sysinfo.h> //#include <sys/user.h> @@ -251,6 +252,12 @@ _syscall2(int, capget, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); _syscall2(int, capset, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); +#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get) +_syscall2(int, ioprio_get, int, which, int, who) +#endif +#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set) +_syscall3(int, ioprio_set, int, which, int, who, int, ioprio) +#endif static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, @@ -294,7 +301,6 @@ static int sys_getcwd1(char *buf, size_t size) return strlen(buf)+1; } -#ifdef TARGET_NR_openat static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) { /* @@ -306,7 +312,6 @@ static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) } return (openat(dirfd, pathname, flags)); } -#endif #ifdef TARGET_NR_utimensat #ifdef CONFIG_UTIMENSAT @@ -1798,6 +1803,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, abi_ulong total_len, max_len; int i; int err = 0; + bool bad_address = false; if (count == 0) { errno = 0; @@ -1838,9 +1844,20 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, vec[i].iov_base = 0; } else { vec[i].iov_base = lock_user(type, base, len, copy); + /* If the first buffer pointer is bad, this is a fault. But + * subsequent bad buffers will result in a partial write; this + * is realized by filling the vector with null pointers and + * zero lengths. */ if (!vec[i].iov_base) { - err = EFAULT; - goto fail; + if (i == 0) { + err = EFAULT; + goto fail; + } else { + bad_address = true; + } + } + if (bad_address) { + len = 0; } if (len > max_len - total_len) { len = max_len - total_len; @@ -2419,9 +2436,13 @@ struct target_semid_ds { struct target_ipc_perm sem_perm; abi_ulong sem_otime; +#if !defined(TARGET_PPC64) abi_ulong __unused1; +#endif abi_ulong sem_ctime; +#if !defined(TARGET_PPC64) abi_ulong __unused2; +#endif abi_ulong sem_nsems; abi_ulong __unused3; abi_ulong __unused4; @@ -2643,9 +2664,18 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, switch( cmd ) { case GETVAL: case SETVAL: - arg.val = tswap32(target_su.val); + /* In 64 bit cross-endian situations, we will erroneously pick up + * the wrong half of the union for the "val" element. To rectify + * this, the entire 8-byte structure is byteswapped, followed by + * a swap of the 4 byte val field. In other cases, the data is + * already in proper host byte order. */ + if (sizeof(target_su.val) != (sizeof(target_su.buf))) { + target_su.buf = tswapal(target_su.buf); + arg.val = tswap32(target_su.val); + } else { + arg.val = target_su.val; + } ret = get_errno(semctl(semid, semnum, cmd, arg)); - target_su.val = tswap32(arg.val); break; case GETALL: case SETALL: @@ -2861,15 +2891,23 @@ struct target_msgbuf { }; static inline abi_long do_msgsnd(int msqid, abi_long msgp, - unsigned int msgsz, int msgflg) + ssize_t msgsz, int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; abi_long ret = 0; + if (msgsz < 0) { + return -TARGET_EINVAL; + } + if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); + if (!host_mb) { + unlock_user_struct(target_mb, msgp, 0); + return -TARGET_ENOMEM; + } host_mb->mtype = (abi_long) tswapal(target_mb->mtype); memcpy(host_mb->mtext, target_mb->mtext, msgsz); ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg)); @@ -3112,8 +3150,8 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ -static abi_long do_ipc(unsigned int call, int first, - int second, int third, +static abi_long do_ipc(unsigned int call, abi_long first, + abi_long second, abi_long third, abi_long ptr, abi_long fifth) { int version; @@ -3131,9 +3169,15 @@ static abi_long do_ipc(unsigned int call, int first, ret = get_errno(semget(first, second, third)); break; - case IPCOP_semctl: - ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); + case IPCOP_semctl: { + /* The semun argument to semctl is passed by value, so dereference the + * ptr argument. */ + abi_ulong atptr; + get_user_ual(atptr, ptr); + ret = do_semctl(first, second, third, + (union target_semun) atptr); break; + } case IPCOP_msgget: ret = get_errno(msgget(first, second)); @@ -4914,6 +4958,47 @@ static inline abi_long host_to_target_itimerspec(abi_ulong target_addr, return 0; } +static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, + abi_ulong target_addr) +{ + struct target_sigevent *target_sevp; + + if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) { + return -TARGET_EFAULT; + } + + /* This union is awkward on 64 bit systems because it has a 32 bit + * integer and a pointer in it; we follow the conversion approach + * used for handling sigval types in signal.c so the guest should get + * the correct value back even if we did a 64 bit byteswap and it's + * using the 32 bit integer. + */ + host_sevp->sigev_value.sival_ptr = + (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr); + host_sevp->sigev_signo = + target_to_host_signal(tswap32(target_sevp->sigev_signo)); + host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify); + host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid); + + unlock_user_struct(target_sevp, target_addr, 1); + return 0; +} + +#if defined(TARGET_NR_mlockall) +static inline int target_to_host_mlockall_arg(int arg) +{ + int result = 0; + + if (arg & TARGET_MLOCKALL_MCL_CURRENT) { + result |= MCL_CURRENT; + } + if (arg & TARGET_MLOCKALL_MCL_FUTURE) { + result |= MCL_FUTURE; + } + return result; +} +#endif + #if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat) static inline abi_long host_to_target_stat64(void *cpu_env, abi_ulong target_addr, @@ -5092,10 +5177,8 @@ static int open_self_cmdline(void *cpu_env, int fd) static int open_self_maps(void *cpu_env, int fd) { -#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; -#endif FILE *fp; char *line = NULL; size_t len = 0; @@ -5118,13 +5201,18 @@ static int open_self_maps(void *cpu_env, int fd) if ((fields < 10) || (fields > 11)) { continue; } - if (!strncmp(path, "[stack]", 7)) { - continue; - } - if (h2g_valid(min) && h2g_valid(max)) { + if (h2g_valid(min)) { + int flags = page_get_flags(h2g(min)); + max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX); + if (page_check_range(h2g(min), max - min, flags) == -1) { + continue; + } + if (h2g(min) == ts->info->stack_limit) { + pstrcpy(path, sizeof(path), " [stack]"); + } dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", - h2g(min), h2g(max), flag_r, flag_w, + h2g(min), h2g(max - 1) + 1, flag_r, flag_w, flag_x, flag_p, offset, dev_maj, dev_min, inode, path[0] ? " " : "", path); } @@ -5133,14 +5221,6 @@ static int open_self_maps(void *cpu_env, int fd) free(line); fclose(fp); -#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) - dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n", - (unsigned long long)ts->info->stack_limit, - (unsigned long long)(ts->info->start_stack + - (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK, - (unsigned long long)0); -#endif - return 0; } @@ -5279,7 +5359,7 @@ static int open_net_route(void *cpu_env, int fd) } #endif -static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) +static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) { struct fake_open { const char *filename; @@ -5300,7 +5380,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) if (is_proc_myself(pathname, "exe")) { int execfd = qemu_getauxval(AT_EXECFD); - return execfd ? execfd : get_errno(open(exec_path, flags, mode)); + return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode)); } for (fake_open = fakes; fake_open->filename; fake_open++) { @@ -5334,7 +5414,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) return fd; } - return get_errno(open(path(pathname), flags, mode)); + return get_errno(sys_openat(dirfd, path(pathname), flags, mode)); } /* do_syscall() should always have a single exit point at the end so @@ -5409,22 +5489,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_open: if (!(p = lock_user_string(arg1))) goto efault; - ret = get_errno(do_open(cpu_env, p, - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); + ret = get_errno(do_openat(cpu_env, AT_FDCWD, p, + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); unlock_user(p, arg1, 0); break; -#if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_openat(arg1, - path(p), - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); + ret = get_errno(do_openat(cpu_env, arg1, p, + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); unlock_user(p, arg2, 0); break; -#endif case TARGET_NR_close: ret = get_errno(close(arg1)); break; @@ -6620,11 +6697,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); if (!p || !p2) { ret = -TARGET_EFAULT; + } else if (!arg3) { + /* Short circuit this for the magic exe check. */ + ret = -TARGET_EINVAL; } else if (is_proc_myself((const char *)p, "exe")) { char real[PATH_MAX], *temp; temp = realpath(exec_path, real); - ret = temp == NULL ? get_errno(-1) : strlen(real) ; - snprintf((char *)p2, arg3, "%s", real); + /* Return value is # of bytes that we wrote to the buffer. */ + if (temp == NULL) { + ret = get_errno(-1); + } else { + /* Don't worry about sign mismatch as earlier mapping + * logic would have thrown a bad address error. */ + ret = MIN(strlen(real), arg3); + /* We cannot NUL terminate the string. */ + memcpy(p2, real, ret); + } } else { ret = get_errno(readlink(path(p), p2, arg3)); } @@ -6763,7 +6851,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_mlockall case TARGET_NR_mlockall: - ret = get_errno(mlockall(arg1)); + ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1))); break; #endif #ifdef TARGET_NR_munlockall @@ -7679,6 +7767,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param *target_schp; struct sched_param schp; + if (arg2 == 0) { + return -TARGET_EINVAL; + } if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); @@ -7690,6 +7781,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; + + if (arg2 == 0) { + return -TARGET_EINVAL; + } ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) @@ -7703,6 +7798,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; + if (arg3 == 0) { + return -TARGET_EINVAL; + } if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); @@ -7727,7 +7825,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec ts; ret = get_errno(sched_rr_get_interval(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + ret = host_to_target_timespec(arg2, &ts); } } break; @@ -8966,6 +9064,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL)); if (arg4) host_to_target_timespec(arg4, &ts); + +#if defined(TARGET_PPC) + /* clock_nanosleep is odd in that it returns positive errno values. + * On PPC, CR0 bit 3 should be set in such a situation. */ + if (ret) { + ((CPUPPCState *)cpu_env)->crf[0] |= 1; + } +#endif break; } #endif @@ -9062,12 +9168,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) case TARGET_NR_mq_open: { - struct mq_attr posix_mq_attr; + struct mq_attr posix_mq_attr, *attrp; p = lock_user_string(arg1 - 1); - if (arg4 != 0) + if (arg4 != 0) { copy_from_user_mq_attr (&posix_mq_attr, arg4); - ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr)); + attrp = &posix_mq_attr; + } else { + attrp = 0; + } + ret = get_errno(mq_open(p, arg2, arg3, attrp)); unlock_user (p, arg1, 0); } break; @@ -9413,7 +9523,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */ struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL; - struct target_sigevent *ptarget_sevp; struct target_timer_t *ptarget_timer; int clkid = arg1; @@ -9425,14 +9534,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, timer_t *phtimer = g_posix_timers + timer_index; if (arg2) { - if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) { - goto efault; - } - - host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo); - host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify); - phost_sevp = &host_sevp; + ret = target_to_host_sigevent(phost_sevp, arg2); + if (ret != 0) { + break; + } } ret = get_errno(timer_create(clkid, phost_sevp, phtimer)); @@ -9524,6 +9630,73 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } #endif +#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_create: + ret = get_errno(timerfd_create(arg1, + target_to_host_bitmask(arg2, fcntl_flags_tbl))); + break; +#endif + +#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_gettime: + { + struct itimerspec its_curr; + + ret = get_errno(timerfd_gettime(arg1, &its_curr)); + + if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) { + goto efault; + } + } + break; +#endif + +#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_settime: + { + struct itimerspec its_new, its_old, *p_new; + + if (arg3) { + if (target_to_host_itimerspec(&its_new, arg3)) { + goto efault; + } + p_new = &its_new; + } else { + p_new = NULL; + } + + ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old)); + + if (arg4 && host_to_target_itimerspec(arg4, &its_old)) { + goto efault; + } + } + break; +#endif + +#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get) + case TARGET_NR_ioprio_get: + ret = get_errno(ioprio_get(arg1, arg2)); + break; +#endif + +#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set) + case TARGET_NR_ioprio_set: + ret = get_errno(ioprio_set(arg1, arg2, arg3)); + break; +#endif + +#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS) + case TARGET_NR_setns: + ret = get_errno(setns(arg1, arg2)); + break; +#endif +#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS) + case TARGET_NR_unshare: + ret = get_errno(unshare(arg1)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h index f7e55254cf..385a97562d 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/syscall.h @@ -53,4 +53,8 @@ struct target_pt_regs { #define UNAME_MACHINE "UniCore-II" #define UNAME_MINIMUM_RELEASE "2.6.32" +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 + #endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index e03b5a0cfc..88b3c3fe31 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -97,3 +97,6 @@ struct target_msqid64_ds { #define TARGET_ARCH_SET_FS 0x1002 #define TARGET_ARCH_GET_FS 0x1003 #define TARGET_ARCH_GET_GS 0x1004 +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 2d970d0cb9..13eefbac3b 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1127,8 +1127,8 @@ static void do_interrupt_user(CPUX86State *env, int intno, int is_int, /* Since we emulate only user space, we cannot do more than exiting the emulation with the suitable exception and error - code */ - if (is_int) { + code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ + if (is_int || intno == EXCP_SYSCALL) { env->eip = next_eip; } } |