Commit e5289087edbb66ac02729211ec46cfb7acbd5f1c
1 parent
c48101ae
linux-user: fix IPCOP_sem* and implement sem*
Fix and cleanup IPCOP_sem* ipc calls handling and implement sem* syscalls. Riku: 1) Uglify whitespace so that diff gets smaller and easier to review 2) use __get_user in target_to_host_sembuf Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7184 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
188 additions
and
98 deletions
linux-user/syscall.c
| ... | ... | @@ -2006,7 +2006,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, |
| 2006 | 2006 | |
| 2007 | 2007 | if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) |
| 2008 | 2008 | return -TARGET_EFAULT; |
| 2009 | - target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); | |
| 2009 | + if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr)) | |
| 2010 | + return -TARGET_EFAULT; | |
| 2010 | 2011 | host_sd->sem_nsems = tswapl(target_sd->sem_nsems); |
| 2011 | 2012 | host_sd->sem_otime = tswapl(target_sd->sem_otime); |
| 2012 | 2013 | host_sd->sem_ctime = tswapl(target_sd->sem_ctime); |
| ... | ... | @@ -2021,7 +2022,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, |
| 2021 | 2022 | |
| 2022 | 2023 | if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) |
| 2023 | 2024 | return -TARGET_EFAULT; |
| 2024 | - host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); | |
| 2025 | + if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm))) | |
| 2026 | + return -TARGET_EFAULT;; | |
| 2025 | 2027 | target_sd->sem_nsems = tswapl(host_sd->sem_nsems); |
| 2026 | 2028 | target_sd->sem_otime = tswapl(host_sd->sem_otime); |
| 2027 | 2029 | target_sd->sem_ctime = tswapl(host_sd->sem_ctime); |
| ... | ... | @@ -2029,135 +2031,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, |
| 2029 | 2031 | return 0; |
| 2030 | 2032 | } |
| 2031 | 2033 | |
| 2034 | +struct target_seminfo { | |
| 2035 | + int semmap; | |
| 2036 | + int semmni; | |
| 2037 | + int semmns; | |
| 2038 | + int semmnu; | |
| 2039 | + int semmsl; | |
| 2040 | + int semopm; | |
| 2041 | + int semume; | |
| 2042 | + int semusz; | |
| 2043 | + int semvmx; | |
| 2044 | + int semaem; | |
| 2045 | +}; | |
| 2046 | + | |
| 2047 | +static inline abi_long host_to_target_seminfo(abi_ulong target_addr, | |
| 2048 | + struct seminfo *host_seminfo) | |
| 2049 | +{ | |
| 2050 | + struct target_seminfo *target_seminfo; | |
| 2051 | + if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0)) | |
| 2052 | + return -TARGET_EFAULT; | |
| 2053 | + __put_user(host_seminfo->semmap, &target_seminfo->semmap); | |
| 2054 | + __put_user(host_seminfo->semmni, &target_seminfo->semmni); | |
| 2055 | + __put_user(host_seminfo->semmns, &target_seminfo->semmns); | |
| 2056 | + __put_user(host_seminfo->semmnu, &target_seminfo->semmnu); | |
| 2057 | + __put_user(host_seminfo->semmsl, &target_seminfo->semmsl); | |
| 2058 | + __put_user(host_seminfo->semopm, &target_seminfo->semopm); | |
| 2059 | + __put_user(host_seminfo->semume, &target_seminfo->semume); | |
| 2060 | + __put_user(host_seminfo->semusz, &target_seminfo->semusz); | |
| 2061 | + __put_user(host_seminfo->semvmx, &target_seminfo->semvmx); | |
| 2062 | + __put_user(host_seminfo->semaem, &target_seminfo->semaem); | |
| 2063 | + unlock_user_struct(target_seminfo, target_addr, 1); | |
| 2064 | + return 0; | |
| 2065 | +} | |
| 2066 | + | |
| 2032 | 2067 | union semun { |
| 2033 | 2068 | int val; |
| 2034 | 2069 | struct semid_ds *buf; |
| 2035 | 2070 | unsigned short *array; |
| 2071 | + struct seminfo *__buf; | |
| 2036 | 2072 | }; |
| 2037 | 2073 | |
| 2038 | 2074 | union target_semun { |
| 2039 | 2075 | int val; |
| 2040 | - abi_long buf; | |
| 2041 | - unsigned short int *array; | |
| 2076 | + abi_ulong buf; | |
| 2077 | + abi_ulong array; | |
| 2078 | + abi_ulong __buf; | |
| 2042 | 2079 | }; |
| 2043 | 2080 | |
| 2044 | -static inline abi_long target_to_host_semun(int cmd, | |
| 2045 | - union semun *host_su, | |
| 2046 | - abi_ulong target_addr, | |
| 2047 | - struct semid_ds *ds) | |
| 2081 | +static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array, | |
| 2082 | + abi_ulong target_addr) | |
| 2048 | 2083 | { |
| 2049 | - union target_semun *target_su; | |
| 2084 | + int nsems; | |
| 2085 | + unsigned short *array; | |
| 2086 | + union semun semun; | |
| 2087 | + struct semid_ds semid_ds; | |
| 2088 | + int i, ret; | |
| 2050 | 2089 | |
| 2051 | - switch( cmd ) { | |
| 2052 | - case IPC_STAT: | |
| 2053 | - case IPC_SET: | |
| 2054 | - if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) | |
| 2055 | - return -TARGET_EFAULT; | |
| 2056 | - target_to_host_semid_ds(ds,target_su->buf); | |
| 2057 | - host_su->buf = ds; | |
| 2058 | - unlock_user_struct(target_su, target_addr, 0); | |
| 2059 | - break; | |
| 2060 | - case GETVAL: | |
| 2061 | - case SETVAL: | |
| 2062 | - if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) | |
| 2063 | - return -TARGET_EFAULT; | |
| 2064 | - host_su->val = tswapl(target_su->val); | |
| 2065 | - unlock_user_struct(target_su, target_addr, 0); | |
| 2066 | - break; | |
| 2067 | - case GETALL: | |
| 2068 | - case SETALL: | |
| 2069 | - if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) | |
| 2070 | - return -TARGET_EFAULT; | |
| 2071 | - *host_su->array = tswap16(*target_su->array); | |
| 2072 | - unlock_user_struct(target_su, target_addr, 0); | |
| 2073 | - break; | |
| 2074 | - default: | |
| 2075 | - gemu_log("semun operation not fully supported: %d\n", (int)cmd); | |
| 2090 | + semun.buf = &semid_ds; | |
| 2091 | + | |
| 2092 | + ret = semctl(semid, 0, IPC_STAT, semun); | |
| 2093 | + if (ret == -1) | |
| 2094 | + return get_errno(ret); | |
| 2095 | + | |
| 2096 | + nsems = semid_ds.sem_nsems; | |
| 2097 | + | |
| 2098 | + *host_array = malloc(nsems*sizeof(unsigned short)); | |
| 2099 | + array = lock_user(VERIFY_READ, target_addr, | |
| 2100 | + nsems*sizeof(unsigned short), 1); | |
| 2101 | + if (!array) | |
| 2102 | + return -TARGET_EFAULT; | |
| 2103 | + | |
| 2104 | + for(i=0; i<nsems; i++) { | |
| 2105 | + __get_user((*host_array)[i], &array[i]); | |
| 2076 | 2106 | } |
| 2107 | + unlock_user(array, target_addr, 0); | |
| 2108 | + | |
| 2077 | 2109 | return 0; |
| 2078 | 2110 | } |
| 2079 | 2111 | |
| 2080 | -static inline abi_long host_to_target_semun(int cmd, | |
| 2081 | - abi_ulong target_addr, | |
| 2082 | - union semun *host_su, | |
| 2083 | - struct semid_ds *ds) | |
| 2112 | +static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr, | |
| 2113 | + unsigned short **host_array) | |
| 2084 | 2114 | { |
| 2085 | - union target_semun *target_su; | |
| 2115 | + int nsems; | |
| 2116 | + unsigned short *array; | |
| 2117 | + union semun semun; | |
| 2118 | + struct semid_ds semid_ds; | |
| 2119 | + int i, ret; | |
| 2086 | 2120 | |
| 2087 | - switch( cmd ) { | |
| 2088 | - case IPC_STAT: | |
| 2089 | - case IPC_SET: | |
| 2090 | - if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) | |
| 2091 | - return -TARGET_EFAULT; | |
| 2092 | - host_to_target_semid_ds(target_su->buf,ds); | |
| 2093 | - unlock_user_struct(target_su, target_addr, 1); | |
| 2094 | - break; | |
| 2095 | - case GETVAL: | |
| 2096 | - case SETVAL: | |
| 2097 | - if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) | |
| 2098 | - return -TARGET_EFAULT; | |
| 2099 | - target_su->val = tswapl(host_su->val); | |
| 2100 | - unlock_user_struct(target_su, target_addr, 1); | |
| 2101 | - break; | |
| 2102 | - case GETALL: | |
| 2103 | - case SETALL: | |
| 2104 | - if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) | |
| 2105 | - return -TARGET_EFAULT; | |
| 2106 | - *target_su->array = tswap16(*host_su->array); | |
| 2107 | - unlock_user_struct(target_su, target_addr, 1); | |
| 2108 | - break; | |
| 2109 | - default: | |
| 2110 | - gemu_log("semun operation not fully supported: %d\n", (int)cmd); | |
| 2121 | + semun.buf = &semid_ds; | |
| 2122 | + | |
| 2123 | + ret = semctl(semid, 0, IPC_STAT, semun); | |
| 2124 | + if (ret == -1) | |
| 2125 | + return get_errno(ret); | |
| 2126 | + | |
| 2127 | + nsems = semid_ds.sem_nsems; | |
| 2128 | + | |
| 2129 | + array = lock_user(VERIFY_WRITE, target_addr, | |
| 2130 | + nsems*sizeof(unsigned short), 0); | |
| 2131 | + if (!array) | |
| 2132 | + return -TARGET_EFAULT; | |
| 2133 | + | |
| 2134 | + for(i=0; i<nsems; i++) { | |
| 2135 | + __put_user((*host_array)[i], &array[i]); | |
| 2111 | 2136 | } |
| 2137 | + free(*host_array); | |
| 2138 | + unlock_user(array, target_addr, 1); | |
| 2139 | + | |
| 2112 | 2140 | return 0; |
| 2113 | 2141 | } |
| 2114 | 2142 | |
| 2115 | -static inline abi_long do_semctl(int first, int second, int third, | |
| 2116 | - abi_long ptr) | |
| 2143 | +static inline abi_long do_semctl(int semid, int semnum, int cmd, | |
| 2144 | + union target_semun target_su) | |
| 2117 | 2145 | { |
| 2118 | 2146 | union semun arg; |
| 2119 | 2147 | struct semid_ds dsarg; |
| 2120 | - int cmd = third&0xff; | |
| 2121 | - abi_long ret = 0; | |
| 2148 | + unsigned short *array; | |
| 2149 | + struct seminfo seminfo; | |
| 2150 | + abi_long ret = -TARGET_EINVAL; | |
| 2151 | + abi_long err; | |
| 2152 | + cmd &= 0xff; | |
| 2122 | 2153 | |
| 2123 | 2154 | switch( cmd ) { |
| 2124 | 2155 | case GETVAL: |
| 2125 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2126 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2127 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2128 | - break; | |
| 2129 | 2156 | case SETVAL: |
| 2130 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2131 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2132 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2157 | + arg.val = tswapl(target_su.val); | |
| 2158 | + ret = get_errno(semctl(semid, semnum, cmd, arg)); | |
| 2159 | + target_su.val = tswapl(arg.val); | |
| 2133 | 2160 | break; |
| 2134 | 2161 | case GETALL: |
| 2135 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2136 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2137 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2138 | - break; | |
| 2139 | 2162 | case SETALL: |
| 2140 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2141 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2142 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2163 | + err = target_to_host_semarray(semid, &array, target_su.array); | |
| 2164 | + if (err) | |
| 2165 | + return err; | |
| 2166 | + arg.array = array; | |
| 2167 | + ret = get_errno(semctl(semid, semnum, cmd, arg)); | |
| 2168 | + err = host_to_target_semarray(semid, target_su.array, &array); | |
| 2169 | + if (err) | |
| 2170 | + return err; | |
| 2143 | 2171 | break; |
| 2144 | 2172 | case IPC_STAT: |
| 2145 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2146 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2147 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2148 | - break; | |
| 2149 | 2173 | case IPC_SET: |
| 2150 | - target_to_host_semun(cmd,&arg,ptr,&dsarg); | |
| 2151 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2152 | - host_to_target_semun(cmd,ptr,&arg,&dsarg); | |
| 2174 | + case SEM_STAT: | |
| 2175 | + err = target_to_host_semid_ds(&dsarg, target_su.buf); | |
| 2176 | + if (err) | |
| 2177 | + return err; | |
| 2178 | + arg.buf = &dsarg; | |
| 2179 | + ret = get_errno(semctl(semid, semnum, cmd, arg)); | |
| 2180 | + err = host_to_target_semid_ds(target_su.buf, &dsarg); | |
| 2181 | + if (err) | |
| 2182 | + return err; | |
| 2183 | + break; | |
| 2184 | + case IPC_INFO: | |
| 2185 | + case SEM_INFO: | |
| 2186 | + arg.__buf = &seminfo; | |
| 2187 | + ret = get_errno(semctl(semid, semnum, cmd, arg)); | |
| 2188 | + err = host_to_target_seminfo(target_su.__buf, &seminfo); | |
| 2189 | + if (err) | |
| 2190 | + return err; | |
| 2191 | + break; | |
| 2192 | + case IPC_RMID: | |
| 2193 | + case GETPID: | |
| 2194 | + case GETNCNT: | |
| 2195 | + case GETZCNT: | |
| 2196 | + ret = get_errno(semctl(semid, semnum, cmd, NULL)); | |
| 2153 | 2197 | break; |
| 2154 | - default: | |
| 2155 | - ret = get_errno(semctl(first, second, cmd, arg)); | |
| 2156 | 2198 | } |
| 2157 | 2199 | |
| 2158 | 2200 | return ret; |
| 2159 | 2201 | } |
| 2160 | 2202 | |
| 2203 | +struct target_sembuf { | |
| 2204 | + unsigned short sem_num; | |
| 2205 | + short sem_op; | |
| 2206 | + short sem_flg; | |
| 2207 | +}; | |
| 2208 | + | |
| 2209 | +static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf, | |
| 2210 | + abi_ulong target_addr, | |
| 2211 | + unsigned nsops) | |
| 2212 | +{ | |
| 2213 | + struct target_sembuf *target_sembuf; | |
| 2214 | + int i; | |
| 2215 | + | |
| 2216 | + target_sembuf = lock_user(VERIFY_READ, target_addr, | |
| 2217 | + nsops*sizeof(struct target_sembuf), 1); | |
| 2218 | + if (!target_sembuf) | |
| 2219 | + return -TARGET_EFAULT; | |
| 2220 | + | |
| 2221 | + for(i=0; i<nsops; i++) { | |
| 2222 | + __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num); | |
| 2223 | + __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op); | |
| 2224 | + __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg); | |
| 2225 | + } | |
| 2226 | + | |
| 2227 | + unlock_user(target_sembuf, target_addr, 0); | |
| 2228 | + | |
| 2229 | + return 0; | |
| 2230 | +} | |
| 2231 | + | |
| 2232 | +static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops) | |
| 2233 | +{ | |
| 2234 | + struct sembuf sops[nsops]; | |
| 2235 | + | |
| 2236 | + if (target_to_host_sembuf(sops, ptr, nsops)) | |
| 2237 | + return -TARGET_EFAULT; | |
| 2238 | + | |
| 2239 | + return semop(semid, sops, nsops); | |
| 2240 | +} | |
| 2241 | + | |
| 2161 | 2242 | struct target_msqid_ds |
| 2162 | 2243 | { |
| 2163 | 2244 | struct target_ipc_perm msg_perm; |
| ... | ... | @@ -2361,7 +2442,7 @@ static abi_long do_ipc(unsigned int call, int first, |
| 2361 | 2442 | |
| 2362 | 2443 | switch (call) { |
| 2363 | 2444 | case IPCOP_semop: |
| 2364 | - ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); | |
| 2445 | + ret = do_semop(first, ptr, second); | |
| 2365 | 2446 | break; |
| 2366 | 2447 | |
| 2367 | 2448 | case IPCOP_semget: |
| ... | ... | @@ -2369,12 +2450,7 @@ static abi_long do_ipc(unsigned int call, int first, |
| 2369 | 2450 | break; |
| 2370 | 2451 | |
| 2371 | 2452 | case IPCOP_semctl: |
| 2372 | - ret = do_semctl(first, second, third, ptr); | |
| 2373 | - break; | |
| 2374 | - | |
| 2375 | - case IPCOP_semtimedop: | |
| 2376 | - gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); | |
| 2377 | - ret = -TARGET_ENOSYS; | |
| 2453 | + ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); | |
| 2378 | 2454 | break; |
| 2379 | 2455 | |
| 2380 | 2456 | case IPCOP_msgget: |
| ... | ... | @@ -5200,7 +5276,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, |
| 5200 | 5276 | ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); |
| 5201 | 5277 | break; |
| 5202 | 5278 | #endif |
| 5203 | - | |
| 5279 | +#ifdef TARGET_NR_semget | |
| 5280 | + case TARGET_NR_semget: | |
| 5281 | + ret = get_errno(semget(arg1, arg2, arg3)); | |
| 5282 | + break; | |
| 5283 | +#endif | |
| 5284 | +#ifdef TARGET_NR_semop | |
| 5285 | + case TARGET_NR_semop: | |
| 5286 | + ret = get_errno(do_semop(arg1, arg2, arg3)); | |
| 5287 | + break; | |
| 5288 | +#endif | |
| 5289 | +#ifdef TARGET_NR_semctl | |
| 5290 | + case TARGET_NR_semctl: | |
| 5291 | + ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); | |
| 5292 | + break; | |
| 5293 | +#endif | |
| 5204 | 5294 | #ifdef TARGET_NR_msgctl |
| 5205 | 5295 | case TARGET_NR_msgctl: |
| 5206 | 5296 | ret = do_msgctl(arg1, arg2, arg3); | ... | ... |