@@ -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
*/
@@ -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:
new file mode 100644
@@ -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
@@ -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)
@@ -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",
]
@@ -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
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