qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] ipc endianness and ipc_64 fixes


From: Alexander Graf
Subject: [Qemu-devel] [PATCH] ipc endianness and ipc_64 fixes
Date: Mon, 02 Jul 2007 19:46:11 +0200
User-agent: Thunderbird 1.5.0.10 (X11/20060911)

ipc_semop

This patch fixes an endianness issue with the semop-call.

ipc

This patch implements IPC_64 semantics to the semctl and shmctl calls.
This was tested on ppc host and i386 target and might work on others as
well. This is necessary to get alsa running.

As always: comments and suggestions appreciated

Alex
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -29,7 +29,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <time.h>
-#include <sys/types.h>
+#include <linux/types.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/wait.h>
@@ -46,6 +46,9 @@
 #include <sys/uio.h>
 #include <sys/poll.h>
 #include <sys/times.h>
+#include <asm/ipcbuf.h>
+#include <asm/shmbuf.h>
+#include <asm/sembuf.h>
 #include <sys/shm.h>
 #include <sys/sem.h>
 #include <sys/statfs.h>
@@ -150,6 +153,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_tgkill __NR_tgkill
 #define __NR_sys_clone __NR_clone
 #define __NR_sys_sched_getaffinity __NR_sched_getaffinity
+#define __NR_sys_ipc __NR_ipc
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -172,6 +176,10 @@ _syscall3(int,sys_rt_sigqueueinfo,int,pi
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
 _syscall5(int,sys_clone, int, flags, void *, child_stack, int *, 
parent_tidptr, void *, newtls, int *, child_tidptr)
+#ifdef __NR_ipc
+_syscall6(int,sys_ipc, long, call, long, first, long, second, long, third, 
void *, ptr, long, fifth)
+#define semctl(a,b,c,d) sys_ipc(IPCOP_semctl,a,b,c,&d,0l)
+#endif
 _syscall3(int,sys_sched_getaffinity,pid_t,pid,unsigned 
int,cpusetsize,void*,mask)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
@@ -1255,6 +1263,21 @@ struct target_ipc_perm
     target_ulong __unused2;
 };
 
+struct target_ipc64_perm
+{
+       int     key;
+       unsigned int    uid;
+       unsigned int    gid;
+       unsigned int    cuid;
+       unsigned int    cgid;
+       unsigned short  mode;
+       unsigned short  __pad1;
+       unsigned short  seq;
+       unsigned short  __pad2;
+       target_ulong    __unused1;
+       target_ulong    __unused2;
+};
+
 struct target_semid_ds
 {
   struct target_ipc_perm sem_perm;
@@ -1267,6 +1290,18 @@ struct target_semid_ds
   target_ulong __unused4;
 };
 
+struct target_semid64_ds
+{
+  struct target_ipc64_perm sem_perm;
+  target_ulong sem_otime;
+  target_ulong __unused1;
+  target_ulong sem_ctime;
+  target_ulong __unused2;
+  target_ulong sem_nsems;
+  target_ulong __unused3;
+  target_ulong __unused4;
+};
+
 static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip,
                                            target_ulong target_addr)
 {
@@ -1301,6 +1336,41 @@ static inline void host_to_target_ipc_pe
     unlock_user_struct(target_sd, target_addr, 1);
 }
 
+static inline void target_to_host_ipc64_perm( struct ipc64_perm *host_ip, 
target_ulong target_addr )
+{
+    struct target_ipc64_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 1);
+    target_ip=&(target_sd->sem_perm);
+    host_ip->key = tswapl(target_ip->key);
+    host_ip->uid = tswapl(target_ip->uid);
+    host_ip->gid = tswapl(target_ip->gid);
+    host_ip->cuid = tswapl(target_ip->cuid);
+    host_ip->cgid = tswapl(target_ip->cgid);
+    host_ip->mode = tswap16(target_ip->mode);
+    host_ip->seq = tswap16(target_ip->seq);
+    unlock_user_struct(target_sd, target_addr, 1);
+}
+
+static inline void host_to_target_ipc64_perm(target_ulong target_addr,
+                                           struct ipc64_perm *host_ip)
+{
+    struct target_ipc64_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 0);
+    target_ip = &(target_sd->sem_perm);
+    target_ip->key = tswapl(host_ip->key);
+    target_ip->uid = tswapl(host_ip->uid);
+    target_ip->gid = tswapl(host_ip->gid);
+    target_ip->cuid = tswapl(host_ip->cuid);
+    target_ip->cgid = tswapl(host_ip->cgid);
+    target_ip->mode = tswap16(host_ip->mode);
+    target_ip->seq = tswap16(host_ip->seq);
+    unlock_user_struct(target_sd, target_addr, 1);
+}
+
 static inline void target_to_host_semid_ds(struct semid_ds *host_sd,
                                           target_ulong target_addr)
 {
@@ -1327,6 +1397,32 @@ static inline void host_to_target_semid_
     unlock_user_struct(target_sd, target_addr, 1);
 }
 
+static inline void target_to_host_semid64_ds(struct semid64_ds *host_sd,
+                                          target_ulong target_addr)
+{
+    struct target_semid64_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 1);
+    target_to_host_ipc64_perm(&(host_sd->sem_perm),target_addr);
+    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapl(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+}
+
+static inline void host_to_target_semid64_ds(target_ulong target_addr,
+                                           struct semid64_ds *host_sd)
+{
+    struct target_semid64_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 0);
+    host_to_target_ipc64_perm(target_addr,&(host_sd->sem_perm));
+    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapl(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+}
+
 union semun {
        int val;
        struct semid_ds *buf;
@@ -1339,6 +1435,10 @@ union target_semun {
        unsigned short int *array;
 };
 
+#ifndef IPC_64
+#define IPC_64 0x100
+#endif
+
 static inline void target_to_host_semun(unsigned long cmd,
                                         union semun *host_su,
                                         target_ulong target_addr,
@@ -1350,7 +1450,16 @@ static inline void target_to_host_semun(
        case IPC_STAT:
        case IPC_SET:
            lock_user_struct(target_su, target_addr, 1);
-          target_to_host_semid_ds(ds,target_su->buf);
+          target_to_host_semid_ds(ds,tswapl(target_su->buf));
+          host_su->buf = ds;
+           unlock_user_struct(target_su, target_addr, 0);
+          break;
+       case IPC_STAT + IPC_64:
+       case IPC_SET + IPC_64:
+           lock_user_struct(target_su, target_addr, 1);
+          
+          //target_to_host_semid_ds(ds,tswapl(target_su->buf));
+          target_to_host_semid64_ds((struct semid64_ds 
*)ds,tswapl(target_su->buf));
           host_su->buf = ds;
            unlock_user_struct(target_su, target_addr, 0);
           break;
@@ -1382,7 +1491,14 @@ static inline void host_to_target_semun(
        case IPC_STAT:
        case IPC_SET:
            lock_user_struct(target_su, target_addr, 0);
-          host_to_target_semid_ds(target_su->buf,ds);
+          host_to_target_semid_ds(tswapl(target_su->buf),ds);
+           unlock_user_struct(target_su, target_addr, 1);
+          break;
+       case IPC_STAT + IPC_64:
+       case IPC_SET + IPC_64:
+           lock_user_struct(target_su, target_addr, 0);
+          //host_to_target_semid_ds(tswapl(target_su->buf),ds);
+          host_to_target_semid64_ds(tswapl(target_su->buf),(struct semid64_ds 
*)ds);
            unlock_user_struct(target_su, target_addr, 1);
           break;
        case GETVAL:
@@ -1406,7 +1522,8 @@ static inline long do_semctl(long first,
 {
     union semun arg;
     struct semid_ds dsarg;
-    int cmd = third&0xff;
+    struct semid64_ds dsarg64;
+    int cmd = third; // & 0xff;
     long ret = 0;
 
     switch( cmd ) {
@@ -1435,13 +1552,23 @@ static inline long do_semctl(long first,
             ret = get_errno(semctl(first, second, cmd, arg));
             host_to_target_semun(cmd,ptr,&arg,&dsarg);
             break;
+       case IPC_STAT + IPC_64:
+            target_to_host_semun(cmd,&arg,ptr,(struct semid_ds *)&dsarg64);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,(struct semid_ds *)&dsarg64);
+            break;
        case IPC_SET:
             target_to_host_semun(cmd,&arg,ptr,&dsarg);
             ret = get_errno(semctl(first, second, cmd, arg));
             host_to_target_semun(cmd,ptr,&arg,&dsarg);
             break;
-    default:
+       case IPC_SET + IPC_64:
+            target_to_host_semun(cmd,&arg,ptr,(struct semid_ds *)&dsarg64);
             ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,(struct semid_ds *)&dsarg64);
+            break;
+    default:
+            ret = get_errno(semctl(first, second, cmd & 0xff, arg));
     }
 
     return ret;
@@ -1465,6 +1592,42 @@ struct target_msqid_ds
   target_ulong __unused5;
 };
 
+
+struct target_shmid64_ds {
+       struct target_ipc64_perm shm_perm;      /* operation perms */
+       target_ulong            shm_segsz;      /* size of segment (bytes) */
+       target_ulong            shm_atime;      /* last attach time */
+       target_ulong            __unused1;
+       target_ulong            shm_dtime;      /* last detach time */
+       target_ulong            __unused2;
+       target_ulong            shm_ctime;      /* last change time */
+       target_ulong            __unused3;
+       int32_t                 shm_cpid;       /* pid of creator */
+       int32_t                 shm_lpid;       /* pid of last operator */
+       target_ulong            shm_nattch;     /* no. of current attaches */
+       target_ulong            __unused4;
+       target_ulong            __unused5;
+};
+
+/* Data structure describing a set of semaphores.  */
+struct target_shmid_ds
+  {
+    struct target_ipc_perm shm_perm;          /* operation permission struct */
+    unsigned int __unused1;
+    target_ulong shm_atime;                        /* time of last shmat() */
+    unsigned int __unused2;
+    target_ulong shm_dtime;                        /* time of last shmdt() */
+    unsigned int __unused3;
+    target_ulong shm_ctime;                    /* time of last change by 
shmctl() */
+    unsigned int __unused4;
+    target_ulong shm_segsz;                  /* size of segment in bytes */
+    unsigned int shm_cpid;                  /* pid of creator */
+    unsigned int shm_lpid;                  /* pid of last shmop */
+    target_ulong shm_nattch;               /* number of current attaches */
+    unsigned long __unused5;
+    unsigned long __unused6;
+  };
+
 static inline void target_to_host_msqid_ds(struct msqid_ds *host_md,
                                           target_ulong target_addr)
 {
@@ -1665,11 +1828,59 @@ static long do_ipc(long call, long first
     case IPCOP_shmctl:
         switch(second) {
         case IPC_RMID:
+       case IPC_RMID + IPC_64:
         case SHM_LOCK:
+       case SHM_LOCK + IPC_64:
         case SHM_UNLOCK:
+       case SHM_UNLOCK + IPC_64:
             ret = get_errno(shmctl(first, second, NULL));
             break;
+       case IPC_STAT + IPC_64:
+       {
+           struct shmid64_ds buf;
+           struct target_shmid64_ds *target_buf;
+#ifdef DEBUG
+           gemu_log("qemu: doing IPC_STAT\n");
+#endif
+           lock_user_struct(target_buf, ptr, 1); 
+           ret = get_errno(shmctl(first, second, (struct shmid_ds*)&buf));
+           
+           host_to_target_ipc64_perm(ptr, &buf.shm_perm);
+           target_buf->shm_atime  = tswapl(buf.shm_atime);
+           target_buf->shm_dtime  = tswapl(buf.shm_dtime);
+           target_buf->shm_ctime  = tswapl(buf.shm_ctime);
+           target_buf->shm_segsz  = tswapl(buf.shm_segsz);
+           target_buf->shm_cpid   = tswap32(buf.shm_cpid);
+           target_buf->shm_lpid   = tswap32(buf.shm_lpid);
+           target_buf->shm_nattch = tswapl(buf.shm_nattch);
+           unlock_user_struct(target_buf, ptr, 0);
+           break;
+       }
+       case IPC_SET + IPC_64:
+       {
+           struct shmid64_ds buf;
+           struct target_shmid64_ds *target_buf;
+#ifdef DEBUG
+           gemu_log("qemu: doing IPC_SET\n");
+#endif
+           lock_user_struct(target_buf, ptr, 1); 
+
+           target_to_host_ipc64_perm(&buf.shm_perm, ptr);
+           buf.shm_atime  = tswapl(target_buf->shm_atime);
+           buf.shm_dtime  = tswapl(target_buf->shm_dtime);
+           buf.shm_ctime  = tswapl(target_buf->shm_ctime);
+           buf.shm_segsz  = tswapl(target_buf->shm_segsz);
+           buf.shm_cpid   = tswap32(target_buf->shm_cpid);
+           buf.shm_lpid   = tswap32(target_buf->shm_lpid);
+           buf.shm_nattch = tswapl(target_buf->shm_nattch);
+
+           ret = get_errno(shmctl(first, second, (struct shmid_ds*)&buf));
+           
+           unlock_user_struct(target_buf, ptr, 0);
+           break;
+       }
         default:
+           gemu_log("Unsopported shmctl(%ld,%#lx)\n", second, second);
             goto unimplemented;
         }
         break;
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -1573,9 +1732,19 @@ static long do_ipc(long call, long first
 
     switch (call) {
     case IPCOP_semop:
-        ret = get_errno(semop(first,(struct sembuf *) ptr, second));
+    {
+       struct sembuf *target_sops;
+       int i;
+       lock_user_struct(target_sops, ptr, 0);
+       for(i=0; i<second; i++) {
+               target_sops[i].sem_num = tswap16(target_sops[i].sem_num);
+               target_sops[i].sem_op  = tswap16(target_sops[i].sem_op);
+               target_sops[i].sem_flg = tswap16(target_sops[i].sem_flg);
+       }
+        ret = get_errno(semop(first, target_sops, second));
+       unlock_user_struct(target_sops, ptr, 0);
         break;
-
+    }
     case IPCOP_semget:
         ret = get_errno(semget(first, second, third));
         break;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]