ipc endianness and ipc_64 fixes
PATCH 1/1 ipc endianness and ipc_64 fixes
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
linux-user/syscall.c +216 -5
@@ -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_permtarget_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_dstarget_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_peunlock_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_dstarget_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 firstcase 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 ;
linux-user/syscall.c +12 -2
@@ -1573,9 +1732,19 @@ static long do_ipc(long call, long firstswitch (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 ;
[Qemu-devel] linux-user ALSA partial support
Dear qemu developers,
I've been working with linux-user mode a little. I've added partial ALSA support through ioctls. The sucessful tests on an i386 host are:
* aplay -l (qemu-i386, qemu-ppc, qemu-i386 on qemu-i386)
* aplay test.wav (ditto)
* zsnes (qemu-i386)
I think there were other attempts to implement this, thus I don't know if mine would be of your interest.
While developing I fixed some issues maybe already reported: IPC, ioctl, memory alignment... Regarding the last one, I'm working with Debian, so that may be specific to it.
I've already found out what I wanted to know about qemu. If someone wants to take it over, I'll send the patch. I'll be glad to answer some questions about it.
Bye.