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 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);
... ...