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,7 +2006,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, | ||
| 2006 | 2006 | ||
| 2007 | if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) | 2007 | if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) |
| 2008 | return -TARGET_EFAULT; | 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 | host_sd->sem_nsems = tswapl(target_sd->sem_nsems); | 2011 | host_sd->sem_nsems = tswapl(target_sd->sem_nsems); |
| 2011 | host_sd->sem_otime = tswapl(target_sd->sem_otime); | 2012 | host_sd->sem_otime = tswapl(target_sd->sem_otime); |
| 2012 | host_sd->sem_ctime = tswapl(target_sd->sem_ctime); | 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,7 +2022,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, | ||
| 2021 | 2022 | ||
| 2022 | if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) | 2023 | if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) |
| 2023 | return -TARGET_EFAULT; | 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 | target_sd->sem_nsems = tswapl(host_sd->sem_nsems); | 2027 | target_sd->sem_nsems = tswapl(host_sd->sem_nsems); |
| 2026 | target_sd->sem_otime = tswapl(host_sd->sem_otime); | 2028 | target_sd->sem_otime = tswapl(host_sd->sem_otime); |
| 2027 | target_sd->sem_ctime = tswapl(host_sd->sem_ctime); | 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,135 +2031,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, | ||
| 2029 | return 0; | 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 | union semun { | 2067 | union semun { |
| 2033 | int val; | 2068 | int val; |
| 2034 | struct semid_ds *buf; | 2069 | struct semid_ds *buf; |
| 2035 | unsigned short *array; | 2070 | unsigned short *array; |
| 2071 | + struct seminfo *__buf; | ||
| 2036 | }; | 2072 | }; |
| 2037 | 2073 | ||
| 2038 | union target_semun { | 2074 | union target_semun { |
| 2039 | int val; | 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 | return 0; | 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 | return 0; | 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 | union semun arg; | 2146 | union semun arg; |
| 2119 | struct semid_ds dsarg; | 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 | switch( cmd ) { | 2154 | switch( cmd ) { |
| 2124 | case GETVAL: | 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 | case SETVAL: | 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 | break; | 2160 | break; |
| 2134 | case GETALL: | 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 | case SETALL: | 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 | break; | 2171 | break; |
| 2144 | case IPC_STAT: | 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 | case IPC_SET: | 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 | break; | 2197 | break; |
| 2154 | - default: | ||
| 2155 | - ret = get_errno(semctl(first, second, cmd, arg)); | ||
| 2156 | } | 2198 | } |
| 2157 | 2199 | ||
| 2158 | return ret; | 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 | struct target_msqid_ds | 2242 | struct target_msqid_ds |
| 2162 | { | 2243 | { |
| 2163 | struct target_ipc_perm msg_perm; | 2244 | struct target_ipc_perm msg_perm; |
| @@ -2361,7 +2442,7 @@ static abi_long do_ipc(unsigned int call, int first, | @@ -2361,7 +2442,7 @@ static abi_long do_ipc(unsigned int call, int first, | ||
| 2361 | 2442 | ||
| 2362 | switch (call) { | 2443 | switch (call) { |
| 2363 | case IPCOP_semop: | 2444 | case IPCOP_semop: |
| 2364 | - ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); | 2445 | + ret = do_semop(first, ptr, second); |
| 2365 | break; | 2446 | break; |
| 2366 | 2447 | ||
| 2367 | case IPCOP_semget: | 2448 | case IPCOP_semget: |
| @@ -2369,12 +2450,7 @@ static abi_long do_ipc(unsigned int call, int first, | @@ -2369,12 +2450,7 @@ static abi_long do_ipc(unsigned int call, int first, | ||
| 2369 | break; | 2450 | break; |
| 2370 | 2451 | ||
| 2371 | case IPCOP_semctl: | 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 | break; | 2454 | break; |
| 2379 | 2455 | ||
| 2380 | case IPCOP_msgget: | 2456 | case IPCOP_msgget: |
| @@ -5200,7 +5276,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | @@ -5200,7 +5276,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | ||
| 5200 | ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); | 5276 | ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); |
| 5201 | break; | 5277 | break; |
| 5202 | #endif | 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 | #ifdef TARGET_NR_msgctl | 5294 | #ifdef TARGET_NR_msgctl |
| 5205 | case TARGET_NR_msgctl: | 5295 | case TARGET_NR_msgctl: |
| 5206 | ret = do_msgctl(arg1, arg2, arg3); | 5296 | ret = do_msgctl(arg1, arg2, arg3); |