Commit e5289087edbb66ac02729211ec46cfb7acbd5f1c

Authored by aurel32
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);