]> Git Repo - qemu.git/blobdiff - linux-user/syscall.c
Implement waitid syscall.
[qemu.git] / linux-user / syscall.c
index bf7b31bebe2d5aaa648f4eeed1ec017102c7ad6f..618e57ef2318a9dd76e677a0c3b8341251bd3a10 100644 (file)
@@ -52,6 +52,9 @@
 //#include <sys/user.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
+#if defined(USE_NPTL)
+#include <sys/futex.h>
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -68,6 +71,7 @@
 #include <linux/soundcard.h>
 #include <linux/dirent.h>
 #include <linux/kd.h>
+#include "linux_loop.h"
 
 #include "qemu.h"
 
@@ -159,6 +163,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6)       \
 #define __NR_sys_tkill __NR_tkill
 #define __NR_sys_unlinkat __NR_unlinkat
 #define __NR_sys_utimensat __NR_utimensat
+#define __NR_sys_futex __NR_futex
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -240,6 +245,11 @@ _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
           const struct timespec *,tsp,int,flags)
 #endif
+#if defined(TARGET_NR_futex) && defined(__NR_futex)
+_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
+          const struct timespec *,timeout,int *,uaddr2,int,val3)
+          
+#endif
 
 extern int personality(int);
 extern int flock(int, int);
@@ -420,7 +430,7 @@ abi_long do_brk(abi_ulong new_brk)
     if (!new_brk)
         return target_brk;
     if (new_brk < target_original_brk)
-        return -TARGET_ENOMEM;
+        return target_brk;
 
     brk_page = HOST_PAGE_ALIGN(target_brk);
 
@@ -435,58 +445,73 @@ abi_long do_brk(abi_ulong new_brk)
     mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
                                         PROT_READ|PROT_WRITE,
                                         MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
-    if (is_error(mapped_addr)) {
-       return mapped_addr;
-    } else {
+
+    if (!is_error(mapped_addr))
        target_brk = new_brk;
-       return target_brk;
-    }
+    
+    return target_brk;
 }
 
-static inline fd_set *target_to_host_fds(fd_set *fds,
-                                         abi_long *target_fds, int n)
+static inline abi_long copy_from_user_fdset(fd_set *fds,
+                                            abi_ulong target_fds_addr,
+                                            int n)
 {
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
-    return (fd_set *)target_fds;
-#else
-    int i, b;
-    if (target_fds) {
-        FD_ZERO(fds);
-        for(i = 0;i < n; i++) {
-            b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >>
-                 (i & (TARGET_ABI_BITS - 1))) & 1;
-            if (b)
-                FD_SET(i, fds);
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_READ,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 1)))
+        return -TARGET_EFAULT;
+
+    FD_ZERO(fds);
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        /* grab the abi_ulong */
+        __get_user(b, &target_fds[i]);
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            /* check the bit inside the abi_ulong */
+            if ((b >> j) & 1)
+                FD_SET(k, fds);
+            k++;
         }
-        return fds;
-    } else {
-        return NULL;
     }
-#endif
+
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
 }
 
-static inline void host_to_target_fds(abi_long *target_fds,
-                                      fd_set *fds, int n)
+static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
+                                          const fd_set *fds,
+                                          int n)
 {
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
-    /* nothing to do */
-#else
     int i, nw, j, k;
     abi_long v;
+    abi_ulong *target_fds;
 
-    if (target_fds) {
-        nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
-        k = 0;
-        for(i = 0;i < nw; i++) {
-            v = 0;
-            for(j = 0; j < TARGET_ABI_BITS; j++) {
-                v |= ((FD_ISSET(k, fds) != 0) << j);
-                k++;
-            }
-            target_fds[i] = tswapl(v);
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_WRITE,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 0)))
+        return -TARGET_EFAULT;
+
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        v = 0;
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            v |= ((FD_ISSET(k, fds) != 0) << j);
+            k++;
         }
+        __put_user(v, &target_fds[i]);
     }
-#endif
+
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
 }
 
 #if defined(__alpha__)
@@ -534,30 +559,34 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr,
     return 0;
 }
 
-static inline abi_long target_to_host_timeval(struct timeval *tv,
-                                              abi_ulong target_addr)
+static inline abi_long copy_from_user_timeval(struct timeval *tv,
+                                              abi_ulong target_tv_addr)
 {
     struct target_timeval *target_tv;
 
-    if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1))
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
         return -TARGET_EFAULT;
-    tv->tv_sec = tswapl(target_tv->tv_sec);
-    tv->tv_usec = tswapl(target_tv->tv_usec);
-    unlock_user_struct(target_tv, target_addr, 0);
+
+    __get_user(tv->tv_sec, &target_tv->tv_sec);
+    __get_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 0);
 
     return 0;
 }
 
-static inline abi_long host_to_target_timeval(abi_ulong target_addr,
-                                              const struct timeval *tv)
+static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
+                                            const struct timeval *tv)
 {
     struct target_timeval *target_tv;
 
-    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0))
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
         return -TARGET_EFAULT;
-    target_tv->tv_sec = tswapl(tv->tv_sec);
-    target_tv->tv_usec = tswapl(tv->tv_usec);
-    unlock_user_struct(target_tv, target_addr, 1);
+
+    __put_user(tv->tv_sec, &target_tv->tv_sec);
+    __put_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 1);
 
     return 0;
 }
@@ -565,74 +594,58 @@ static inline abi_long host_to_target_timeval(abi_ulong target_addr,
 
 /* do_select() must return target values and target errnos. */
 static abi_long do_select(int n,
-                          abi_ulong rfd_p, abi_ulong wfd_p,
-                          abi_ulong efd_p, abi_ulong target_tv)
+                          abi_ulong rfd_addr, abi_ulong wfd_addr,
+                          abi_ulong efd_addr, abi_ulong target_tv_addr)
 {
     fd_set rfds, wfds, efds;
     fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
-    abi_long *target_rfds, *target_wfds, *target_efds;
     struct timeval tv, *tv_ptr;
     abi_long ret;
-    int ok;
 
-    if (rfd_p) {
-        target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1);
-        if (!target_rfds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        rfds_ptr = target_to_host_fds(&rfds, target_rfds, n);
+    if (rfd_addr) {
+        if (copy_from_user_fdset(&rfds, rfd_addr, n))
+            return -TARGET_EFAULT;
+        rfds_ptr = &rfds;
     } else {
-        target_rfds = NULL;
         rfds_ptr = NULL;
     }
-    if (wfd_p) {
-        target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1);
-        if (!target_wfds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        wfds_ptr = target_to_host_fds(&wfds, target_wfds, n);
+    if (wfd_addr) {
+        if (copy_from_user_fdset(&wfds, wfd_addr, n))
+            return -TARGET_EFAULT;
+        wfds_ptr = &wfds;
     } else {
-        target_wfds = NULL;
         wfds_ptr = NULL;
     }
-    if (efd_p) {
-        target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1);
-        if (!target_efds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        efds_ptr = target_to_host_fds(&efds, target_efds, n);
+    if (efd_addr) {
+        if (copy_from_user_fdset(&efds, efd_addr, n))
+            return -TARGET_EFAULT;
+        efds_ptr = &efds;
     } else {
-        target_efds = NULL;
         efds_ptr = NULL;
     }
 
-    if (target_tv) {
-        target_to_host_timeval(&tv, target_tv);
+    if (target_tv_addr) {
+        if (copy_from_user_timeval(&tv, target_tv_addr))
+            return -TARGET_EFAULT;
         tv_ptr = &tv;
     } else {
         tv_ptr = NULL;
     }
+
     ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
-    ok = !is_error(ret);
 
-    if (ok) {
-        host_to_target_fds(target_rfds, rfds_ptr, n);
-        host_to_target_fds(target_wfds, wfds_ptr, n);
-        host_to_target_fds(target_efds, efds_ptr, n);
+    if (!is_error(ret)) {
+        if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+            return -TARGET_EFAULT;
+        if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+            return -TARGET_EFAULT;
+        if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+            return -TARGET_EFAULT;
 
-        if (target_tv) {
-            host_to_target_timeval(target_tv, &tv);
-        }
+        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
+            return -TARGET_EFAULT;
     }
 
-end:
-    unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0);
-    unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0);
-    unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0);
-
     return ret;
 }
 
@@ -902,7 +915,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
     default:
     unimplemented:
         gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
-        ret = -TARGET_ENOSYS;
+        ret = -TARGET_ENOPROTOOPT;
     }
     return ret;
 }
@@ -992,14 +1005,15 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
             }
             break;
         default:
-            goto unimplemented;
+            ret = -TARGET_ENOPROTOOPT;
+            break;
         }
         break;
     default:
     unimplemented:
         gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                  level, optname);
-        ret = -TARGET_ENOSYS;
+        ret = -TARGET_EOPNOTSUPP;
         break;
     }
     return ret;
@@ -1022,9 +1036,14 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
     for(i = 0;i < count; i++) {
         base = tswapl(target_vec[i].iov_base);
         vec[i].iov_len = tswapl(target_vec[i].iov_len);
-        vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
-       if (!vec[i].iov_base) 
-            goto fail;
+        if (vec[i].iov_len != 0) {
+            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
+            if (!vec[i].iov_base && vec[i].iov_len) 
+                goto fail;
+        } else {
+            /* zero length pointer is ignored */
+            vec[i].iov_base = NULL;
+        }
     }
     unlock_user (target_vec, target_addr, 0);
     return 0;
@@ -2708,6 +2727,14 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
     CPUState *new_env;
 
     if (flags & CLONE_VM) {
+#if defined(USE_NPTL)
+        /* qemu is not threadsafe.  Bail out immediately if application
+           tries to create a thread.  */
+        if (!(flags & CLONE_VFORK)) {
+            gemu_log ("clone(CLONE_VM) not supported\n");
+            return -EINVAL;
+        }
+#endif
         ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
         memset(ts, 0, sizeof(TaskState));
         new_stack = ts->stack;
@@ -2717,64 +2744,8 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
         first_task_state = ts;
         /* we create a new CPU instance. */
         new_env = cpu_copy(env);
-#if defined(TARGET_I386)
-        if (!newsp)
-            newsp = env->regs[R_ESP];
-        new_env->regs[R_ESP] = newsp;
-        new_env->regs[R_EAX] = 0;
-#elif defined(TARGET_ARM)
-        if (!newsp)
-            newsp = env->regs[13];
-        new_env->regs[13] = newsp;
-        new_env->regs[0] = 0;
-#elif defined(TARGET_SPARC)
-        if (!newsp)
-            newsp = env->regwptr[22];
-        new_env->regwptr[22] = newsp;
-        new_env->regwptr[0] = 0;
-       /* XXXXX */
-        printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
-#elif defined(TARGET_M68K)
-        if (!newsp)
-            newsp = env->aregs[7];
-        new_env->aregs[7] = newsp;
-        new_env->dregs[0] = 0;
-        /* ??? is this sufficient?  */
-#elif defined(TARGET_MIPS)
-        if (!newsp)
-            newsp = env->gpr[29][env->current_tc];
-        new_env->gpr[29][env->current_tc] = newsp;
-#elif defined(TARGET_PPC)
-        if (!newsp)
-            newsp = env->gpr[1];
-        new_env->gpr[1] = newsp;
-        {
-            int i;
-            for (i = 7; i < 32; i++)
-                new_env->gpr[i] = 0;
-        }
-#elif defined(TARGET_SH4)
-       if (!newsp)
-         newsp = env->gregs[15];
-       new_env->gregs[15] = newsp;
-       /* XXXXX */
-#elif defined(TARGET_ALPHA)
-       if (!newsp)
-         newsp = env->ir[30];
-       new_env->ir[30] = newsp;
-        /* ? */
-        {
-            int i;
-            for (i = 7; i < 30; i++)
-                new_env->ir[i] = 0;
-        }
-#elif defined(TARGET_CRIS)
-       if (!newsp)
-         newsp = env->regs[14];
-       new_env->regs[14] = newsp;
-#else
-#error unsupported target CPU
-#endif
+        /* Init regs that differ from the parent.  */
+        cpu_clone_regs(new_env, newsp);
         new_env->opaque = ts;
 #ifdef __ia64__
         ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
@@ -2786,6 +2757,9 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
         if ((flags & ~CSIGNAL) != 0)
             return -EINVAL;
         ret = fork();
+        if (ret == 0) {
+            cpu_clone_regs(env, newsp);
+        }
     }
     return ret;
 }
@@ -3030,6 +3004,7 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
     host_ts->tv_sec = tswapl(target_ts->tv_sec);
     host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 0);
+    return 0;
 }
 
 static inline abi_long host_to_target_timespec(abi_ulong target_addr,
@@ -3042,6 +3017,77 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
     target_ts->tv_sec = tswapl(host_ts->tv_sec);
     target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 1);
+    return 0;
+}
+
+#if defined(USE_NPTL)
+/* ??? Using host futex calls even when target atomic operations
+   are not really atomic probably breaks things.  However implementing
+   futexes locally would make futexes shared between multiple processes
+   tricky.  However they're probably useless because guest atomic
+   operations won't work either.  */
+int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
+             target_ulong uaddr2, int val3)
+{
+    struct timespec ts, *pts;
+
+    /* ??? We assume FUTEX_* constants are the same on both host
+       and target.  */
+    switch (op) {
+    case FUTEX_WAIT:
+        if (timeout) {
+            pts = &ts;
+            target_to_host_timespec(pts, timeout);
+        } else {
+            pts = NULL;
+        }
+        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
+                         pts, NULL, 0));
+    case FUTEX_WAKE:
+        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
+    case FUTEX_FD:
+        return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
+    case FUTEX_REQUEUE:
+        return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
+                         NULL, g2h(uaddr2), 0));
+    case FUTEX_CMP_REQUEUE:
+        return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
+                         NULL, g2h(uaddr2), tswap32(val3)));
+    default:
+        return -TARGET_ENOSYS;
+    }
+}
+#endif
+
+int get_osversion(void)
+{
+    static int osversion;
+    struct new_utsname buf;
+    const char *s;
+    int i, n, tmp;
+    if (osversion)
+        return osversion;
+    if (qemu_uname_release && *qemu_uname_release) {
+        s = qemu_uname_release;
+    } else {
+        if (sys_uname(&buf))
+            return 0;
+        s = buf.release;
+    }
+    tmp = 0;
+    for (i = 0; i < 3; i++) {
+        n = 0;
+        while (*s >= '0' && *s <= '9') {
+            n *= 10;
+            n += *s - '0';
+            s++;
+        }
+        tmp = (tmp << 8) + n;
+        if (*s == '.')
+            s++;
+    }
+    osversion = tmp;
+    return osversion;
 }
 
 /* do_syscall() should always have a single exit point at the end so
@@ -3123,6 +3169,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         }
         break;
 #endif
+#ifdef TARGET_NR_waitid
+    case TARGET_NR_waitid:
+        {
+            siginfo_t info;
+            info.si_pid = 0;
+            ret = get_errno(waitid(arg1, arg2, &info, arg4));
+            if (!is_error(ret) && arg3 && info.si_pid != 0) {
+                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
+                    goto efault;
+                host_to_target_siginfo(p, &info);
+                unlock_user(p, arg3, sizeof(target_siginfo_t));
+            }
+        }
+        break;
+#endif
 #ifdef TARGET_NR_creat /* not on alpha */
     case TARGET_NR_creat:
         if (!(p = lock_user_string(arg1)))
@@ -3173,6 +3234,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             goto efault;
         ret = get_errno(sys_unlinkat(arg1, p, arg3));
         unlock_user(p, arg2, 0);
+        break;
 #endif
     case TARGET_NR_execve:
         {
@@ -3186,7 +3248,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
             argc = 0;
             guest_argp = arg2;
-            for (gp = guest_argp; ; gp++) {
+            for (gp = guest_argp; ; gp += sizeof(abi_ulong)) {
                 if (get_user_ual(addr, gp))
                     goto efault;
                 if (!addr)
@@ -3195,7 +3257,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             }
             envc = 0;
             guest_envp = arg3;
-            for (gp = guest_envp; ; gp++) {
+            for (gp = guest_envp; ; gp += sizeof(abi_ulong)) {
                 if (get_user_ual(addr, gp))
                     goto efault;
                 if (!addr)
@@ -3391,9 +3453,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         {
             struct timeval *tvp, tv[2];
             if (arg2) {
-                target_to_host_timeval(&tv[0], arg2);
-                target_to_host_timeval(&tv[1],
-                    arg2 + sizeof (struct target_timeval));
+                if (copy_from_user_timeval(&tv[0], arg2)
+                    || copy_from_user_timeval(&tv[1],
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
                 tvp = tv;
             } else {
                 tvp = NULL;
@@ -3440,7 +3503,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = 0;
         break;
     case TARGET_NR_kill:
-        ret = get_errno(kill(arg1, arg2));
+        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
         break;
     case TARGET_NR_rename:
         {
@@ -3500,7 +3563,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             if (!is_error(ret)) {
 #if defined(TARGET_MIPS)
                 CPUMIPSState *env = (CPUMIPSState*)cpu_env;
-               env->gpr[3][env->current_tc] = host_pipe[1];
+               env->gpr[env->current_tc][3] = host_pipe[1];
+               ret = host_pipe[0];
+#elif defined(TARGET_SH4)
+               ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
                ret = host_pipe[0];
 #else
                 if (put_user_s32(host_pipe[0], arg1)
@@ -3932,14 +3998,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             struct timeval tv;
             ret = get_errno(gettimeofday(&tv, NULL));
             if (!is_error(ret)) {
-                host_to_target_timeval(arg1, &tv);
+                if (copy_to_user_timeval(arg1, &tv))
+                    goto efault;
             }
         }
         break;
     case TARGET_NR_settimeofday:
         {
             struct timeval tv;
-            target_to_host_timeval(&tv, arg1);
+            if (copy_from_user_timeval(&tv, arg1))
+                goto efault;
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
@@ -4069,10 +4137,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_mmap2
     case TARGET_NR_mmap2:
-#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
+#ifndef MMAP_SHIFT
 #define MMAP_SHIFT 12
-#else
-#define MMAP_SHIFT TARGET_PAGE_BITS
 #endif
         ret = get_errno(target_mmap(arg1, arg2, arg3,
                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
@@ -4314,19 +4380,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
             if (arg2) {
                 pvalue = &value;
-                target_to_host_timeval(&pvalue->it_interval,
-                                       arg2);
-                target_to_host_timeval(&pvalue->it_value,
-                                       arg2 + sizeof(struct target_timeval));
+                if (copy_from_user_timeval(&pvalue->it_interval, arg2)
+                    || copy_from_user_timeval(&pvalue->it_value,
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
             } else {
                 pvalue = NULL;
             }
             ret = get_errno(setitimer(arg1, pvalue, &ovalue));
             if (!is_error(ret) && arg3) {
-                host_to_target_timeval(arg3,
-                                       &ovalue.it_interval);
-                host_to_target_timeval(arg3 + sizeof(struct target_timeval),
-                                       &ovalue.it_value);
+                if (copy_to_user_timeval(arg3,
+                                         &ovalue.it_interval)
+                    || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
+                                            &ovalue.it_value))
+                    goto efault;
             }
         }
         break;
@@ -4336,10 +4403,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
             ret = get_errno(getitimer(arg1, &value));
             if (!is_error(ret) && arg2) {
-                host_to_target_timeval(arg2,
-                                       &value.it_interval);
-                host_to_target_timeval(arg2 + sizeof(struct target_timeval),
-                                       &value.it_value);
+                if (copy_to_user_timeval(arg2,
+                                         &value.it_interval)
+                    || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
+                                            &value.it_value))
+                    goto efault;
             }
         }
         break;
@@ -4712,7 +4780,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             struct iovec *vec;
 
             vec = alloca(count * sizeof(struct iovec));
-            lock_iovec(VERIFY_WRITE, vec, arg2, count, 0);
+            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
+                goto efault;
             ret = get_errno(readv(arg1, vec, count));
             unlock_iovec(vec, arg2, count, 1);
         }
@@ -4723,7 +4792,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             struct iovec *vec;
 
             vec = alloca(count * sizeof(struct iovec));
-            lock_iovec(VERIFY_READ, vec, arg2, count, 1);
+            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+                goto efault;
             ret = get_errno(writev(arg1, vec, count));
             unlock_iovec(vec, arg2, count, 0);
         }
@@ -4855,6 +4925,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(pwrite(arg1, p, arg3, arg4));
         unlock_user(p, arg2, 0);
         break;
+#endif
+#ifdef TARGET_NR_pread64
+    case TARGET_NR_pread64:
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_NR_pwrite64:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
+        unlock_user(p, arg2, 0);
+        break;
 #endif
     case TARGET_NR_getcwd:
         if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
@@ -5494,6 +5578,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
     }
 #endif
+#ifdef TARGET_NR_clock_nanosleep
+    case TARGET_NR_clock_nanosleep:
+    {
+        struct timespec ts;
+        target_to_host_timespec(&ts, arg3);
+        ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
+        if (arg4)
+            host_to_target_timespec(arg4, &ts);
+        break;
+    }
+#endif
 
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
     case TARGET_NR_set_tid_address:
@@ -5503,13 +5598,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
 #if defined(TARGET_NR_tkill) && defined(__NR_tkill)
     case TARGET_NR_tkill:
-        ret = get_errno(sys_tkill((int)arg1, (int)arg2));
+        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
         break;
 #endif
 
 #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
     case TARGET_NR_tgkill:
-       ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3));
+       ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
+                        target_to_host_signal(arg3)));
        break;
 #endif
 
@@ -5537,6 +5633,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         }
        break;
 #endif
+#if defined(USE_NPTL)
+    case TARGET_NR_futex:
+        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+#endif
 
     default:
     unimplemented:
This page took 0.046543 seconds and 4 git commands to generate.