Merge commit 'gnu/master' into test
[qemu] / linux-user / syscall.c
index 59c91f8..2087226 100644 (file)
@@ -77,6 +77,7 @@
 #include <linux/soundcard.h>
 #include <linux/kd.h>
 #include <linux/mtio.h>
+#include <linux/fs.h>
 #include "linux_loop.h"
 
 #include "qemu.h"
 
 //#define DEBUG
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
-    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
-/* 16 bit uid wrappers emulation */
-#define USE_UID16
-#endif
-
 //#include <linux/msdos_fs.h>
 #define        VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct linux_dirent [2])
 #define        VFAT_IOCTL_READDIR_SHORT        _IOR('r', 2, struct linux_dirent [2])
@@ -412,13 +407,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
   return (unlinkat(dirfd, pathname, flags));
 }
 #endif
-#ifdef TARGET_NR_utimensat
-static int sys_utimensat(int dirfd, const char *pathname,
-    const struct timespec times[2], int flags)
-{
-  return (utimensat(dirfd, pathname, times, flags));
-}
-#endif
 #else /* !CONFIG_ATFILE */
 
 /*
@@ -459,6 +447,11 @@ _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
 _syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
           mode_t,mode,dev_t,dev)
 #endif
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+        defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
 #if defined(TARGET_NR_openat) && defined(__NR_openat)
 _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
 #endif
@@ -477,12 +470,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 #endif
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_UTIMENSAT
+static int sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
+{
+    if (pathname == NULL)
+        return futimens(dirfd, times);
+    else
+        return utimensat(dirfd, pathname, times, flags);
+}
+#else
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
           const struct timespec *,tsp,int,flags)
 #endif
-
-#endif /* CONFIG_ATFILE */
+#endif /* CONFIG_UTIMENSAT  */
 
 #ifdef CONFIG_INOTIFY
 #include <sys/inotify.h>
@@ -944,6 +949,55 @@ static abi_long do_select(int n,
     return ret;
 }
 
+static abi_long do_pipe2(int host_pipe[], int flags)
+{
+#ifdef CONFIG_PIPE2
+    return pipe2(host_pipe, flags);
+#else
+    return -ENOSYS;
+#endif
+}
+
+static abi_long do_pipe(void *cpu_env, int pipedes, int flags)
+{
+    int host_pipe[2];
+    abi_long ret;
+    ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
+
+    if (is_error(ret))
+        return get_errno(ret);
+#if defined(TARGET_MIPS)
+    ((CPUMIPSState*)cpu_env)->active_tc.gpr[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], pipedes)
+        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
+        return -TARGET_EFAULT;
+#endif
+    return get_errno(ret);
+}
+
+static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
+                                              abi_ulong target_addr,
+                                              socklen_t len)
+{
+    struct target_ip_mreqn *target_smreqn;
+
+    target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (!target_smreqn)
+        return -TARGET_EFAULT;
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn))
+        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
 static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                                abi_ulong target_addr,
                                                socklen_t len)
@@ -1119,6 +1173,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
 {
     abi_long ret;
     int val;
+    struct ip_mreqn *ip_mreq;
+    struct ip_mreq_source *ip_mreq_source;
 
     switch(level) {
     case SOL_TCP:
@@ -1157,6 +1213,29 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
             }
             ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
             break;
+        case IP_ADD_MEMBERSHIP:
+        case IP_DROP_MEMBERSHIP:
+            if (optlen < sizeof (struct target_ip_mreq) ||
+                optlen > sizeof (struct target_ip_mreqn))
+                return -TARGET_EINVAL;
+
+            ip_mreq = (struct ip_mreqn *) alloca(optlen);
+            target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
+            break;
+
+        case IP_BLOCK_SOURCE:
+        case IP_UNBLOCK_SOURCE:
+        case IP_ADD_SOURCE_MEMBERSHIP:
+        case IP_DROP_SOURCE_MEMBERSHIP:
+            if (optlen != sizeof (struct target_ip_mreq_source))
+                return -TARGET_EINVAL;
+
+            ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
+            unlock_user (ip_mreq_source, optval_addr, 0);
+            break;
+
         default:
             goto unimplemented;
         }
@@ -1513,6 +1592,9 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
     void *addr;
     abi_long ret;
 
+    if (target_addr == 0)
+       return get_errno(accept(fd, NULL, NULL));
+
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
@@ -1924,14 +2006,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
 }
 #endif
 
-#ifdef TARGET_NR_ipc
 #define N_SHM_REGIONS  32
 
 static struct shm_region {
     abi_ulong  start;
     abi_ulong  size;
 } shm_regions[N_SHM_REGIONS];
-#endif
 
 struct target_ipc_perm
 {
@@ -2424,6 +2504,224 @@ end:
     return ret;
 }
 
+struct target_shmid_ds
+{
+    struct target_ipc_perm shm_perm;
+    abi_ulong shm_segsz;
+    abi_ulong shm_atime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong shm_dtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong shm_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    int shm_cpid;
+    int shm_lpid;
+    abi_ulong shm_nattch;
+    unsigned long int __unused4;
+    unsigned long int __unused5;
+};
+
+static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                               abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
+        return -TARGET_EFAULT;
+    __put_user(target_sd->shm_segsz, &host_sd->shm_segsz);
+    __put_user(target_sd->shm_atime, &host_sd->shm_atime);
+    __put_user(target_sd->shm_dtime, &host_sd->shm_dtime);
+    __put_user(target_sd->shm_ctime, &host_sd->shm_ctime);
+    __put_user(target_sd->shm_cpid, &host_sd->shm_cpid);
+    __put_user(target_sd->shm_lpid, &host_sd->shm_lpid);
+    __put_user(target_sd->shm_nattch, &host_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                               struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
+        return -TARGET_EFAULT;
+    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct  target_shminfo {
+    abi_ulong shmmax;
+    abi_ulong shmmin;
+    abi_ulong shmmni;
+    abi_ulong shmseg;
+    abi_ulong shmall;
+};
+
+static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
+                                              struct shminfo *host_shminfo)
+{
+    struct target_shminfo *target_shminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+    unlock_user_struct(target_shminfo, target_addr, 1);
+    return 0;
+}
+
+struct target_shm_info {
+    int used_ids;
+    abi_ulong shm_tot;
+    abi_ulong shm_rss;
+    abi_ulong shm_swp;
+    abi_ulong swap_attempts;
+    abi_ulong swap_successes;
+};
+
+static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
+                                               struct shm_info *host_shm_info)
+{
+    struct target_shm_info *target_shm_info;
+    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
+    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
+    unlock_user_struct(target_shm_info, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
+{
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch(cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SHM_STAT:
+        if (target_to_host_shmid_ds(&dsarg, buf))
+            return -TARGET_EFAULT;
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buf, &dsarg))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (host_to_target_shminfo(buf, &shminfo))
+            return -TARGET_EFAULT;
+        break;
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (host_to_target_shm_info(buf, &shm_info))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+    }
+
+    return ret;
+}
+
+static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_long raddr;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i,ret;
+
+    /* find out the length of the shared memory segment */
+    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
+    if (is_error(ret)) {
+        /* can't get length, bail out */
+        return ret;
+    }
+
+    mmap_lock();
+
+    if (shmaddr)
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+    else {
+        abi_ulong mmap_start;
+
+        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            host_raddr = (void *)-1;
+        } else
+            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
+    }
+
+    if (host_raddr == (void *)-1) {
+        mmap_unlock();
+        return get_errno((long)host_raddr);
+    }
+    raddr=h2g((unsigned long)host_raddr);
+
+    page_set_flags(raddr, raddr + shm_info.shm_segsz,
+                   PAGE_VALID | PAGE_READ |
+                   ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
+
+    for (i = 0; i < N_SHM_REGIONS; i++) {
+        if (shm_regions[i].start == 0) {
+            shm_regions[i].start = raddr;
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+
+}
+
+static inline abi_long do_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].start == shmaddr) {
+            shm_regions[i].start = 0;
+            page_set_flags(shmaddr, shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
 #ifdef TARGET_NR_ipc
 /* ??? This only works with linear mappings.  */
 /* do_ipc() must return target values and target errnos. */
@@ -2433,8 +2731,6 @@ static abi_long do_ipc(unsigned int call, int first,
 {
     int version;
     abi_long ret = 0;
-    struct shmid_ds shm_info;
-    int i;
 
     version = call >> 16;
     call &= 0xffff;
@@ -2489,48 +2785,24 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_shmat:
+        switch (version) {
+        default:
         {
             abi_ulong raddr;
-            void *host_addr;
-            /* SHM_* flags are the same on all linux platforms */
-            host_addr = shmat(first, (void *)g2h(ptr), second);
-            if (host_addr == (void *)-1) {
-                ret = get_errno((long)host_addr);
-                break;
-            }
-            raddr = h2g((unsigned long)host_addr);
-            /* find out the length of the shared memory segment */
-            
-            ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
-            if (is_error(ret)) {
-                /* can't get length, bail out */
-                shmdt(host_addr);
-                break;
-            }
-            page_set_flags(raddr, raddr + shm_info.shm_segsz,
-                           PAGE_VALID | PAGE_READ |
-                           ((second & SHM_RDONLY)? 0: PAGE_WRITE));
-            for (i = 0; i < N_SHM_REGIONS; ++i) {
-                if (shm_regions[i].start == 0) {
-                    shm_regions[i].start = raddr;
-                    shm_regions[i].size = shm_info.shm_segsz;
-                    break;
-                }
-            }
+            raddr = do_shmat(first, ptr, second);
+            if (is_error(raddr))
+                return get_errno(raddr);
             if (put_user_ual(raddr, third))
                 return -TARGET_EFAULT;
-            ret = 0;
+            break;
+        }
+        case 1:
+            ret = -TARGET_EINVAL;
+            break;
         }
        break;
     case IPCOP_shmdt:
-       for (i = 0; i < N_SHM_REGIONS; ++i) {
-           if (shm_regions[i].start == ptr) {
-               shm_regions[i].start = 0;
-               page_set_flags(ptr, shm_regions[i].size, 0);
-               break;
-           }
-       }
-       ret = get_errno(shmdt((void *)g2h(ptr)));
+        ret = do_shmdt(ptr);
        break;
 
     case IPCOP_shmget:
@@ -2540,18 +2812,9 @@ static abi_long do_ipc(unsigned int call, int first,
 
        /* IPC_* and SHM_* command values are the same on all linux platforms */
     case IPCOP_shmctl:
-        switch(second) {
-        case IPC_RMID:
-        case SHM_LOCK:
-        case SHM_UNLOCK:
-            ret = get_errno(shmctl(first, second, NULL));
-            break;
-        default:
-            goto unimplemented;
-        }
+        ret = do_shmctl(first, second, third);
         break;
     default:
-    unimplemented:
        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
        ret = -TARGET_ENOSYS;
        break;
@@ -2797,6 +3060,7 @@ static void target_to_host_termios (void *dst, const void *src)
         target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
     host->c_line = target->c_line;
 
+    memset(host->c_cc, 0, sizeof(host->c_cc));
     host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
     host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
     host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
@@ -2831,6 +3095,7 @@ static void host_to_target_termios (void *dst, const void *src)
         tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
     target->c_line = host->c_line;
 
+    memset(target->c_cc, 0, sizeof(target->c_cc));
     target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
     target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
     target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
@@ -3189,6 +3454,7 @@ typedef struct {
     pthread_cond_t cond;
     pthread_t thread;
     uint32_t tid;
+    unsigned int flags;
     abi_ulong child_tidptr;
     abi_ulong parent_tidptr;
     sigset_t sigmask;
@@ -3198,9 +3464,12 @@ static void *clone_func(void *arg)
 {
     new_thread_info *info = arg;
     CPUState *env;
+    TaskState *ts;
 
     env = info->env;
     thread_env = env;
+    ts = (TaskState *)thread_env->opaque;
+    task_settid(ts);
     info->tid = gettid();
     env->host_tid = info->tid;
     if (info->child_tidptr)
@@ -3254,6 +3523,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         flags &= ~(CLONE_VFORK | CLONE_VM);
 
     if (flags & CLONE_VM) {
+        TaskState *parent_ts = (TaskState *)env->opaque;
 #if defined(USE_NPTL)
         new_thread_info info;
         pthread_attr_t attr;
@@ -3266,6 +3536,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         /* Init regs that differ from the parent.  */
         cpu_clone_regs(new_env, newsp);
         new_env->opaque = ts;
+        ts->bprm = parent_ts->bprm;
+        ts->info = parent_ts->info;
 #if defined(USE_NPTL)
         nptl_flags = flags;
         flags &= ~CLONE_NPTL_FLAGS2;
@@ -3377,7 +3649,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl.l_len = tswapl(target_fl->l_len);
         fl.l_pid = tswapl(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
-        ret = get_errno(fcntl(fd, cmd, &fl));
+        ret = get_errno(fcntl(fd, F_GETLK, &fl));
         if (ret == 0) {
             if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                 return -TARGET_EFAULT;
@@ -3400,7 +3672,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl.l_len = tswapl(target_fl->l_len);
         fl.l_pid = tswapl(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
-        ret = get_errno(fcntl(fd, cmd, &fl));
+        ret = get_errno(fcntl(fd, F_SETLK+(cmd-TARGET_F_SETLK), &fl));
         break;
 
     case TARGET_F_GETLK64:
@@ -3412,7 +3684,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl64.l_len = tswapl(target_fl64->l_len);
         fl64.l_pid = tswap16(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
-        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
+        ret = get_errno(fcntl(fd, F_GETLK64, &fl64));
         if (ret == 0) {
             if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                 return -TARGET_EFAULT;
@@ -3434,7 +3706,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl64.l_len = tswapl(target_fl64->l_len);
         fl64.l_pid = tswap16(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
-        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
+        ret = get_errno(fcntl(fd, F_SETLK64+(cmd-TARGET_F_SETLK64), &fl64));
         break;
 
     case F_GETFL:
@@ -3694,7 +3966,11 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
 
     /* ??? We assume FUTEX_* constants are the same on both host
        and target.  */
+#ifdef FUTEX_CMD_MASK
+    switch ((op&FUTEX_CMD_MASK)) {
+#else
     switch (op) {
+#endif
     case FUTEX_WAIT:
         if (timeout) {
             pts = &ts;
@@ -3702,17 +3978,19 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
         } else {
             pts = NULL;
         }
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
+        return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
                          pts, NULL, 0));
     case FUTEX_WAKE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+    case FUTEX_WAKE_OP:
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), val3 ));
     case FUTEX_FD:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
     case FUTEX_REQUEUE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
+        return get_errno(sys_futex(g2h(uaddr), op, val,
                          NULL, g2h(uaddr2), 0));
     case FUTEX_CMP_REQUEUE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
+        return get_errno(sys_futex(g2h(uaddr), op, val,
                          NULL, g2h(uaddr2), tswap32(val3)));
     default:
         return -TARGET_ENOSYS;
@@ -4291,25 +4569,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(dup(arg1));
         break;
     case TARGET_NR_pipe:
-        {
-            int host_pipe[2];
-            ret = get_errno(pipe(host_pipe));
-            if (!is_error(ret)) {
-#if defined(TARGET_MIPS)
-                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
-               env->active_tc.gpr[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)
-                    || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0])))
-                    goto efault;
-#endif
-            }
-        }
+        ret = do_pipe(cpu_env, arg1, 0);
+        break;
+#ifdef TARGET_NR_pipe2
+    case TARGET_NR_pipe2:
+        ret = do_pipe(cpu_env, arg1, arg2);
         break;
+#endif
     case TARGET_NR_times:
         {
             struct target_tms *tmsp;
@@ -5312,6 +5578,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_msgsnd(arg1, arg2, arg3, arg4);
         break;
 #endif
+#ifdef TARGET_NR_shmget
+    case TARGET_NR_shmget:
+        ret = get_errno(shmget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_shmctl
+    case TARGET_NR_shmctl:
+        ret = do_shmctl(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmat
+    case TARGET_NR_shmat:
+        ret = do_shmat(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmdt
+    case TARGET_NR_shmdt:
+        ret = do_shmdt(arg1);
+        break;
+#endif
     case TARGET_NR_fsync:
         ret = get_errno(fsync(arg1));
         break;
@@ -6317,7 +6603,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = get_errno(fcntl(arg1, cmd, &fl));
            break;
         default:
-            ret = do_fcntl(arg1, cmd, arg3);
+            ret = do_fcntl(arg1, arg2, arg3);
             break;
         }
        break;
@@ -6371,7 +6657,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
-        goto unimplemented_nowarn;
+        ret = -TARGET_EOPNOTSUPP;
+        break;
 #endif
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
@@ -6468,17 +6755,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
     case TARGET_NR_utimensat:
         {
-            struct timespec ts[2];
-            target_to_host_timespec(ts, arg3);
-            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+            struct timespec *tsp, ts[2];
+            if (!arg3) {
+                tsp = NULL;
+            } else {
+                target_to_host_timespec(ts, arg3);
+                target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+                tsp = ts;
+            }
             if (!arg2)
-                ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
             else {
                 if (!(p = lock_user_string(arg2))) {
                     ret = -TARGET_EFAULT;
                     goto fail;
                 }
-                ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
                 unlock_user(p, arg2, 0);
             }
         }