diff mbox series

[v3,17/19] linux-user: Split out ipc syscalls

Message ID 20180612005145.3375-18-richard.henderson@linaro.org
State New
Headers show
Series linux-user: Split do_syscall | expand

Commit Message

Richard Henderson June 12, 2018, 12:51 a.m. UTC
Given that these are all intertwined via TARGET_NR_ipc,
we must move them all to the new file all at once.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 linux-user/strace.c            |   83 ---
 linux-user/syscall.c           |  973 ----------------------------
 linux-user/syscall_ipc.c       | 1095 ++++++++++++++++++++++++++++++++
 linux-user/Makefile.objs       |    4 +-
 linux-user/gen_syscall_list.py |   12 +
 linux-user/strace.list         |   42 --
 6 files changed, 1110 insertions(+), 1099 deletions(-)
 create mode 100644 linux-user/syscall_ipc.c

-- 
2.17.1
diff mbox series

Patch

diff --git a/linux-user/strace.c b/linux-user/strace.c
index 4240ea649a..79d2d91636 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1,8 +1,4 @@ 
 #include "qemu/osdep.h"
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
 #include <sys/select.h>
 #include <sys/mount.h>
 #include <arpa/inet.h>
@@ -74,54 +70,6 @@  UNUSED static void print_socket_protocol(int domain, int type, int protocol);
 /*
  * Utility functions
  */
-static void
-print_ipc_cmd(int cmd)
-{
-#define output_cmd(val) \
-if( cmd == val ) { \
-    gemu_log(#val); \
-    return; \
-}
-
-    cmd &= 0xff;
-
-    /* General IPC commands */
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_SET );
-    output_cmd( IPC_STAT );
-    output_cmd( IPC_INFO );
-    /* msgctl() commands */
-    output_cmd( MSG_STAT );
-    output_cmd( MSG_INFO );
-    /* shmctl() commands */
-    output_cmd( SHM_LOCK );
-    output_cmd( SHM_UNLOCK );
-    output_cmd( SHM_STAT );
-    output_cmd( SHM_INFO );
-    /* semctl() commands */
-    output_cmd( GETPID );
-    output_cmd( GETVAL );
-    output_cmd( GETALL );
-    output_cmd( GETNCNT );
-    output_cmd( GETZCNT );
-    output_cmd( SETVAL );
-    output_cmd( SETALL );
-    output_cmd( SEM_STAT );
-    output_cmd( SEM_INFO );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-
-    /* Some value we don't recognize */
-    gemu_log("%d",cmd);
-}
-
 static void
 print_signal(abi_ulong arg, int last)
 {
@@ -620,18 +568,6 @@  print_newselect(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_semctl
-static void
-print_semctl(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2);
-    print_ipc_cmd(arg3);
-    gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
-}
-#endif
-
 static void
 print_execve(const struct syscallname *name,
              abi_long arg1, abi_long arg2, abi_long arg3,
@@ -664,25 +600,6 @@  print_execve(const struct syscallname *name,
     gemu_log("NULL})");
 }
 
-#ifdef TARGET_NR_ipc
-static void
-print_ipc(const struct syscallname *name,
-          abi_long arg1, abi_long arg2, abi_long arg3,
-          abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    switch(arg1) {
-    case IPCOP_semctl:
-        gemu_log("semctl(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", arg1, arg2);
-        print_ipc_cmd(arg3);
-        gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
-        break;
-    default:
-        gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")",
-                 name->name, arg1, arg2, arg3, arg4);
-    }
-}
-#endif
-
 /*
  * Variants for the return value output function
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8c7dd3049e..51d27f2a88 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -23,8 +23,6 @@ 
 #include <elf.h>
 #include <endian.h>
 #include <grp.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/file.h>
@@ -41,8 +39,6 @@ 
 #include <sys/uio.h>
 #include <poll.h>
 #include <sys/times.h>
-#include <sys/shm.h>
-#include <sys/sem.h>
 #include <sys/statfs.h>
 #include <utime.h>
 #include <sys/sysinfo.h>
@@ -843,43 +839,6 @@  safe_syscall2(int, nanosleep, const struct timespec *, req,
 safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
               const struct timespec *, req, struct timespec *, rem)
 #endif
-#ifdef __NR_msgsnd
-safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
-              int, flags)
-safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
-              long, msgtype, int, flags)
-safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
-              unsigned, nsops, const struct timespec *, timeout)
-#else
-/* This host kernel architecture uses a single ipc syscall; fake up
- * wrappers for the sub-operations to hide this implementation detail.
- * Annoyingly we can't include linux/ipc.h to get the constant definitions
- * for the call parameter because some structs in there conflict with the
- * sys/ipc.h ones. So we just define them here, and rely on them being
- * the same for all host architectures.
- */
-#define Q_SEMTIMEDOP 4
-#define Q_MSGSND 11
-#define Q_MSGRCV 12
-#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
-
-safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
-              void *, ptr, long, fifth)
-static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
-{
-    return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
-}
-static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
-{
-    return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
-}
-static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
-                           const struct timespec *timeout)
-{
-    return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
-                    (long)timeout);
-}
-#endif
 #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
 safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
               size_t, len, unsigned, prio, const struct timespec *, timeout)
@@ -4083,890 +4042,6 @@  static abi_long do_socketcall(int num, abi_ulong vptr)
 }
 #endif
 
-#define N_SHM_REGIONS	32
-
-static struct shm_region {
-    abi_ulong start;
-    abi_ulong size;
-    bool in_use;
-} shm_regions[N_SHM_REGIONS];
-
-#ifndef TARGET_SEMID64_DS
-/* asm-generic version of this struct */
-struct target_semid64_ds
-{
-  struct target_ipc_perm sem_perm;
-  abi_ulong sem_otime;
-#if TARGET_ABI_BITS == 32
-  abi_ulong __unused1;
-#endif
-  abi_ulong sem_ctime;
-#if TARGET_ABI_BITS == 32
-  abi_ulong __unused2;
-#endif
-  abi_ulong sem_nsems;
-  abi_ulong __unused3;
-  abi_ulong __unused4;
-};
-#endif
-
-static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
-                                               abi_ulong target_addr)
-{
-    struct target_ipc_perm *target_ip;
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
-        return -TARGET_EFAULT;
-    target_ip = &(target_sd->sem_perm);
-    host_ip->__key = tswap32(target_ip->__key);
-    host_ip->uid = tswap32(target_ip->uid);
-    host_ip->gid = tswap32(target_ip->gid);
-    host_ip->cuid = tswap32(target_ip->cuid);
-    host_ip->cgid = tswap32(target_ip->cgid);
-#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
-    host_ip->mode = tswap32(target_ip->mode);
-#else
-    host_ip->mode = tswap16(target_ip->mode);
-#endif
-#if defined(TARGET_PPC)
-    host_ip->__seq = tswap32(target_ip->__seq);
-#else
-    host_ip->__seq = tswap16(target_ip->__seq);
-#endif
-    unlock_user_struct(target_sd, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
-                                               struct ipc_perm *host_ip)
-{
-    struct target_ipc_perm *target_ip;
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
-        return -TARGET_EFAULT;
-    target_ip = &(target_sd->sem_perm);
-    target_ip->__key = tswap32(host_ip->__key);
-    target_ip->uid = tswap32(host_ip->uid);
-    target_ip->gid = tswap32(host_ip->gid);
-    target_ip->cuid = tswap32(host_ip->cuid);
-    target_ip->cgid = tswap32(host_ip->cgid);
-#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
-    target_ip->mode = tswap32(host_ip->mode);
-#else
-    target_ip->mode = tswap16(host_ip->mode);
-#endif
-#if defined(TARGET_PPC)
-    target_ip->__seq = tswap32(host_ip->__seq);
-#else
-    target_ip->__seq = tswap16(host_ip->__seq);
-#endif
-    unlock_user_struct(target_sd, target_addr, 1);
-    return 0;
-}
-
-static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
-                                               abi_ulong target_addr)
-{
-    struct target_semid64_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->sem_perm),target_addr))
-        return -TARGET_EFAULT;
-    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
-    host_sd->sem_otime = tswapal(target_sd->sem_otime);
-    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
-    unlock_user_struct(target_sd, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
-                                               struct semid_ds *host_sd)
-{
-    struct target_semid64_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->sem_perm)))
-        return -TARGET_EFAULT;
-    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
-    target_sd->sem_otime = tswapal(host_sd->sem_otime);
-    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
-    unlock_user_struct(target_sd, target_addr, 1);
-    return 0;
-}
-
-struct target_seminfo {
-    int semmap;
-    int semmni;
-    int semmns;
-    int semmnu;
-    int semmsl;
-    int semopm;
-    int semume;
-    int semusz;
-    int semvmx;
-    int semaem;
-};
-
-static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
-                                              struct seminfo *host_seminfo)
-{
-    struct target_seminfo *target_seminfo;
-    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
-    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
-    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
-    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
-    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
-    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
-    __put_user(host_seminfo->semume, &target_seminfo->semume);
-    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
-    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
-    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
-    unlock_user_struct(target_seminfo, target_addr, 1);
-    return 0;
-}
-
-union semun {
-	int val;
-	struct semid_ds *buf;
-	unsigned short *array;
-	struct seminfo *__buf;
-};
-
-union target_semun {
-	int val;
-	abi_ulong buf;
-	abi_ulong array;
-	abi_ulong __buf;
-};
-
-static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
-                                               abi_ulong target_addr)
-{
-    int nsems;
-    unsigned short *array;
-    union semun semun;
-    struct semid_ds semid_ds;
-    int i, ret;
-
-    semun.buf = &semid_ds;
-
-    ret = semctl(semid, 0, IPC_STAT, semun);
-    if (ret == -1)
-        return get_errno(ret);
-
-    nsems = semid_ds.sem_nsems;
-
-    *host_array = g_try_new(unsigned short, nsems);
-    if (!*host_array) {
-        return -TARGET_ENOMEM;
-    }
-    array = lock_user(VERIFY_READ, target_addr,
-                      nsems*sizeof(unsigned short), 1);
-    if (!array) {
-        g_free(*host_array);
-        return -TARGET_EFAULT;
-    }
-
-    for(i=0; i<nsems; i++) {
-        __get_user((*host_array)[i], &array[i]);
-    }
-    unlock_user(array, target_addr, 0);
-
-    return 0;
-}
-
-static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
-                                               unsigned short **host_array)
-{
-    int nsems;
-    unsigned short *array;
-    union semun semun;
-    struct semid_ds semid_ds;
-    int i, ret;
-
-    semun.buf = &semid_ds;
-
-    ret = semctl(semid, 0, IPC_STAT, semun);
-    if (ret == -1)
-        return get_errno(ret);
-
-    nsems = semid_ds.sem_nsems;
-
-    array = lock_user(VERIFY_WRITE, target_addr,
-                      nsems*sizeof(unsigned short), 0);
-    if (!array)
-        return -TARGET_EFAULT;
-
-    for(i=0; i<nsems; i++) {
-        __put_user((*host_array)[i], &array[i]);
-    }
-    g_free(*host_array);
-    unlock_user(array, target_addr, 1);
-
-    return 0;
-}
-
-static inline abi_long do_semctl(int semid, int semnum, int cmd,
-                                 abi_ulong target_arg)
-{
-    union target_semun target_su = { .buf = target_arg };
-    union semun arg;
-    struct semid_ds dsarg;
-    unsigned short *array = NULL;
-    struct seminfo seminfo;
-    abi_long ret = -TARGET_EINVAL;
-    abi_long err;
-    cmd &= 0xff;
-
-    switch( cmd ) {
-	case GETVAL:
-	case SETVAL:
-            /* 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));
-            break;
-	case GETALL:
-	case SETALL:
-            err = target_to_host_semarray(semid, &array, target_su.array);
-            if (err)
-                return err;
-            arg.array = array;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_semarray(semid, target_su.array, &array);
-            if (err)
-                return err;
-            break;
-	case IPC_STAT:
-	case IPC_SET:
-	case SEM_STAT:
-            err = target_to_host_semid_ds(&dsarg, target_su.buf);
-            if (err)
-                return err;
-            arg.buf = &dsarg;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_semid_ds(target_su.buf, &dsarg);
-            if (err)
-                return err;
-            break;
-	case IPC_INFO:
-	case SEM_INFO:
-            arg.__buf = &seminfo;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_seminfo(target_su.__buf, &seminfo);
-            if (err)
-                return err;
-            break;
-	case IPC_RMID:
-	case GETPID:
-	case GETNCNT:
-	case GETZCNT:
-            ret = get_errno(semctl(semid, semnum, cmd, NULL));
-            break;
-    }
-
-    return ret;
-}
-
-struct target_sembuf {
-    unsigned short sem_num;
-    short sem_op;
-    short sem_flg;
-};
-
-static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
-                                             abi_ulong target_addr,
-                                             unsigned nsops)
-{
-    struct target_sembuf *target_sembuf;
-    int i;
-
-    target_sembuf = lock_user(VERIFY_READ, target_addr,
-                              nsops*sizeof(struct target_sembuf), 1);
-    if (!target_sembuf)
-        return -TARGET_EFAULT;
-
-    for(i=0; i<nsops; i++) {
-        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
-        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
-        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
-    }
-
-    unlock_user(target_sembuf, target_addr, 0);
-
-    return 0;
-}
-
-static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
-{
-    struct sembuf sops[nsops];
-
-    if (target_to_host_sembuf(sops, ptr, nsops))
-        return -TARGET_EFAULT;
-
-    return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
-}
-
-struct target_msqid_ds
-{
-    struct target_ipc_perm msg_perm;
-    abi_ulong msg_stime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused1;
-#endif
-    abi_ulong msg_rtime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused2;
-#endif
-    abi_ulong msg_ctime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused3;
-#endif
-    abi_ulong __msg_cbytes;
-    abi_ulong msg_qnum;
-    abi_ulong msg_qbytes;
-    abi_ulong msg_lspid;
-    abi_ulong msg_lrpid;
-    abi_ulong __unused4;
-    abi_ulong __unused5;
-};
-
-static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
-                                               abi_ulong target_addr)
-{
-    struct target_msqid_ds *target_md;
-
-    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
-        return -TARGET_EFAULT;
-    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
-        return -TARGET_EFAULT;
-    host_md->msg_stime = tswapal(target_md->msg_stime);
-    host_md->msg_rtime = tswapal(target_md->msg_rtime);
-    host_md->msg_ctime = tswapal(target_md->msg_ctime);
-    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
-    host_md->msg_qnum = tswapal(target_md->msg_qnum);
-    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
-    host_md->msg_lspid = tswapal(target_md->msg_lspid);
-    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
-    unlock_user_struct(target_md, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
-                                               struct msqid_ds *host_md)
-{
-    struct target_msqid_ds *target_md;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
-        return -TARGET_EFAULT;
-    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
-        return -TARGET_EFAULT;
-    target_md->msg_stime = tswapal(host_md->msg_stime);
-    target_md->msg_rtime = tswapal(host_md->msg_rtime);
-    target_md->msg_ctime = tswapal(host_md->msg_ctime);
-    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
-    target_md->msg_qnum = tswapal(host_md->msg_qnum);
-    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
-    target_md->msg_lspid = tswapal(host_md->msg_lspid);
-    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
-    unlock_user_struct(target_md, target_addr, 1);
-    return 0;
-}
-
-struct target_msginfo {
-    int msgpool;
-    int msgmap;
-    int msgmax;
-    int msgmnb;
-    int msgmni;
-    int msgssz;
-    int msgtql;
-    unsigned short int msgseg;
-};
-
-static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
-                                              struct msginfo *host_msginfo)
-{
-    struct target_msginfo *target_msginfo;
-    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
-    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
-    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
-    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
-    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
-    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
-    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
-    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
-    unlock_user_struct(target_msginfo, target_addr, 1);
-    return 0;
-}
-
-static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
-{
-    struct msqid_ds dsarg;
-    struct msginfo msginfo;
-    abi_long ret = -TARGET_EINVAL;
-
-    cmd &= 0xff;
-
-    switch (cmd) {
-    case IPC_STAT:
-    case IPC_SET:
-    case MSG_STAT:
-        if (target_to_host_msqid_ds(&dsarg,ptr))
-            return -TARGET_EFAULT;
-        ret = get_errno(msgctl(msgid, cmd, &dsarg));
-        if (host_to_target_msqid_ds(ptr,&dsarg))
-            return -TARGET_EFAULT;
-        break;
-    case IPC_RMID:
-        ret = get_errno(msgctl(msgid, cmd, NULL));
-        break;
-    case IPC_INFO:
-    case MSG_INFO:
-        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
-        if (host_to_target_msginfo(ptr, &msginfo))
-            return -TARGET_EFAULT;
-        break;
-    }
-
-    return ret;
-}
-
-struct target_msgbuf {
-    abi_long mtype;
-    char	mtext[1];
-};
-
-static inline abi_long do_msgsnd(int msqid, abi_long msgp,
-                                 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 = g_try_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(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
-    g_free(host_mb);
-    unlock_user_struct(target_mb, msgp, 0);
-
-    return ret;
-}
-
-static inline abi_long do_msgrcv(int msqid, abi_long msgp,
-                                 ssize_t msgsz, abi_long msgtyp,
-                                 int msgflg)
-{
-    struct target_msgbuf *target_mb;
-    char *target_mtext;
-    struct msgbuf *host_mb;
-    abi_long ret = 0;
-
-    if (msgsz < 0) {
-        return -TARGET_EINVAL;
-    }
-
-    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
-        return -TARGET_EFAULT;
-
-    host_mb = g_try_malloc(msgsz + sizeof(long));
-    if (!host_mb) {
-        ret = -TARGET_ENOMEM;
-        goto end;
-    }
-    ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
-
-    if (ret > 0) {
-        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
-        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
-        if (!target_mtext) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        memcpy(target_mb->mtext, host_mb->mtext, ret);
-        unlock_user(target_mtext, target_mtext_addr, ret);
-    }
-
-    target_mb->mtype = tswapal(host_mb->mtype);
-
-end:
-    if (target_mb)
-        unlock_user_struct(target_mb, msgp, 1);
-    g_free(host_mb);
-    return ret;
-}
-
-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;
-    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
-    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
-    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
-    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
-    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
-    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
-    __get_user(host_sd->shm_nattch, &target_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;
-}
-
-#ifndef TARGET_FORCE_SHMLBA
-/* For most architectures, SHMLBA is the same as the page size;
- * some architectures have larger values, in which case they should
- * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
- * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
- * and defining its own value for SHMLBA.
- *
- * The kernel also permits SHMLBA to be set by the architecture to a
- * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
- * this means that addresses are rounded to the large size if
- * SHM_RND is set but addresses not aligned to that size are not rejected
- * as long as they are at least page-aligned. Since the only architecture
- * which uses this is ia64 this code doesn't provide for that oddity.
- */
-static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
-{
-    return TARGET_PAGE_SIZE;
-}
-#endif
-
-static inline abi_ulong do_shmat(CPUArchState *cpu_env,
-                                 int shmid, abi_ulong shmaddr, int shmflg)
-{
-    abi_long raddr;
-    void *host_raddr;
-    struct shmid_ds shm_info;
-    int i,ret;
-    abi_ulong shmlba;
-
-    /* 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;
-    }
-
-    shmlba = target_shmlba(cpu_env);
-
-    if (shmaddr & (shmlba - 1)) {
-        if (shmflg & SHM_RND) {
-            shmaddr &= ~(shmlba - 1);
-        } else {
-            return -TARGET_EINVAL;
-        }
-    }
-    if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
-        return -TARGET_EINVAL;
-    }
-
-    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].in_use) {
-            shm_regions[i].in_use = true;
-            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;
-    abi_long rv;
-
-    mmap_lock();
-
-    for (i = 0; i < N_SHM_REGIONS; ++i) {
-        if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
-            shm_regions[i].in_use = false;
-            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
-            break;
-        }
-    }
-    rv = get_errno(shmdt(g2h(shmaddr)));
-
-    mmap_unlock();
-
-    return rv;
-}
-
-#ifdef TARGET_NR_ipc
-/* ??? This only works with linear mappings.  */
-/* do_ipc() must return target values and target errnos. */
-static abi_long do_ipc(CPUArchState *cpu_env,
-                       unsigned int call, abi_long first,
-                       abi_long second, abi_long third,
-                       abi_long ptr, abi_long fifth)
-{
-    int version;
-    abi_long ret = 0;
-
-    version = call >> 16;
-    call &= 0xffff;
-
-    switch (call) {
-    case IPCOP_semop:
-        ret = do_semop(first, ptr, second);
-        break;
-
-    case IPCOP_semget:
-        ret = get_errno(semget(first, second, third));
-        break;
-
-    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, atptr);
-        break;
-    }
-
-    case IPCOP_msgget:
-        ret = get_errno(msgget(first, second));
-        break;
-
-    case IPCOP_msgsnd:
-        ret = do_msgsnd(first, ptr, second, third);
-        break;
-
-    case IPCOP_msgctl:
-        ret = do_msgctl(first, second, ptr);
-        break;
-
-    case IPCOP_msgrcv:
-        switch (version) {
-        case 0:
-            {
-                struct target_ipc_kludge {
-                    abi_long msgp;
-                    abi_long msgtyp;
-                } *tmp;
-
-                if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
-                    ret = -TARGET_EFAULT;
-                    break;
-                }
-
-                ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
-
-                unlock_user_struct(tmp, ptr, 0);
-                break;
-            }
-        default:
-            ret = do_msgrcv(first, ptr, second, fifth, third);
-        }
-        break;
-
-    case IPCOP_shmat:
-        switch (version) {
-        default:
-        {
-            abi_ulong raddr;
-            raddr = do_shmat(cpu_env, first, ptr, second);
-            if (is_error(raddr))
-                return get_errno(raddr);
-            if (put_user_ual(raddr, third))
-                return -TARGET_EFAULT;
-            break;
-        }
-        case 1:
-            ret = -TARGET_EINVAL;
-            break;
-        }
-	break;
-    case IPCOP_shmdt:
-        ret = do_shmdt(ptr);
-	break;
-
-    case IPCOP_shmget:
-	/* IPC_* flag values are the same on all linux platforms */
-	ret = get_errno(shmget(first, second, third));
-	break;
-
-	/* IPC_* and SHM_* command values are the same on all linux platforms */
-    case IPCOP_shmctl:
-        ret = do_shmctl(first, second, ptr);
-        break;
-    default:
-	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-	ret = -TARGET_ENOSYS;
-	break;
-    }
-    return ret;
-}
-#endif
-
 /* kernel structure types definitions */
 
 #define STRUCT(name, ...) STRUCT_ ## name,
@@ -9245,54 +8320,6 @@  static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             }
         }
         return ret;
-#ifdef TARGET_NR_ipc
-    case TARGET_NR_ipc:
-        return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
-#endif
-#ifdef TARGET_NR_semget
-    case TARGET_NR_semget:
-        return get_errno(semget(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_semop
-    case TARGET_NR_semop:
-        return do_semop(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_semctl
-    case TARGET_NR_semctl:
-        return do_semctl(arg1, arg2, arg3, arg4);
-#endif
-#ifdef TARGET_NR_msgctl
-    case TARGET_NR_msgctl:
-        return do_msgctl(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_msgget
-    case TARGET_NR_msgget:
-        return get_errno(msgget(arg1, arg2));
-#endif
-#ifdef TARGET_NR_msgrcv
-    case TARGET_NR_msgrcv:
-        return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
-#endif
-#ifdef TARGET_NR_msgsnd
-    case TARGET_NR_msgsnd:
-        return do_msgsnd(arg1, arg2, arg3, arg4);
-#endif
-#ifdef TARGET_NR_shmget
-    case TARGET_NR_shmget:
-        return get_errno(shmget(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_shmctl
-    case TARGET_NR_shmctl:
-        return do_shmctl(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_shmat
-    case TARGET_NR_shmat:
-        return do_shmat(cpu_env, arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_shmdt
-    case TARGET_NR_shmdt:
-        return do_shmdt(arg1);
-#endif
     case TARGET_NR_fsync:
         return get_errno(fsync(arg1));
     case TARGET_NR_clone:
diff --git a/linux-user/syscall_ipc.c b/linux-user/syscall_ipc.c
new file mode 100644
index 0000000000..e2617c7a63
--- /dev/null
+++ b/linux-user/syscall_ipc.c
@@ -0,0 +1,1095 @@ 
+/*
+ *  Linux ipc-related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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 "qemu/cutils.h"
+#include "qemu/path.h"
+#include "qemu.h"
+#include "syscall.h"
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <linux/unistd.h>
+
+
+#ifdef __NR_msgsnd
+safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
+              int, flags)
+safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
+              long, msgtype, int, flags)
+safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
+              unsigned, nsops, const struct timespec *, timeout)
+#else
+/* This host kernel architecture uses a single ipc syscall; fake up
+ * wrappers for the sub-operations to hide this implementation detail.
+ * Annoyingly we can't include linux/ipc.h to get the constant definitions
+ * for the call parameter because some structs in there conflict with the
+ * sys/ipc.h ones. So we just define them here, and rely on them being
+ * the same for all host architectures.
+ */
+#define Q_SEMTIMEDOP 4
+#define Q_MSGSND 11
+#define Q_MSGRCV 12
+#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
+
+safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
+              void *, ptr, long, fifth)
+
+static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
+{
+    return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
+}
+
+static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
+{
+    return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
+}
+
+static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
+                           const struct timespec *timeout)
+{
+    return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
+                    (long)timeout);
+}
+#endif
+
+/* See <linux/ipc.h> comment above.  */
+#define SEMOPM  500
+
+#define N_SHM_REGIONS  32
+
+static struct shm_region {
+    abi_ulong start;
+    abi_ulong size;
+    bool in_use;
+} shm_regions[N_SHM_REGIONS];
+
+#ifndef TARGET_SEMID64_DS
+/* asm-generic version of this struct */
+struct target_semid64_ds {
+    struct target_ipc_perm sem_perm;
+    abi_ulong sem_otime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong sem_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong sem_nsems;
+    abi_ulong __unused3;
+    abi_ulong __unused4;
+};
+#endif
+
+static abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+                                        abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    target_ip = &target_sd->sem_perm;
+    host_ip->__key = tswap32(target_ip->__key);
+    host_ip->uid = tswap32(target_ip->uid);
+    host_ip->gid = tswap32(target_ip->gid);
+    host_ip->cuid = tswap32(target_ip->cuid);
+    host_ip->cgid = tswap32(target_ip->cgid);
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
+    host_ip->mode = tswap32(target_ip->mode);
+#else
+    host_ip->mode = tswap16(target_ip->mode);
+#endif
+#if defined(TARGET_PPC)
+    host_ip->__seq = tswap32(target_ip->__seq);
+#else
+    host_ip->__seq = tswap16(target_ip->__seq);
+#endif
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+                                        struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_ip = &target_sd->sem_perm;
+    target_ip->__key = tswap32(host_ip->__key);
+    target_ip->uid = tswap32(host_ip->uid);
+    target_ip->gid = tswap32(host_ip->gid);
+    target_ip->cuid = tswap32(host_ip->cuid);
+    target_ip->cgid = tswap32(host_ip->cgid);
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
+    target_ip->mode = tswap32(host_ip->mode);
+#else
+    target_ip->mode = tswap16(host_ip->mode);
+#endif
+#if defined(TARGET_PPC)
+    target_ip->__seq = tswap32(host_ip->__seq);
+#else
+    target_ip->__seq = tswap16(host_ip->__seq);
+#endif
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+static abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+                                        abi_ulong target_addr)
+{
+    struct target_semid64_ds *target_sd;
+
+    if (target_to_host_ipc_perm(&host_sd->sem_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_semid_ds(abi_ulong target_addr,
+                                        struct semid_ds *host_sd)
+{
+    struct target_semid64_ds *target_sd;
+
+    if (host_to_target_ipc_perm(target_addr, &host_sd->sem_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                       struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
+union semun {
+    int val;
+    struct semid_ds *buf;
+    unsigned short *array;
+    struct seminfo *__buf;
+};
+
+union target_semun {
+    int val;
+    abi_ulong buf;
+    abi_ulong array;
+    abi_ulong __buf;
+};
+
+static abi_long target_to_host_semarray(int semid,
+                                        unsigned short **host_array,
+                                        abi_ulong target_addr)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = g_try_new(unsigned short, nsems);
+    if (!*host_array) {
+        return -TARGET_ENOMEM;
+    }
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems * sizeof(unsigned short), 1);
+    if (!array) {
+        g_free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+static abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                        unsigned short **host_array)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems * sizeof(unsigned short), 0);
+    if (!array) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
+    }
+    g_free(*host_array);
+    unlock_user(array, target_addr, 1);
+
+    return 0;
+}
+
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                      abi_ulong target_addr,
+                                      unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops * sizeof(struct target_sembuf), 1);
+    if (!target_sembuf) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsops; i++) {
+        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+    unlock_user(target_sembuf, target_addr, 0);
+    return 0;
+}
+
+struct target_msqid_ds {
+    struct target_ipc_perm msg_perm;
+    abi_ulong msg_stime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong msg_rtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong msg_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    abi_ulong __msg_cbytes;
+    abi_ulong msg_qnum;
+    abi_ulong msg_qbytes;
+    abi_ulong msg_lspid;
+    abi_ulong msg_lrpid;
+    abi_ulong __unused4;
+    abi_ulong __unused5;
+};
+
+static abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+                                        abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (target_to_host_ipc_perm(&host_md->msg_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    host_md->msg_stime = tswapal(target_md->msg_stime);
+    host_md->msg_rtime = tswapal(target_md->msg_rtime);
+    host_md->msg_ctime = tswapal(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapal(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapal(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+                                        struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (host_to_target_ipc_perm(target_addr, &host_md->msg_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_md->msg_stime = tswapal(host_md->msg_stime);
+    target_md->msg_rtime = tswapal(host_md->msg_rtime);
+    target_md->msg_ctime = tswapal(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapal(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapal(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 1);
+    return 0;
+}
+
+struct target_msginfo {
+    int msgpool;
+    int msgmap;
+    int msgmax;
+    int msgmnb;
+    int msgmni;
+    int msgssz;
+    int msgtql;
+    unsigned short int msgseg;
+};
+
+static abi_long host_to_target_msginfo(abi_ulong target_addr,
+                                       struct msginfo *host_msginfo)
+{
+    struct target_msginfo *target_msginfo;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
+    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
+    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
+    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
+    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
+    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
+    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
+    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
+    unlock_user_struct(target_msginfo, target_addr, 1);
+    return 0;
+}
+
+struct target_msgbuf {
+    abi_long mtype;
+    char mtext[1];
+};
+
+static abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                        abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (target_to_host_ipc_perm(&host_sd->shm_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                        struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (host_to_target_ipc_perm(target_addr, &host_sd->shm_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        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 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 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;
+}
+
+#ifndef TARGET_FORCE_SHMLBA
+/* For most architectures, SHMLBA is the same as the page size;
+ * some architectures have larger values, in which case they should
+ * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
+ * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
+ * and defining its own value for SHMLBA.
+ *
+ * The kernel also permits SHMLBA to be set by the architecture to a
+ * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
+ * this means that addresses are rounded to the large size if
+ * SHM_RND is set but addresses not aligned to that size are not rejected
+ * as long as they are at least page-aligned. Since the only architecture
+ * which uses this is ia64 this code doesn't provide for that oddity.
+ */
+static abi_ulong target_shmlba(CPUArchState *cpu_env)
+{
+    return TARGET_PAGE_SIZE;
+}
+#endif
+
+
+SYSCALL_IMPL(msgctl)
+{
+    abi_long msgid = arg1;
+    int cmd = arg2 & 0xff;
+    abi_ulong ptr = arg3;
+    struct msqid_ds dsarg;
+    struct msginfo msginfo;
+    abi_long ret;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case MSG_STAT:
+        if (target_to_host_msqid_ds(&dsarg, ptr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(msgctl(msgid, cmd, &dsarg));
+        if (!is_error(ret) && host_to_target_msqid_ds(ptr, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_RMID:
+        return get_errno(msgctl(msgid, cmd, NULL));
+
+    case IPC_INFO:
+    case MSG_INFO:
+        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
+        if (host_to_target_msginfo(ptr, &msginfo)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+SYSCALL_DEF(msgctl, ARG_DEC, ARG_DEC, ARG_PTR);
+
+SYSCALL_IMPL(msgget)
+{
+    return get_errno(msgget(arg1, arg2));
+}
+SYSCALL_DEF(msgget, ARG_DEC, ARG_DEC);
+
+SYSCALL_IMPL(msgrcv)
+{
+    int msqid = arg1;
+    abi_ulong msgp = arg2;
+    abi_long msgsz = arg3;
+    abi_long msgtyp = arg4;
+    int msgflg = arg5;
+    struct target_msgbuf *target_mb;
+    char *target_mtext;
+    struct msgbuf *host_mb;
+    abi_long ret = 0;
+
+    if (msgsz < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    host_mb = g_try_malloc(msgsz + sizeof(long));
+    if (!host_mb) {
+        ret = -TARGET_ENOMEM;
+        goto end;
+    }
+    ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
+
+    if (ret > 0) {
+        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
+        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
+        if (!target_mtext) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+    target_mb->mtype = tswapal(host_mb->mtype);
+
+ end:
+    unlock_user_struct(target_mb, msgp, 1);
+    g_free(host_mb);
+    return ret;
+}
+SYSCALL_DEF(msgrcv, ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC, ARG_HEX);
+
+SYSCALL_IMPL(msgsnd)
+{
+    int msqid = arg1;
+    abi_ulong msgp = arg2;
+    abi_long msgsz = arg3;
+    int msgflg = arg4;
+    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 = g_try_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(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
+
+    g_free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+    return ret;
+}
+SYSCALL_DEF(msgsnd, ARG_DEC, ARG_PTR, ARG_DEC, ARG_HEX);
+
+SYSCALL_IMPL(semctl)
+{
+    abi_long semid = arg1;
+    abi_long semnum = arg2;
+    int cmd = arg3 & 0xff;
+    abi_ulong target_arg = arg4;
+    union target_semun target_su = { .buf = target_arg };
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    struct seminfo seminfo;
+    abi_long ret, err;
+
+    switch (cmd) {
+    case GETVAL:
+    case SETVAL:
+        /* 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;
+        }
+        return get_errno(semctl(semid, semnum, cmd, arg));
+
+    case GETALL:
+    case SETALL:
+        err = target_to_host_semarray(semid, &array, target_su.array);
+        if (err) {
+            return err;
+        }
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_semarray(semid, target_su.array, &array);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_STAT:
+    case IPC_SET:
+    case SEM_STAT:
+        err = target_to_host_semid_ds(&dsarg, target_su.buf);
+        if (err) {
+            return err;
+        }
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_semid_ds(target_su.buf, &dsarg);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_INFO:
+    case SEM_INFO:
+        arg.__buf = &seminfo;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_seminfo(target_su.__buf, &seminfo);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        return get_errno(semctl(semid, semnum, cmd, NULL));
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+SYSCALL_DEF(semctl, ARG_DEC, ARG_DEC, ARG_DEC, ARG_HEX);
+
+SYSCALL_IMPL(semget)
+{
+    return get_errno(semget(arg1, arg2, arg3));
+}
+SYSCALL_DEF(semget, ARG_DEC, ARG_DEC, ARG_HEX);
+
+SYSCALL_IMPL(semop)
+{
+    abi_long semid = arg1;
+    abi_ulong ptr = arg2;
+    abi_ulong nsops = arg3;
+    struct sembuf sops[SEMOPM];
+
+    if (nsops > SEMOPM) {
+        return -TARGET_E2BIG;
+    }
+    if (target_to_host_sembuf(sops, ptr, nsops)) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
+}
+SYSCALL_DEF(semop, ARG_DEC, ARG_PTR, ARG_DEC);
+
+SYSCALL_IMPL(shmget)
+{
+    return get_errno(shmget(arg1, arg2, arg3));
+}
+SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
+
+SYSCALL_IMPL(shmctl)
+{
+    int shmid = arg1;
+    int cmd = arg2 & 0xff;
+    abi_ulong buf = arg3;
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret;
+
+    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 (!is_error(ret) && host_to_target_shmid_ds(buf, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (!is_error(ret) && host_to_target_shminfo(buf, &shminfo)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (!is_error(ret) && host_to_target_shm_info(buf, &shm_info)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        return get_errno(shmctl(shmid, cmd, NULL));
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+SYSCALL_DEF(shmctl, ARG_DEC, ARG_DEC, ARG_PTR);
+
+SYSCALL_IMPL(shmat)
+{
+    int shmid = arg1;
+    abi_ulong shmaddr = arg2;
+    int shmflg = arg3;
+    abi_ulong raddr;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i, ret;
+    abi_ulong shmlba;
+
+    /* 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;
+    }
+
+    /* Validate memory placement and alignment for the guest.  */
+    shmlba = target_shmlba(cpu_env);
+    if (shmaddr & (shmlba - 1)) {
+        if (shmflg & SHM_RND) {
+            shmaddr &= ~(shmlba - 1);
+        } else {
+            return -TARGET_EINVAL;
+        }
+    }
+    if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
+        return -TARGET_EINVAL;
+    }
+
+    mmap_lock();
+
+    if (shmaddr) {
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+    } else {
+        abi_ulong 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((intptr_t)host_raddr);
+    }
+
+    raddr = h2g((uintptr_t)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].in_use) {
+            shm_regions[i].in_use = true;
+            shm_regions[i].start = raddr;
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+    mmap_unlock();
+    return raddr;
+}
+
+const SyscallDef def_shmat = {
+    .name = "shmat",
+    .impl = impl_shmat,
+    .print_ret = print_syscall_ptr_ret,
+    .arg_type = { ARG_DEC, ARG_PTR, ARG_HEX }
+};
+
+SYSCALL_IMPL(shmdt)
+{
+    abi_ulong shmaddr = arg1;
+    abi_long ret;
+    int i;
+
+    mmap_lock();
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
+            shm_regions[i].in_use = false;
+            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
+            break;
+        }
+    }
+    ret = get_errno(shmdt(g2h(shmaddr)));
+
+    mmap_unlock();
+
+    return ret;
+}
+SYSCALL_DEF(shmdt, ARG_PTR);
+
+#ifdef TARGET_NR_ipc
+/* This differs from normal shmat in returning the result via a pointer.
+ * Here we have shifted that pointer to arg4.
+ */
+SYSCALL_IMPL(ipc_shmat)
+{
+    abi_long ret = impl_shmat(cpu_env, arg1, arg2, arg3, 0, 0, 0);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+    if (put_user_ual(ret, arg4)) {
+        return -TARGET_EFAULT;
+    }
+    return 0;
+}
+
+static const SyscallDef def_ipc_shmat = {
+    .name = "shmat",
+    .impl = impl_ipc_shmat,
+    .arg_type = { ARG_DEC, ARG_PTR, ARG_HEX, ARG_PTR },
+};
+
+/* Demultiplex the IPC syscall and shuffle the arguments around
+ * into the "normal" ordering.
+ */
+SYSCALL_ARGS(ipc)
+{
+    int call = extract32(in[0], 0, 16);
+    int version = extract32(in[0], 16, 16);
+    abi_long first = in[1];
+    abi_long second = in[2];
+    abi_long third = in[3];
+    abi_ulong ptr = in[4];
+    abi_long fifth = in[5];
+    abi_ulong atptr;
+
+    /* IPC_* and SHM_* command values are the same on all linux platforms */
+    switch (call) {
+    case IPCOP_semop:
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        return &def_semop;
+
+    case IPCOP_semget:
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        return &def_semget;
+
+    case IPCOP_semctl:
+        /* The semun argument to semctl is passed by value,
+         * so dereference the ptr argument.
+         */
+        if (get_user_ual(atptr, ptr)) {
+            errno = EFAULT;
+            return NULL;
+        }
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        out[3] = atptr;
+        return &def_semctl;
+
+    case IPCOP_msgget:
+        out[0] = first;
+        out[1] = second;
+        return &def_msgget;
+
+    case IPCOP_msgsnd:
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        out[3] = third;
+        return &def_msgsnd;
+
+    case IPCOP_msgctl:
+        out[0] = first;
+        out[1] = second;
+        out[2] = ptr;
+        return &def_msgctl;
+
+    case IPCOP_msgrcv:
+        if (version == 0) {
+            struct target_ipc_kludge {
+                abi_long msgp;
+                abi_long msgtyp;
+            } *tmp;
+
+            if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
+                errno = EFAULT;
+                return NULL;
+            }
+            out[0] = first;
+            out[1] = tswapal(tmp->msgp);
+            out[2] = second;
+            out[3] = tswapal(tmp->msgtyp);
+            out[4] = third;
+            unlock_user_struct(tmp, ptr, 0);
+        } else {
+            out[0] = first;
+            out[1] = ptr;
+            out[2] = second;
+            out[3] = fifth;
+            out[4] = third;
+        }
+        return &def_msgrcv;
+
+    case IPCOP_shmat:
+        if (version == 1) {
+            errno = EINVAL;
+            return NULL;
+        }
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        out[3] = third;
+        return &def_ipc_shmat;
+
+    case IPCOP_shmdt:
+        out[0] = ptr;
+        return &def_shmdt;
+
+    case IPCOP_shmget:
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        return &def_shmget;
+
+    case IPCOP_shmctl:
+        out[0] = first;
+        out[1] = second;
+        out[2] = ptr;
+        return &def_shmctl;
+
+    default:
+        /* Invalid syscall.  Continue to impl_ipc for logging.  */
+        return def;
+    }
+}
+
+SYSCALL_IMPL(ipc)
+{
+    int call = extract32(arg1, 0, 16);
+    int version = extract32(arg1, 16, 16);
+
+    gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+    return -TARGET_ENOSYS;
+}
+SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
+#endif
diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
index 63b81f50e8..18dfda66c9 100644
--- a/linux-user/Makefile.objs
+++ b/linux-user/Makefile.objs
@@ -1,4 +1,5 @@ 
-obj-y = main.o syscall.o syscall_file.o strace.o mmap.o signal.o \
+obj-y = main.o syscall.o syscall_file.o syscall_ipc.o \
+	strace.o mmap.o signal.o \
 	elfload.o linuxload.o uaccess.o uname.o \
 	safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
         $(TARGET_ABI_DIR)/cpu_loop.o
@@ -17,4 +18,5 @@  $(SYSCALL_LIST): $(GEN_SYSCALL_LIST)
 
 linux-user/syscall.o \
 linux-user/syscall_file.o \
+linux-user/syscall_ipc.o \
 linux-user/strace.o: $(SYSCALL_LIST)
diff --git a/linux-user/gen_syscall_list.py b/linux-user/gen_syscall_list.py
index cebf111660..68ab279d00 100644
--- a/linux-user/gen_syscall_list.py
+++ b/linux-user/gen_syscall_list.py
@@ -41,7 +41,19 @@  unconditional_syscalls = [
 
 # These syscalls are only supported by some target or abis.
 conditional_syscalls = [
+    "ipc",
+    "msgctl",
+    "msgget",
+    "msgrcv",
+    "msgsnd",
     "open",
+    "semctl",
+    "semget",
+    "semop",
+    "shmat",
+    "shmctl",
+    "shmdt",
+    "shmget",
 ]
 
 
diff --git a/linux-user/strace.list b/linux-user/strace.list
index d7880665a4..b0a9b4ad1a 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -452,9 +452,6 @@ 
 #ifdef TARGET_NR_io_submit
 { TARGET_NR_io_submit, "io_submit" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_ipc
-{ TARGET_NR_ipc, "ipc" , NULL, print_ipc, NULL },
-#endif
 #ifdef TARGET_NR_kcmp
 { TARGET_NR_kcmp, "kcmp" , NULL, NULL, NULL },
 #endif
@@ -608,18 +605,6 @@ 
 #ifdef TARGET_NR_mremap
 { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_msgctl
-{ TARGET_NR_msgctl, "msgctl" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgget
-{ TARGET_NR_msgget, "msgget" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgrcv
-{ TARGET_NR_msgrcv, "msgrcv" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgsnd
-{ TARGET_NR_msgsnd, "msgsnd" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_msync
 { TARGET_NR_msync, "msync" , NULL, NULL, NULL },
 #endif
@@ -917,9 +902,6 @@ 
 #ifdef TARGET_NR_osf_settimeofday
 { TARGET_NR_osf_settimeofday, "osf_settimeofday" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_osf_shmat
-{ TARGET_NR_osf_shmat, "osf_shmat" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_osf_signal
 { TARGET_NR_osf_signal, "osf_signal" , NULL, NULL, NULL },
 #endif
@@ -1190,18 +1172,6 @@ 
 #ifdef TARGET_NR_select
 { TARGET_NR_select, "select" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_semctl
-{ TARGET_NR_semctl, "semctl" , NULL, print_semctl, NULL },
-#endif
-#ifdef TARGET_NR_semget
-{ TARGET_NR_semget, "semget" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_semop
-{ TARGET_NR_semop, "semop" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_semtimedop
-{ TARGET_NR_semtimedop, "semtimedop" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_send
 { TARGET_NR_send, "send" , NULL, NULL, NULL },
 #endif
@@ -1329,18 +1299,6 @@ 
 #ifdef TARGET_NR_sgetmask
 { TARGET_NR_sgetmask, "sgetmask" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_shmat
-{ TARGET_NR_shmat, "shmat" , NULL, NULL, print_syscall_ret_addr },
-#endif
-#ifdef TARGET_NR_shmctl
-{ TARGET_NR_shmctl, "shmctl" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_shmdt
-{ TARGET_NR_shmdt, "shmdt" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_shmget
-{ TARGET_NR_shmget, "shmget" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_shutdown
 { TARGET_NR_shutdown, "shutdown" , NULL, NULL, NULL },
 #endif