From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KpKMw-0003vq-Os for qemu-devel@nongnu.org; Mon, 13 Oct 2008 06:09:42 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KpKMv-0003uu-JT for qemu-devel@nongnu.org; Mon, 13 Oct 2008 06:09:41 -0400 Received: from [199.232.76.173] (port=47853 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KpKMu-0003ub-GE for qemu-devel@nongnu.org; Mon, 13 Oct 2008 06:09:40 -0400 Received: from ug-out-1314.google.com ([66.249.92.169]:63550) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KpKMt-00076x-V4 for qemu-devel@nongnu.org; Mon, 13 Oct 2008 06:09:40 -0400 Received: by ug-out-1314.google.com with SMTP id j3so435909ugf.36 for ; Mon, 13 Oct 2008 03:09:39 -0700 (PDT) From: "Kirill A. Shutemov" Date: Mon, 13 Oct 2008 13:10:34 +0300 Message-Id: <1223892640-15545-7-git-send-email-kirill@shutemov.name> In-Reply-To: <1223892640-15545-6-git-send-email-kirill@shutemov.name> References: <1223892640-15545-1-git-send-email-kirill@shutemov.name> <1223892640-15545-2-git-send-email-kirill@shutemov.name> <1223892640-15545-3-git-send-email-kirill@shutemov.name> <1223892640-15545-4-git-send-email-kirill@shutemov.name> <1223892640-15545-5-git-send-email-kirill@shutemov.name> <1223892640-15545-6-git-send-email-kirill@shutemov.name> Subject: [Qemu-devel] [PATCH] Fix and cleanup IPCOP_shm* ipc calls handling Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: "Kirill A. Shutemov" , Paul Brook Signed-off-by: Kirill A. Shutemov --- linux-user/syscall.c | 282 +++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 224 insertions(+), 58 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1a09d90..d1fccb4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2109,6 +2109,206 @@ end: return ret; } +struct target_shmid_ds +{ + struct target_ipc_perm shm_perm; + abi_ulong shm_segsz; + abi_ulong shm_atime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused1; +#endif + abi_ulong shm_dtime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused2; +#endif + abi_ulong shm_ctime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused3; +#endif + int shm_cpid; + int shm_lpid; + abi_ulong shm_nattch; + unsigned long int __unused4; + unsigned long int __unused5; +}; + +static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; + if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) + return -TARGET_EFAULT; + __put_user(target_sd->shm_segsz, &host_sd->shm_segsz); + __put_user(target_sd->shm_atime, &host_sd->shm_atime); + __put_user(target_sd->shm_dtime, &host_sd->shm_dtime); + __put_user(target_sd->shm_ctime, &host_sd->shm_ctime); + __put_user(target_sd->shm_cpid, &host_sd->shm_cpid); + __put_user(target_sd->shm_lpid, &host_sd->shm_lpid); + __put_user(target_sd->shm_nattch, &host_sd->shm_nattch); + unlock_user_struct(target_sd, target_addr, 0); + return 0; +} + +static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; + if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) + return -TARGET_EFAULT; + __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __put_user(host_sd->shm_atime, &target_sd->shm_atime); + __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); + __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); + unlock_user_struct(target_sd, target_addr, 1); + return 0; +} + +struct target_shminfo { + abi_ulong shmmax; + abi_ulong shmmin; + abi_ulong shmmni; + abi_ulong shmseg; + abi_ulong shmall; +}; + +static inline abi_long host_to_target_shminfo(abi_ulong target_addr, + struct shminfo *host_shminfo) +{ + struct target_shminfo *target_shminfo; + if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0)) + return -TARGET_EFAULT; + __put_user(host_shminfo->shmmax, &target_shminfo->shmmax); + __put_user(host_shminfo->shmmin, &target_shminfo->shmmin); + __put_user(host_shminfo->shmmni, &target_shminfo->shmmni); + __put_user(host_shminfo->shmseg, &target_shminfo->shmseg); + __put_user(host_shminfo->shmall, &target_shminfo->shmall); + unlock_user_struct(target_shminfo, target_addr, 1); +} + +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); +} + +static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf) +{ + struct shmid_ds dsarg; + struct shminfo shminfo; + struct shm_info shm_info; + abi_long ret = -TARGET_EINVAL; + + cmd &= 0xff; + + switch(cmd) { + case IPC_STAT: + case IPC_SET: + case SHM_STAT: + if (target_to_host_shmid_ds(&dsarg, buf)) + return -TARGET_EFAULT; + ret = get_errno(shmctl(shmid, cmd, &dsarg)); + if (host_to_target_shmid_ds(buf, &dsarg)) + return -TARGET_EFAULT; + break; + case IPC_INFO: + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo)); + if (host_to_target_shminfo(buf, &shminfo)) + return -TARGET_EFAULT; + break; + case SHM_INFO: + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info)); + if (host_to_target_shm_info(buf, &shm_info)) + return -TARGET_EFAULT; + break; + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + ret = get_errno(shmctl(shmid, cmd, NULL)); + break; + } + + return ret; +} + +static inline abi_long do_shmat(int shmid, abi_ulong shmaddr, int shmflg, + unsigned long *raddr) +{ + abi_long ret; + struct shmid_ds shm_info; + int i; + + /* SHM_* flags are the same on all linux platforms */ + *raddr = (unsigned long) shmat(shmid, g2h(shmaddr), shmflg); + + if (*raddr == -1) { + return get_errno(*raddr); + } + + /* 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 */ + shmdt((void *) *raddr); + return get_errno(ret); + } + + page_set_flags(h2g(*raddr), h2g(*raddr) + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | + ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE)); + + for (i = 0; i < N_SHM_REGIONS; i++) { + if (shm_regions[i].start == 0) { + shm_regions[i].start = h2g(*raddr); + shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + + return 0; +} + +static inline abi_long do_shmdt(abi_ulong shmaddr) +{ + int i; + + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == shmaddr) { + shm_regions[i].start = 0; + page_set_flags(shmaddr, shm_regions[i].size, 0); + break; + } + } + + return get_errno(shmdt(g2h(shmaddr))); +} + #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ @@ -2118,8 +2318,6 @@ static abi_long do_ipc(unsigned int call, int first, { int version; abi_long ret = 0; - struct shmid_ds shm_info; - int i; version = call >> 16; call &= 0xffff; @@ -2174,72 +2372,40 @@ static abi_long do_ipc(unsigned int call, int first, break; case IPCOP_shmat: - { - abi_ulong raddr; - void *host_addr; - /* SHM_* flags are the same on all linux platforms */ - host_addr = shmat(first, (void *)g2h(ptr), second); - if (host_addr == (void *)-1) { - ret = get_errno((long)host_addr); - break; - } - raddr = h2g((unsigned long)host_addr); - /* find out the length of the shared memory segment */ - - ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); - if (is_error(ret)) { - /* can't get length, bail out */ - shmdt(host_addr); - break; - } - page_set_flags(raddr, raddr + shm_info.shm_segsz, - PAGE_VALID | PAGE_READ | - ((second & SHM_RDONLY)? 0: PAGE_WRITE)); - for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == 0) { - shm_regions[i].start = raddr; - shm_regions[i].size = shm_info.shm_segsz; + switch (version) { + default: + { + unsigned long raddr; + + ret = do_shmat(first, ptr, second, &raddr); + if (ret) break; - } + + ret = put_user_ual(raddr, third); + break; } - if (put_user_ual(raddr, third)) - return -TARGET_EFAULT; - ret = 0; + case 1: + ret = -TARGET_EINVAL; + break; } - break; + break; + case IPCOP_shmdt: - for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == ptr) { - shm_regions[i].start = 0; - page_set_flags(ptr, shm_regions[i].size, 0); - break; - } - } - ret = get_errno(shmdt((void *)g2h(ptr))); - break; + 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; + ret = get_errno(shmget(first, second, third)); + break; - /* IPC_* and SHM_* command values are the same on all linux platforms */ case IPCOP_shmctl: - switch(second) { - case IPC_RMID: - case SHM_LOCK: - case SHM_UNLOCK: - ret = get_errno(shmctl(first, second, NULL)); - break; - default: - goto unimplemented; - } + ret = do_shmctl(first, second, third); break; + default: - unimplemented: - gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); - ret = -TARGET_ENOSYS; - break; + gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); + ret = -TARGET_ENOSYS; + break; } return ret; } -- 1.5.6.5.GIT