|
1 /* |
|
2 * Linux syscalls |
|
3 * |
|
4 * Copyright (c) 2003 Fabrice Bellard |
|
5 * |
|
6 * This program is free software; you can redistribute it and/or modify |
|
7 * it under the terms of the GNU General Public License as published by |
|
8 * the Free Software Foundation; either version 2 of the License, or |
|
9 * (at your option) any later version. |
|
10 * |
|
11 * This program is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 * GNU General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU General Public License |
|
17 * along with this program; if not, write to the Free Software |
|
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 */ |
|
20 #include <stdlib.h> |
|
21 #include <stdio.h> |
|
22 #include <stdarg.h> |
|
23 #include <string.h> |
|
24 #include <elf.h> |
|
25 #include <endian.h> |
|
26 #include <errno.h> |
|
27 #include <unistd.h> |
|
28 #include <fcntl.h> |
|
29 #include <time.h> |
|
30 #include <limits.h> |
|
31 #include <sys/types.h> |
|
32 #include <sys/ipc.h> |
|
33 #include <sys/msg.h> |
|
34 #include <sys/wait.h> |
|
35 #include <sys/time.h> |
|
36 #include <sys/stat.h> |
|
37 #include <sys/mount.h> |
|
38 #include <sys/prctl.h> |
|
39 #include <sys/resource.h> |
|
40 #include <sys/mman.h> |
|
41 #include <sys/swap.h> |
|
42 #include <signal.h> |
|
43 #include <sched.h> |
|
44 #include <sys/socket.h> |
|
45 #include <sys/uio.h> |
|
46 #include <sys/poll.h> |
|
47 #include <sys/times.h> |
|
48 #include <sys/shm.h> |
|
49 #include <sys/sem.h> |
|
50 #include <sys/statfs.h> |
|
51 #include <utime.h> |
|
52 #include <sys/sysinfo.h> |
|
53 //#include <sys/user.h> |
|
54 #include <netinet/ip.h> |
|
55 #include <netinet/tcp.h> |
|
56 #include <qemu-common.h> |
|
57 #ifdef HAVE_GPROF |
|
58 #include <sys/gmon.h> |
|
59 #endif |
|
60 |
|
61 #define termios host_termios |
|
62 #define winsize host_winsize |
|
63 #define termio host_termio |
|
64 #define sgttyb host_sgttyb /* same as target */ |
|
65 #define tchars host_tchars /* same as target */ |
|
66 #define ltchars host_ltchars /* same as target */ |
|
67 |
|
68 #include <linux/termios.h> |
|
69 #include <linux/unistd.h> |
|
70 #include <linux/utsname.h> |
|
71 #include <linux/cdrom.h> |
|
72 #include <linux/hdreg.h> |
|
73 #include <linux/soundcard.h> |
|
74 #include <linux/kd.h> |
|
75 #include <linux/mtio.h> |
|
76 #include "linux_loop.h" |
|
77 |
|
78 #include "qemu.h" |
|
79 #include "qemu-common.h" |
|
80 |
|
81 #if defined(USE_NPTL) |
|
82 #include <linux/futex.h> |
|
83 #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ |
|
84 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) |
|
85 #else |
|
86 /* XXX: Hardcode the above values. */ |
|
87 #define CLONE_NPTL_FLAGS2 0 |
|
88 #endif |
|
89 |
|
90 //#define DEBUG |
|
91 |
|
92 #ifdef USE_NPTL |
|
93 #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ |
|
94 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) |
|
95 #else |
|
96 /* XXX: Hardcode the above values. */ |
|
97 #define CLONE_NPTL_FLAGS2 0 |
|
98 #endif |
|
99 |
|
100 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ |
|
101 || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) |
|
102 /* 16 bit uid wrappers emulation */ |
|
103 #define USE_UID16 |
|
104 #endif |
|
105 |
|
106 //#include <linux/msdos_fs.h> |
|
107 #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2]) |
|
108 #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2]) |
|
109 |
|
110 #define TARGET_PROT_GROWSDOWN 0x01000000 |
|
111 |
|
112 #undef _syscall0 |
|
113 #undef _syscall1 |
|
114 #undef _syscall2 |
|
115 #undef _syscall3 |
|
116 #undef _syscall4 |
|
117 #undef _syscall5 |
|
118 #undef _syscall6 |
|
119 |
|
120 #define _syscall0(type,name) \ |
|
121 static type name (void) \ |
|
122 { \ |
|
123 return syscall(__NR_##name); \ |
|
124 } |
|
125 |
|
126 #define _syscall1(type,name,type1,arg1) \ |
|
127 static type name (type1 arg1) \ |
|
128 { \ |
|
129 return syscall(__NR_##name, arg1); \ |
|
130 } |
|
131 |
|
132 #define _syscall2(type,name,type1,arg1,type2,arg2) \ |
|
133 static type name (type1 arg1,type2 arg2) \ |
|
134 { \ |
|
135 return syscall(__NR_##name, arg1, arg2); \ |
|
136 } |
|
137 |
|
138 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ |
|
139 static type name (type1 arg1,type2 arg2,type3 arg3) \ |
|
140 { \ |
|
141 return syscall(__NR_##name, arg1, arg2, arg3); \ |
|
142 } |
|
143 |
|
144 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ |
|
145 static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ |
|
146 { \ |
|
147 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ |
|
148 } |
|
149 |
|
150 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ |
|
151 type5,arg5) \ |
|
152 static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ |
|
153 { \ |
|
154 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ |
|
155 } |
|
156 |
|
157 |
|
158 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ |
|
159 type5,arg5,type6,arg6) \ |
|
160 static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ |
|
161 type6 arg6) \ |
|
162 { \ |
|
163 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ |
|
164 } |
|
165 |
|
166 |
|
167 #define __NR_sys_exit __NR_exit |
|
168 #define __NR_sys_uname __NR_uname |
|
169 #define __NR_sys_faccessat __NR_faccessat |
|
170 #define __NR_sys_fchmodat __NR_fchmodat |
|
171 #define __NR_sys_fchownat __NR_fchownat |
|
172 #define __NR_sys_fstatat64 __NR_fstatat64 |
|
173 #define __NR_sys_futimesat __NR_futimesat |
|
174 #define __NR_sys_getcwd1 __NR_getcwd |
|
175 #define __NR_sys_getdents __NR_getdents |
|
176 #define __NR_sys_getdents64 __NR_getdents64 |
|
177 #define __NR_sys_getpriority __NR_getpriority |
|
178 #define __NR_sys_linkat __NR_linkat |
|
179 #define __NR_sys_mkdirat __NR_mkdirat |
|
180 #define __NR_sys_mknodat __NR_mknodat |
|
181 #define __NR_sys_openat __NR_openat |
|
182 #define __NR_sys_readlinkat __NR_readlinkat |
|
183 #define __NR_sys_renameat __NR_renameat |
|
184 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo |
|
185 #define __NR_sys_symlinkat __NR_symlinkat |
|
186 #define __NR_sys_syslog __NR_syslog |
|
187 #define __NR_sys_tgkill __NR_tgkill |
|
188 #define __NR_sys_tkill __NR_tkill |
|
189 #define __NR_sys_unlinkat __NR_unlinkat |
|
190 #define __NR_sys_utimensat __NR_utimensat |
|
191 #define __NR_sys_futex __NR_futex |
|
192 #define __NR_sys_inotify_init __NR_inotify_init |
|
193 #define __NR_sys_inotify_add_watch __NR_inotify_add_watch |
|
194 #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch |
|
195 |
|
196 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) |
|
197 #define __NR__llseek __NR_lseek |
|
198 #endif |
|
199 |
|
200 #ifdef __NR_gettid |
|
201 _syscall0(int, gettid) |
|
202 #else |
|
203 /* This is a replacement for the host gettid() and must return a host |
|
204 errno. */ |
|
205 static int gettid(void) { |
|
206 return -ENOSYS; |
|
207 } |
|
208 #endif |
|
209 _syscall1(int,sys_exit,int,status) |
|
210 _syscall1(int,sys_uname,struct new_utsname *,buf) |
|
211 #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) |
|
212 _syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags) |
|
213 #endif |
|
214 #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) |
|
215 _syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname, |
|
216 mode_t,mode,int,flags) |
|
217 #endif |
|
218 #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16) |
|
219 _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, |
|
220 uid_t,owner,gid_t,group,int,flags) |
|
221 #endif |
|
222 #if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64) |
|
223 _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname, |
|
224 struct stat *,buf,int,flags) |
|
225 #endif |
|
226 #if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) |
|
227 _syscall3(int,sys_futimesat,int,dirfd,const char *,pathname, |
|
228 const struct timeval *,times) |
|
229 #endif |
|
230 _syscall2(int,sys_getcwd1,char *,buf,size_t,size) |
|
231 #if TARGET_ABI_BITS == 32 |
|
232 _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count); |
|
233 #endif |
|
234 #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) |
|
235 _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count); |
|
236 #endif |
|
237 _syscall2(int, sys_getpriority, int, which, int, who); |
|
238 #if !defined (__x86_64__) |
|
239 _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, |
|
240 loff_t *, res, uint, wh); |
|
241 #endif |
|
242 #if defined(TARGET_NR_linkat) && defined(__NR_linkat) |
|
243 _syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath, |
|
244 int,newdirfd,const char *,newpath,int,flags) |
|
245 #endif |
|
246 #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) |
|
247 _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode) |
|
248 #endif |
|
249 #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) |
|
250 _syscall4(int,sys_mknodat,int,dirfd,const char *,pathname, |
|
251 mode_t,mode,dev_t,dev) |
|
252 #endif |
|
253 #if defined(TARGET_NR_openat) && defined(__NR_openat) |
|
254 _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) |
|
255 #endif |
|
256 #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) |
|
257 _syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname, |
|
258 char *,buf,size_t,bufsize) |
|
259 #endif |
|
260 #if defined(TARGET_NR_renameat) && defined(__NR_renameat) |
|
261 _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, |
|
262 int,newdirfd,const char *,newpath) |
|
263 #endif |
|
264 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) |
|
265 #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) |
|
266 _syscall3(int,sys_symlinkat,const char *,oldpath, |
|
267 int,newdirfd,const char *,newpath) |
|
268 #endif |
|
269 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) |
|
270 #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) |
|
271 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) |
|
272 #endif |
|
273 #if defined(TARGET_NR_tkill) && defined(__NR_tkill) |
|
274 _syscall2(int,sys_tkill,int,tid,int,sig) |
|
275 #endif |
|
276 #ifdef __NR_exit_group |
|
277 _syscall1(int,exit_group,int,error_code) |
|
278 #endif |
|
279 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) |
|
280 _syscall1(int,set_tid_address,int *,tidptr) |
|
281 #endif |
|
282 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) |
|
283 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) |
|
284 #endif |
|
285 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) |
|
286 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, |
|
287 const struct timespec *,tsp,int,flags) |
|
288 #endif |
|
289 #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init) |
|
290 _syscall0(int,sys_inotify_init) |
|
291 #endif |
|
292 #if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch) |
|
293 _syscall3(int,sys_inotify_add_watch,int,fd,const char *,pathname,uint32_t,mask) |
|
294 #endif |
|
295 #if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch) |
|
296 _syscall2(int,sys_inotify_rm_watch,int,fd,uint32_t,wd) |
|
297 #endif |
|
298 #if defined(USE_NPTL) |
|
299 #if defined(TARGET_NR_futex) && defined(__NR_futex) |
|
300 _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, |
|
301 const struct timespec *,timeout,int *,uaddr2,int,val3) |
|
302 #endif |
|
303 #endif |
|
304 |
|
305 extern int personality(int); |
|
306 extern int flock(int, int); |
|
307 extern int setfsuid(int); |
|
308 extern int setfsgid(int); |
|
309 extern int setgroups(int, gid_t *); |
|
310 |
|
311 #define ERRNO_TABLE_SIZE 1200 |
|
312 |
|
313 /* target_to_host_errno_table[] is initialized from |
|
314 * host_to_target_errno_table[] in syscall_init(). */ |
|
315 static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = { |
|
316 }; |
|
317 |
|
318 /* |
|
319 * This list is the union of errno values overridden in asm-<arch>/errno.h |
|
320 * minus the errnos that are not actually generic to all archs. |
|
321 */ |
|
322 static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { |
|
323 [EIDRM] = TARGET_EIDRM, |
|
324 [ECHRNG] = TARGET_ECHRNG, |
|
325 [EL2NSYNC] = TARGET_EL2NSYNC, |
|
326 [EL3HLT] = TARGET_EL3HLT, |
|
327 [EL3RST] = TARGET_EL3RST, |
|
328 [ELNRNG] = TARGET_ELNRNG, |
|
329 [EUNATCH] = TARGET_EUNATCH, |
|
330 [ENOCSI] = TARGET_ENOCSI, |
|
331 [EL2HLT] = TARGET_EL2HLT, |
|
332 [EDEADLK] = TARGET_EDEADLK, |
|
333 [ENOLCK] = TARGET_ENOLCK, |
|
334 [EBADE] = TARGET_EBADE, |
|
335 [EBADR] = TARGET_EBADR, |
|
336 [EXFULL] = TARGET_EXFULL, |
|
337 [ENOANO] = TARGET_ENOANO, |
|
338 [EBADRQC] = TARGET_EBADRQC, |
|
339 [EBADSLT] = TARGET_EBADSLT, |
|
340 [EBFONT] = TARGET_EBFONT, |
|
341 [ENOSTR] = TARGET_ENOSTR, |
|
342 [ENODATA] = TARGET_ENODATA, |
|
343 [ETIME] = TARGET_ETIME, |
|
344 [ENOSR] = TARGET_ENOSR, |
|
345 [ENONET] = TARGET_ENONET, |
|
346 [ENOPKG] = TARGET_ENOPKG, |
|
347 [EREMOTE] = TARGET_EREMOTE, |
|
348 [ENOLINK] = TARGET_ENOLINK, |
|
349 [EADV] = TARGET_EADV, |
|
350 [ESRMNT] = TARGET_ESRMNT, |
|
351 [ECOMM] = TARGET_ECOMM, |
|
352 [EPROTO] = TARGET_EPROTO, |
|
353 [EDOTDOT] = TARGET_EDOTDOT, |
|
354 [EMULTIHOP] = TARGET_EMULTIHOP, |
|
355 [EBADMSG] = TARGET_EBADMSG, |
|
356 [ENAMETOOLONG] = TARGET_ENAMETOOLONG, |
|
357 [EOVERFLOW] = TARGET_EOVERFLOW, |
|
358 [ENOTUNIQ] = TARGET_ENOTUNIQ, |
|
359 [EBADFD] = TARGET_EBADFD, |
|
360 [EREMCHG] = TARGET_EREMCHG, |
|
361 [ELIBACC] = TARGET_ELIBACC, |
|
362 [ELIBBAD] = TARGET_ELIBBAD, |
|
363 [ELIBSCN] = TARGET_ELIBSCN, |
|
364 [ELIBMAX] = TARGET_ELIBMAX, |
|
365 [ELIBEXEC] = TARGET_ELIBEXEC, |
|
366 [EILSEQ] = TARGET_EILSEQ, |
|
367 [ENOSYS] = TARGET_ENOSYS, |
|
368 [ELOOP] = TARGET_ELOOP, |
|
369 [ERESTART] = TARGET_ERESTART, |
|
370 [ESTRPIPE] = TARGET_ESTRPIPE, |
|
371 [ENOTEMPTY] = TARGET_ENOTEMPTY, |
|
372 [EUSERS] = TARGET_EUSERS, |
|
373 [ENOTSOCK] = TARGET_ENOTSOCK, |
|
374 [EDESTADDRREQ] = TARGET_EDESTADDRREQ, |
|
375 [EMSGSIZE] = TARGET_EMSGSIZE, |
|
376 [EPROTOTYPE] = TARGET_EPROTOTYPE, |
|
377 [ENOPROTOOPT] = TARGET_ENOPROTOOPT, |
|
378 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT, |
|
379 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT, |
|
380 [EOPNOTSUPP] = TARGET_EOPNOTSUPP, |
|
381 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT, |
|
382 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT, |
|
383 [EADDRINUSE] = TARGET_EADDRINUSE, |
|
384 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL, |
|
385 [ENETDOWN] = TARGET_ENETDOWN, |
|
386 [ENETUNREACH] = TARGET_ENETUNREACH, |
|
387 [ENETRESET] = TARGET_ENETRESET, |
|
388 [ECONNABORTED] = TARGET_ECONNABORTED, |
|
389 [ECONNRESET] = TARGET_ECONNRESET, |
|
390 [ENOBUFS] = TARGET_ENOBUFS, |
|
391 [EISCONN] = TARGET_EISCONN, |
|
392 [ENOTCONN] = TARGET_ENOTCONN, |
|
393 [EUCLEAN] = TARGET_EUCLEAN, |
|
394 [ENOTNAM] = TARGET_ENOTNAM, |
|
395 [ENAVAIL] = TARGET_ENAVAIL, |
|
396 [EISNAM] = TARGET_EISNAM, |
|
397 [EREMOTEIO] = TARGET_EREMOTEIO, |
|
398 [ESHUTDOWN] = TARGET_ESHUTDOWN, |
|
399 [ETOOMANYREFS] = TARGET_ETOOMANYREFS, |
|
400 [ETIMEDOUT] = TARGET_ETIMEDOUT, |
|
401 [ECONNREFUSED] = TARGET_ECONNREFUSED, |
|
402 [EHOSTDOWN] = TARGET_EHOSTDOWN, |
|
403 [EHOSTUNREACH] = TARGET_EHOSTUNREACH, |
|
404 [EALREADY] = TARGET_EALREADY, |
|
405 [EINPROGRESS] = TARGET_EINPROGRESS, |
|
406 [ESTALE] = TARGET_ESTALE, |
|
407 [ECANCELED] = TARGET_ECANCELED, |
|
408 [ENOMEDIUM] = TARGET_ENOMEDIUM, |
|
409 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE, |
|
410 #ifdef ENOKEY |
|
411 [ENOKEY] = TARGET_ENOKEY, |
|
412 #endif |
|
413 #ifdef EKEYEXPIRED |
|
414 [EKEYEXPIRED] = TARGET_EKEYEXPIRED, |
|
415 #endif |
|
416 #ifdef EKEYREVOKED |
|
417 [EKEYREVOKED] = TARGET_EKEYREVOKED, |
|
418 #endif |
|
419 #ifdef EKEYREJECTED |
|
420 [EKEYREJECTED] = TARGET_EKEYREJECTED, |
|
421 #endif |
|
422 #ifdef EOWNERDEAD |
|
423 [EOWNERDEAD] = TARGET_EOWNERDEAD, |
|
424 #endif |
|
425 #ifdef ENOTRECOVERABLE |
|
426 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, |
|
427 #endif |
|
428 }; |
|
429 |
|
430 static inline int host_to_target_errno(int err) |
|
431 { |
|
432 if(host_to_target_errno_table[err]) |
|
433 return host_to_target_errno_table[err]; |
|
434 return err; |
|
435 } |
|
436 |
|
437 static inline int target_to_host_errno(int err) |
|
438 { |
|
439 if (target_to_host_errno_table[err]) |
|
440 return target_to_host_errno_table[err]; |
|
441 return err; |
|
442 } |
|
443 |
|
444 static inline abi_long get_errno(abi_long ret) |
|
445 { |
|
446 if (ret == -1) |
|
447 return -host_to_target_errno(errno); |
|
448 else |
|
449 return ret; |
|
450 } |
|
451 |
|
452 static inline int is_error(abi_long ret) |
|
453 { |
|
454 return (abi_ulong)ret >= (abi_ulong)(-4096); |
|
455 } |
|
456 |
|
457 char *target_strerror(int err) |
|
458 { |
|
459 return strerror(target_to_host_errno(err)); |
|
460 } |
|
461 |
|
462 static abi_ulong target_brk; |
|
463 static abi_ulong target_original_brk; |
|
464 |
|
465 void target_set_brk(abi_ulong new_brk) |
|
466 { |
|
467 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); |
|
468 } |
|
469 |
|
470 /* do_brk() must return target values and target errnos. */ |
|
471 abi_long do_brk(abi_ulong new_brk) |
|
472 { |
|
473 abi_ulong brk_page; |
|
474 abi_long mapped_addr; |
|
475 int new_alloc_size; |
|
476 |
|
477 if (!new_brk) |
|
478 return target_brk; |
|
479 if (new_brk < target_original_brk) |
|
480 return target_brk; |
|
481 |
|
482 brk_page = HOST_PAGE_ALIGN(target_brk); |
|
483 |
|
484 /* If the new brk is less than this, set it and we're done... */ |
|
485 if (new_brk < brk_page) { |
|
486 target_brk = new_brk; |
|
487 return target_brk; |
|
488 } |
|
489 |
|
490 /* We need to allocate more memory after the brk... */ |
|
491 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); |
|
492 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, |
|
493 PROT_READ|PROT_WRITE, |
|
494 MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); |
|
495 |
|
496 if (!is_error(mapped_addr)) |
|
497 target_brk = new_brk; |
|
498 |
|
499 return target_brk; |
|
500 } |
|
501 |
|
502 static inline abi_long copy_from_user_fdset(fd_set *fds, |
|
503 abi_ulong target_fds_addr, |
|
504 int n) |
|
505 { |
|
506 int i, nw, j, k; |
|
507 abi_ulong b, *target_fds; |
|
508 |
|
509 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; |
|
510 if (!(target_fds = lock_user(VERIFY_READ, |
|
511 target_fds_addr, |
|
512 sizeof(abi_ulong) * nw, |
|
513 1))) |
|
514 return -TARGET_EFAULT; |
|
515 |
|
516 FD_ZERO(fds); |
|
517 k = 0; |
|
518 for (i = 0; i < nw; i++) { |
|
519 /* grab the abi_ulong */ |
|
520 __get_user(b, &target_fds[i]); |
|
521 for (j = 0; j < TARGET_ABI_BITS; j++) { |
|
522 /* check the bit inside the abi_ulong */ |
|
523 if ((b >> j) & 1) |
|
524 FD_SET(k, fds); |
|
525 k++; |
|
526 } |
|
527 } |
|
528 |
|
529 unlock_user(target_fds, target_fds_addr, 0); |
|
530 |
|
531 return 0; |
|
532 } |
|
533 |
|
534 static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, |
|
535 const fd_set *fds, |
|
536 int n) |
|
537 { |
|
538 int i, nw, j, k; |
|
539 abi_long v; |
|
540 abi_ulong *target_fds; |
|
541 |
|
542 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; |
|
543 if (!(target_fds = lock_user(VERIFY_WRITE, |
|
544 target_fds_addr, |
|
545 sizeof(abi_ulong) * nw, |
|
546 0))) |
|
547 return -TARGET_EFAULT; |
|
548 |
|
549 k = 0; |
|
550 for (i = 0; i < nw; i++) { |
|
551 v = 0; |
|
552 for (j = 0; j < TARGET_ABI_BITS; j++) { |
|
553 v |= ((FD_ISSET(k, fds) != 0) << j); |
|
554 k++; |
|
555 } |
|
556 __put_user(v, &target_fds[i]); |
|
557 } |
|
558 |
|
559 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw); |
|
560 |
|
561 return 0; |
|
562 } |
|
563 |
|
564 #if defined(__alpha__) |
|
565 #define HOST_HZ 1024 |
|
566 #else |
|
567 #define HOST_HZ 100 |
|
568 #endif |
|
569 |
|
570 static inline abi_long host_to_target_clock_t(long ticks) |
|
571 { |
|
572 #if HOST_HZ == TARGET_HZ |
|
573 return ticks; |
|
574 #else |
|
575 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ; |
|
576 #endif |
|
577 } |
|
578 |
|
579 static inline abi_long host_to_target_rusage(abi_ulong target_addr, |
|
580 const struct rusage *rusage) |
|
581 { |
|
582 struct target_rusage *target_rusage; |
|
583 |
|
584 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) |
|
585 return -TARGET_EFAULT; |
|
586 target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); |
|
587 target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); |
|
588 target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); |
|
589 target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec); |
|
590 target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss); |
|
591 target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss); |
|
592 target_rusage->ru_idrss = tswapl(rusage->ru_idrss); |
|
593 target_rusage->ru_isrss = tswapl(rusage->ru_isrss); |
|
594 target_rusage->ru_minflt = tswapl(rusage->ru_minflt); |
|
595 target_rusage->ru_majflt = tswapl(rusage->ru_majflt); |
|
596 target_rusage->ru_nswap = tswapl(rusage->ru_nswap); |
|
597 target_rusage->ru_inblock = tswapl(rusage->ru_inblock); |
|
598 target_rusage->ru_oublock = tswapl(rusage->ru_oublock); |
|
599 target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd); |
|
600 target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv); |
|
601 target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals); |
|
602 target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); |
|
603 target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); |
|
604 unlock_user_struct(target_rusage, target_addr, 1); |
|
605 |
|
606 return 0; |
|
607 } |
|
608 |
|
609 static inline abi_long copy_from_user_timeval(struct timeval *tv, |
|
610 abi_ulong target_tv_addr) |
|
611 { |
|
612 struct target_timeval *target_tv; |
|
613 |
|
614 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) |
|
615 return -TARGET_EFAULT; |
|
616 |
|
617 __get_user(tv->tv_sec, &target_tv->tv_sec); |
|
618 __get_user(tv->tv_usec, &target_tv->tv_usec); |
|
619 |
|
620 unlock_user_struct(target_tv, target_tv_addr, 0); |
|
621 |
|
622 return 0; |
|
623 } |
|
624 |
|
625 static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr, |
|
626 const struct timeval *tv) |
|
627 { |
|
628 struct target_timeval *target_tv; |
|
629 |
|
630 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) |
|
631 return -TARGET_EFAULT; |
|
632 |
|
633 __put_user(tv->tv_sec, &target_tv->tv_sec); |
|
634 __put_user(tv->tv_usec, &target_tv->tv_usec); |
|
635 |
|
636 unlock_user_struct(target_tv, target_tv_addr, 1); |
|
637 |
|
638 return 0; |
|
639 } |
|
640 |
|
641 |
|
642 /* do_select() must return target values and target errnos. */ |
|
643 static abi_long do_select(int n, |
|
644 abi_ulong rfd_addr, abi_ulong wfd_addr, |
|
645 abi_ulong efd_addr, abi_ulong target_tv_addr) |
|
646 { |
|
647 fd_set rfds, wfds, efds; |
|
648 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; |
|
649 struct timeval tv, *tv_ptr; |
|
650 abi_long ret; |
|
651 |
|
652 if (rfd_addr) { |
|
653 if (copy_from_user_fdset(&rfds, rfd_addr, n)) |
|
654 return -TARGET_EFAULT; |
|
655 rfds_ptr = &rfds; |
|
656 } else { |
|
657 rfds_ptr = NULL; |
|
658 } |
|
659 if (wfd_addr) { |
|
660 if (copy_from_user_fdset(&wfds, wfd_addr, n)) |
|
661 return -TARGET_EFAULT; |
|
662 wfds_ptr = &wfds; |
|
663 } else { |
|
664 wfds_ptr = NULL; |
|
665 } |
|
666 if (efd_addr) { |
|
667 if (copy_from_user_fdset(&efds, efd_addr, n)) |
|
668 return -TARGET_EFAULT; |
|
669 efds_ptr = &efds; |
|
670 } else { |
|
671 efds_ptr = NULL; |
|
672 } |
|
673 |
|
674 if (target_tv_addr) { |
|
675 if (copy_from_user_timeval(&tv, target_tv_addr)) |
|
676 return -TARGET_EFAULT; |
|
677 tv_ptr = &tv; |
|
678 } else { |
|
679 tv_ptr = NULL; |
|
680 } |
|
681 |
|
682 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); |
|
683 |
|
684 if (!is_error(ret)) { |
|
685 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) |
|
686 return -TARGET_EFAULT; |
|
687 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) |
|
688 return -TARGET_EFAULT; |
|
689 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) |
|
690 return -TARGET_EFAULT; |
|
691 |
|
692 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv)) |
|
693 return -TARGET_EFAULT; |
|
694 } |
|
695 |
|
696 return ret; |
|
697 } |
|
698 |
|
699 static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, |
|
700 abi_ulong target_addr, |
|
701 socklen_t len) |
|
702 { |
|
703 struct target_sockaddr *target_saddr; |
|
704 |
|
705 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); |
|
706 if (!target_saddr) |
|
707 return -TARGET_EFAULT; |
|
708 memcpy(addr, target_saddr, len); |
|
709 addr->sa_family = tswap16(target_saddr->sa_family); |
|
710 unlock_user(target_saddr, target_addr, 0); |
|
711 |
|
712 return 0; |
|
713 } |
|
714 |
|
715 static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, |
|
716 struct sockaddr *addr, |
|
717 socklen_t len) |
|
718 { |
|
719 struct target_sockaddr *target_saddr; |
|
720 |
|
721 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); |
|
722 if (!target_saddr) |
|
723 return -TARGET_EFAULT; |
|
724 memcpy(target_saddr, addr, len); |
|
725 target_saddr->sa_family = tswap16(addr->sa_family); |
|
726 unlock_user(target_saddr, target_addr, len); |
|
727 |
|
728 return 0; |
|
729 } |
|
730 |
|
731 /* ??? Should this also swap msgh->name? */ |
|
732 static inline abi_long target_to_host_cmsg(struct msghdr *msgh, |
|
733 struct target_msghdr *target_msgh) |
|
734 { |
|
735 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); |
|
736 abi_long msg_controllen; |
|
737 abi_ulong target_cmsg_addr; |
|
738 struct target_cmsghdr *target_cmsg; |
|
739 socklen_t space = 0; |
|
740 |
|
741 msg_controllen = tswapl(target_msgh->msg_controllen); |
|
742 if (msg_controllen < sizeof (struct target_cmsghdr)) |
|
743 goto the_end; |
|
744 target_cmsg_addr = tswapl(target_msgh->msg_control); |
|
745 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); |
|
746 if (!target_cmsg) |
|
747 return -TARGET_EFAULT; |
|
748 |
|
749 while (cmsg && target_cmsg) { |
|
750 void *data = CMSG_DATA(cmsg); |
|
751 void *target_data = TARGET_CMSG_DATA(target_cmsg); |
|
752 |
|
753 int len = tswapl(target_cmsg->cmsg_len) |
|
754 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); |
|
755 |
|
756 space += CMSG_SPACE(len); |
|
757 if (space > msgh->msg_controllen) { |
|
758 space -= CMSG_SPACE(len); |
|
759 gemu_log("Host cmsg overflow\n"); |
|
760 break; |
|
761 } |
|
762 |
|
763 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); |
|
764 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); |
|
765 cmsg->cmsg_len = CMSG_LEN(len); |
|
766 |
|
767 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { |
|
768 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); |
|
769 memcpy(data, target_data, len); |
|
770 } else { |
|
771 int *fd = (int *)data; |
|
772 int *target_fd = (int *)target_data; |
|
773 int i, numfds = len / sizeof(int); |
|
774 |
|
775 for (i = 0; i < numfds; i++) |
|
776 fd[i] = tswap32(target_fd[i]); |
|
777 } |
|
778 |
|
779 cmsg = CMSG_NXTHDR(msgh, cmsg); |
|
780 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); |
|
781 } |
|
782 unlock_user(target_cmsg, target_cmsg_addr, 0); |
|
783 the_end: |
|
784 msgh->msg_controllen = space; |
|
785 return 0; |
|
786 } |
|
787 |
|
788 /* ??? Should this also swap msgh->name? */ |
|
789 static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, |
|
790 struct msghdr *msgh) |
|
791 { |
|
792 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); |
|
793 abi_long msg_controllen; |
|
794 abi_ulong target_cmsg_addr; |
|
795 struct target_cmsghdr *target_cmsg; |
|
796 socklen_t space = 0; |
|
797 |
|
798 msg_controllen = tswapl(target_msgh->msg_controllen); |
|
799 if (msg_controllen < sizeof (struct target_cmsghdr)) |
|
800 goto the_end; |
|
801 target_cmsg_addr = tswapl(target_msgh->msg_control); |
|
802 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); |
|
803 if (!target_cmsg) |
|
804 return -TARGET_EFAULT; |
|
805 |
|
806 while (cmsg && target_cmsg) { |
|
807 void *data = CMSG_DATA(cmsg); |
|
808 void *target_data = TARGET_CMSG_DATA(target_cmsg); |
|
809 |
|
810 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); |
|
811 |
|
812 space += TARGET_CMSG_SPACE(len); |
|
813 if (space > msg_controllen) { |
|
814 space -= TARGET_CMSG_SPACE(len); |
|
815 gemu_log("Target cmsg overflow\n"); |
|
816 break; |
|
817 } |
|
818 |
|
819 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); |
|
820 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); |
|
821 target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); |
|
822 |
|
823 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { |
|
824 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); |
|
825 memcpy(target_data, data, len); |
|
826 } else { |
|
827 int *fd = (int *)data; |
|
828 int *target_fd = (int *)target_data; |
|
829 int i, numfds = len / sizeof(int); |
|
830 |
|
831 for (i = 0; i < numfds; i++) |
|
832 target_fd[i] = tswap32(fd[i]); |
|
833 } |
|
834 |
|
835 cmsg = CMSG_NXTHDR(msgh, cmsg); |
|
836 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); |
|
837 } |
|
838 unlock_user(target_cmsg, target_cmsg_addr, space); |
|
839 the_end: |
|
840 target_msgh->msg_controllen = tswapl(space); |
|
841 return 0; |
|
842 } |
|
843 |
|
844 /* do_setsockopt() Must return target values and target errnos. */ |
|
845 static abi_long do_setsockopt(int sockfd, int level, int optname, |
|
846 abi_ulong optval_addr, socklen_t optlen) |
|
847 { |
|
848 abi_long ret; |
|
849 int val; |
|
850 |
|
851 switch(level) { |
|
852 case SOL_TCP: |
|
853 /* TCP options all take an 'int' value. */ |
|
854 if (optlen < sizeof(uint32_t)) |
|
855 return -TARGET_EINVAL; |
|
856 |
|
857 if (get_user_u32(val, optval_addr)) |
|
858 return -TARGET_EFAULT; |
|
859 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); |
|
860 break; |
|
861 case SOL_IP: |
|
862 switch(optname) { |
|
863 case IP_TOS: |
|
864 case IP_TTL: |
|
865 case IP_HDRINCL: |
|
866 case IP_ROUTER_ALERT: |
|
867 case IP_RECVOPTS: |
|
868 case IP_RETOPTS: |
|
869 case IP_PKTINFO: |
|
870 case IP_MTU_DISCOVER: |
|
871 case IP_RECVERR: |
|
872 case IP_RECVTOS: |
|
873 #ifdef IP_FREEBIND |
|
874 case IP_FREEBIND: |
|
875 #endif |
|
876 case IP_MULTICAST_TTL: |
|
877 case IP_MULTICAST_LOOP: |
|
878 val = 0; |
|
879 if (optlen >= sizeof(uint32_t)) { |
|
880 if (get_user_u32(val, optval_addr)) |
|
881 return -TARGET_EFAULT; |
|
882 } else if (optlen >= 1) { |
|
883 if (get_user_u8(val, optval_addr)) |
|
884 return -TARGET_EFAULT; |
|
885 } |
|
886 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); |
|
887 break; |
|
888 default: |
|
889 goto unimplemented; |
|
890 } |
|
891 break; |
|
892 case TARGET_SOL_SOCKET: |
|
893 switch (optname) { |
|
894 /* Options with 'int' argument. */ |
|
895 case TARGET_SO_DEBUG: |
|
896 optname = SO_DEBUG; |
|
897 break; |
|
898 case TARGET_SO_REUSEADDR: |
|
899 optname = SO_REUSEADDR; |
|
900 break; |
|
901 case TARGET_SO_TYPE: |
|
902 optname = SO_TYPE; |
|
903 break; |
|
904 case TARGET_SO_ERROR: |
|
905 optname = SO_ERROR; |
|
906 break; |
|
907 case TARGET_SO_DONTROUTE: |
|
908 optname = SO_DONTROUTE; |
|
909 break; |
|
910 case TARGET_SO_BROADCAST: |
|
911 optname = SO_BROADCAST; |
|
912 break; |
|
913 case TARGET_SO_SNDBUF: |
|
914 optname = SO_SNDBUF; |
|
915 break; |
|
916 case TARGET_SO_RCVBUF: |
|
917 optname = SO_RCVBUF; |
|
918 break; |
|
919 case TARGET_SO_KEEPALIVE: |
|
920 optname = SO_KEEPALIVE; |
|
921 break; |
|
922 case TARGET_SO_OOBINLINE: |
|
923 optname = SO_OOBINLINE; |
|
924 break; |
|
925 case TARGET_SO_NO_CHECK: |
|
926 optname = SO_NO_CHECK; |
|
927 break; |
|
928 case TARGET_SO_PRIORITY: |
|
929 optname = SO_PRIORITY; |
|
930 break; |
|
931 #ifdef SO_BSDCOMPAT |
|
932 case TARGET_SO_BSDCOMPAT: |
|
933 optname = SO_BSDCOMPAT; |
|
934 break; |
|
935 #endif |
|
936 case TARGET_SO_PASSCRED: |
|
937 optname = SO_PASSCRED; |
|
938 break; |
|
939 case TARGET_SO_TIMESTAMP: |
|
940 optname = SO_TIMESTAMP; |
|
941 break; |
|
942 case TARGET_SO_RCVLOWAT: |
|
943 optname = SO_RCVLOWAT; |
|
944 break; |
|
945 case TARGET_SO_RCVTIMEO: |
|
946 optname = SO_RCVTIMEO; |
|
947 break; |
|
948 case TARGET_SO_SNDTIMEO: |
|
949 optname = SO_SNDTIMEO; |
|
950 break; |
|
951 break; |
|
952 default: |
|
953 goto unimplemented; |
|
954 } |
|
955 if (optlen < sizeof(uint32_t)) |
|
956 return -TARGET_EINVAL; |
|
957 |
|
958 if (get_user_u32(val, optval_addr)) |
|
959 return -TARGET_EFAULT; |
|
960 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); |
|
961 break; |
|
962 default: |
|
963 unimplemented: |
|
964 gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); |
|
965 ret = -TARGET_ENOPROTOOPT; |
|
966 } |
|
967 return ret; |
|
968 } |
|
969 |
|
970 /* do_getsockopt() Must return target values and target errnos. */ |
|
971 static abi_long do_getsockopt(int sockfd, int level, int optname, |
|
972 abi_ulong optval_addr, abi_ulong optlen) |
|
973 { |
|
974 abi_long ret; |
|
975 int len, val; |
|
976 socklen_t lv; |
|
977 |
|
978 switch(level) { |
|
979 case TARGET_SOL_SOCKET: |
|
980 level = SOL_SOCKET; |
|
981 switch (optname) { |
|
982 case TARGET_SO_LINGER: |
|
983 case TARGET_SO_RCVTIMEO: |
|
984 case TARGET_SO_SNDTIMEO: |
|
985 case TARGET_SO_PEERCRED: |
|
986 case TARGET_SO_PEERNAME: |
|
987 /* These don't just return a single integer */ |
|
988 goto unimplemented; |
|
989 default: |
|
990 goto int_case; |
|
991 } |
|
992 break; |
|
993 case SOL_TCP: |
|
994 /* TCP options all take an 'int' value. */ |
|
995 int_case: |
|
996 if (get_user_u32(len, optlen)) |
|
997 return -TARGET_EFAULT; |
|
998 if (len < 0) |
|
999 return -TARGET_EINVAL; |
|
1000 lv = sizeof(int); |
|
1001 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); |
|
1002 if (ret < 0) |
|
1003 return ret; |
|
1004 val = tswap32(val); |
|
1005 if (len > lv) |
|
1006 len = lv; |
|
1007 if (len == 4) { |
|
1008 if (put_user_u32(val, optval_addr)) |
|
1009 return -TARGET_EFAULT; |
|
1010 } else { |
|
1011 if (put_user_u8(val, optval_addr)) |
|
1012 return -TARGET_EFAULT; |
|
1013 } |
|
1014 if (put_user_u32(len, optlen)) |
|
1015 return -TARGET_EFAULT; |
|
1016 break; |
|
1017 case SOL_IP: |
|
1018 switch(optname) { |
|
1019 case IP_TOS: |
|
1020 case IP_TTL: |
|
1021 case IP_HDRINCL: |
|
1022 case IP_ROUTER_ALERT: |
|
1023 case IP_RECVOPTS: |
|
1024 case IP_RETOPTS: |
|
1025 case IP_PKTINFO: |
|
1026 case IP_MTU_DISCOVER: |
|
1027 case IP_RECVERR: |
|
1028 case IP_RECVTOS: |
|
1029 #ifdef IP_FREEBIND |
|
1030 case IP_FREEBIND: |
|
1031 #endif |
|
1032 case IP_MULTICAST_TTL: |
|
1033 case IP_MULTICAST_LOOP: |
|
1034 if (get_user_u32(len, optlen)) |
|
1035 return -TARGET_EFAULT; |
|
1036 if (len < 0) |
|
1037 return -TARGET_EINVAL; |
|
1038 lv = sizeof(int); |
|
1039 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); |
|
1040 if (ret < 0) |
|
1041 return ret; |
|
1042 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { |
|
1043 len = 1; |
|
1044 if (put_user_u32(len, optlen) |
|
1045 || put_user_u8(val, optval_addr)) |
|
1046 return -TARGET_EFAULT; |
|
1047 } else { |
|
1048 if (len > sizeof(int)) |
|
1049 len = sizeof(int); |
|
1050 if (put_user_u32(len, optlen) |
|
1051 || put_user_u32(val, optval_addr)) |
|
1052 return -TARGET_EFAULT; |
|
1053 } |
|
1054 break; |
|
1055 default: |
|
1056 ret = -TARGET_ENOPROTOOPT; |
|
1057 break; |
|
1058 } |
|
1059 break; |
|
1060 default: |
|
1061 unimplemented: |
|
1062 gemu_log("getsockopt level=%d optname=%d not yet supported\n", |
|
1063 level, optname); |
|
1064 ret = -TARGET_EOPNOTSUPP; |
|
1065 break; |
|
1066 } |
|
1067 return ret; |
|
1068 } |
|
1069 |
|
1070 /* FIXME |
|
1071 * lock_iovec()/unlock_iovec() have a return code of 0 for success where |
|
1072 * other lock functions have a return code of 0 for failure. |
|
1073 */ |
|
1074 static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, |
|
1075 int count, int copy) |
|
1076 { |
|
1077 struct target_iovec *target_vec; |
|
1078 abi_ulong base; |
|
1079 int i; |
|
1080 |
|
1081 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); |
|
1082 if (!target_vec) |
|
1083 return -TARGET_EFAULT; |
|
1084 for(i = 0;i < count; i++) { |
|
1085 base = tswapl(target_vec[i].iov_base); |
|
1086 vec[i].iov_len = tswapl(target_vec[i].iov_len); |
|
1087 if (vec[i].iov_len != 0) { |
|
1088 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); |
|
1089 /* Don't check lock_user return value. We must call writev even |
|
1090 if a element has invalid base address. */ |
|
1091 } else { |
|
1092 /* zero length pointer is ignored */ |
|
1093 vec[i].iov_base = NULL; |
|
1094 } |
|
1095 } |
|
1096 unlock_user (target_vec, target_addr, 0); |
|
1097 return 0; |
|
1098 } |
|
1099 |
|
1100 static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, |
|
1101 int count, int copy) |
|
1102 { |
|
1103 struct target_iovec *target_vec; |
|
1104 abi_ulong base; |
|
1105 int i; |
|
1106 |
|
1107 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); |
|
1108 if (!target_vec) |
|
1109 return -TARGET_EFAULT; |
|
1110 for(i = 0;i < count; i++) { |
|
1111 if (target_vec[i].iov_base) { |
|
1112 base = tswapl(target_vec[i].iov_base); |
|
1113 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); |
|
1114 } |
|
1115 } |
|
1116 unlock_user (target_vec, target_addr, 0); |
|
1117 |
|
1118 return 0; |
|
1119 } |
|
1120 |
|
1121 /* do_socket() Must return target values and target errnos. */ |
|
1122 static abi_long do_socket(int domain, int type, int protocol) |
|
1123 { |
|
1124 #if defined(TARGET_MIPS) |
|
1125 switch(type) { |
|
1126 case TARGET_SOCK_DGRAM: |
|
1127 type = SOCK_DGRAM; |
|
1128 break; |
|
1129 case TARGET_SOCK_STREAM: |
|
1130 type = SOCK_STREAM; |
|
1131 break; |
|
1132 case TARGET_SOCK_RAW: |
|
1133 type = SOCK_RAW; |
|
1134 break; |
|
1135 case TARGET_SOCK_RDM: |
|
1136 type = SOCK_RDM; |
|
1137 break; |
|
1138 case TARGET_SOCK_SEQPACKET: |
|
1139 type = SOCK_SEQPACKET; |
|
1140 break; |
|
1141 case TARGET_SOCK_PACKET: |
|
1142 type = SOCK_PACKET; |
|
1143 break; |
|
1144 } |
|
1145 #endif |
|
1146 if (domain == PF_NETLINK) |
|
1147 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */ |
|
1148 return get_errno(socket(domain, type, protocol)); |
|
1149 } |
|
1150 |
|
1151 /* do_bind() Must return target values and target errnos. */ |
|
1152 static abi_long do_bind(int sockfd, abi_ulong target_addr, |
|
1153 socklen_t addrlen) |
|
1154 { |
|
1155 void *addr = alloca(addrlen); |
|
1156 |
|
1157 target_to_host_sockaddr(addr, target_addr, addrlen); |
|
1158 return get_errno(bind(sockfd, addr, addrlen)); |
|
1159 } |
|
1160 |
|
1161 /* do_connect() Must return target values and target errnos. */ |
|
1162 static abi_long do_connect(int sockfd, abi_ulong target_addr, |
|
1163 socklen_t addrlen) |
|
1164 { |
|
1165 void *addr = alloca(addrlen); |
|
1166 |
|
1167 target_to_host_sockaddr(addr, target_addr, addrlen); |
|
1168 return get_errno(connect(sockfd, addr, addrlen)); |
|
1169 } |
|
1170 |
|
1171 /* do_sendrecvmsg() Must return target values and target errnos. */ |
|
1172 static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, |
|
1173 int flags, int send) |
|
1174 { |
|
1175 abi_long ret, len; |
|
1176 struct target_msghdr *msgp; |
|
1177 struct msghdr msg; |
|
1178 int count; |
|
1179 struct iovec *vec; |
|
1180 abi_ulong target_vec; |
|
1181 |
|
1182 /* FIXME */ |
|
1183 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, |
|
1184 msgp, |
|
1185 target_msg, |
|
1186 send ? 1 : 0)) |
|
1187 return -TARGET_EFAULT; |
|
1188 if (msgp->msg_name) { |
|
1189 msg.msg_namelen = tswap32(msgp->msg_namelen); |
|
1190 msg.msg_name = alloca(msg.msg_namelen); |
|
1191 target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), |
|
1192 msg.msg_namelen); |
|
1193 } else { |
|
1194 msg.msg_name = NULL; |
|
1195 msg.msg_namelen = 0; |
|
1196 } |
|
1197 msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); |
|
1198 msg.msg_control = alloca(msg.msg_controllen); |
|
1199 msg.msg_flags = tswap32(msgp->msg_flags); |
|
1200 |
|
1201 count = tswapl(msgp->msg_iovlen); |
|
1202 vec = alloca(count * sizeof(struct iovec)); |
|
1203 target_vec = tswapl(msgp->msg_iov); |
|
1204 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send); |
|
1205 msg.msg_iovlen = count; |
|
1206 msg.msg_iov = vec; |
|
1207 |
|
1208 if (send) { |
|
1209 ret = target_to_host_cmsg(&msg, msgp); |
|
1210 if (ret == 0) |
|
1211 ret = get_errno(sendmsg(fd, &msg, flags)); |
|
1212 } else { |
|
1213 ret = get_errno(recvmsg(fd, &msg, flags)); |
|
1214 if (!is_error(ret)) { |
|
1215 len = ret; |
|
1216 ret = host_to_target_cmsg(msgp, &msg); |
|
1217 if (!is_error(ret)) |
|
1218 ret = len; |
|
1219 } |
|
1220 } |
|
1221 unlock_iovec(vec, target_vec, count, !send); |
|
1222 unlock_user_struct(msgp, target_msg, send ? 0 : 1); |
|
1223 return ret; |
|
1224 } |
|
1225 |
|
1226 /* do_accept() Must return target values and target errnos. */ |
|
1227 static abi_long do_accept(int fd, abi_ulong target_addr, |
|
1228 abi_ulong target_addrlen_addr) |
|
1229 { |
|
1230 socklen_t addrlen; |
|
1231 void *addr; |
|
1232 abi_long ret; |
|
1233 |
|
1234 if (get_user_u32(addrlen, target_addrlen_addr)) |
|
1235 return -TARGET_EFAULT; |
|
1236 |
|
1237 addr = alloca(addrlen); |
|
1238 |
|
1239 ret = get_errno(accept(fd, addr, &addrlen)); |
|
1240 if (!is_error(ret)) { |
|
1241 host_to_target_sockaddr(target_addr, addr, addrlen); |
|
1242 if (put_user_u32(addrlen, target_addrlen_addr)) |
|
1243 ret = -TARGET_EFAULT; |
|
1244 } |
|
1245 return ret; |
|
1246 } |
|
1247 |
|
1248 /* do_getpeername() Must return target values and target errnos. */ |
|
1249 static abi_long do_getpeername(int fd, abi_ulong target_addr, |
|
1250 abi_ulong target_addrlen_addr) |
|
1251 { |
|
1252 socklen_t addrlen; |
|
1253 void *addr; |
|
1254 abi_long ret; |
|
1255 |
|
1256 if (get_user_u32(addrlen, target_addrlen_addr)) |
|
1257 return -TARGET_EFAULT; |
|
1258 |
|
1259 addr = alloca(addrlen); |
|
1260 |
|
1261 ret = get_errno(getpeername(fd, addr, &addrlen)); |
|
1262 if (!is_error(ret)) { |
|
1263 host_to_target_sockaddr(target_addr, addr, addrlen); |
|
1264 if (put_user_u32(addrlen, target_addrlen_addr)) |
|
1265 ret = -TARGET_EFAULT; |
|
1266 } |
|
1267 return ret; |
|
1268 } |
|
1269 |
|
1270 /* do_getsockname() Must return target values and target errnos. */ |
|
1271 static abi_long do_getsockname(int fd, abi_ulong target_addr, |
|
1272 abi_ulong target_addrlen_addr) |
|
1273 { |
|
1274 socklen_t addrlen; |
|
1275 void *addr; |
|
1276 abi_long ret; |
|
1277 |
|
1278 if (get_user_u32(addrlen, target_addrlen_addr)) |
|
1279 return -TARGET_EFAULT; |
|
1280 |
|
1281 addr = alloca(addrlen); |
|
1282 |
|
1283 ret = get_errno(getsockname(fd, addr, &addrlen)); |
|
1284 if (!is_error(ret)) { |
|
1285 host_to_target_sockaddr(target_addr, addr, addrlen); |
|
1286 if (put_user_u32(addrlen, target_addrlen_addr)) |
|
1287 ret = -TARGET_EFAULT; |
|
1288 } |
|
1289 return ret; |
|
1290 } |
|
1291 |
|
1292 /* do_socketpair() Must return target values and target errnos. */ |
|
1293 static abi_long do_socketpair(int domain, int type, int protocol, |
|
1294 abi_ulong target_tab_addr) |
|
1295 { |
|
1296 int tab[2]; |
|
1297 abi_long ret; |
|
1298 |
|
1299 ret = get_errno(socketpair(domain, type, protocol, tab)); |
|
1300 if (!is_error(ret)) { |
|
1301 if (put_user_s32(tab[0], target_tab_addr) |
|
1302 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) |
|
1303 ret = -TARGET_EFAULT; |
|
1304 } |
|
1305 return ret; |
|
1306 } |
|
1307 |
|
1308 /* do_sendto() Must return target values and target errnos. */ |
|
1309 static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, |
|
1310 abi_ulong target_addr, socklen_t addrlen) |
|
1311 { |
|
1312 void *addr; |
|
1313 void *host_msg; |
|
1314 abi_long ret; |
|
1315 |
|
1316 host_msg = lock_user(VERIFY_READ, msg, len, 1); |
|
1317 if (!host_msg) |
|
1318 return -TARGET_EFAULT; |
|
1319 if (target_addr) { |
|
1320 addr = alloca(addrlen); |
|
1321 target_to_host_sockaddr(addr, target_addr, addrlen); |
|
1322 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); |
|
1323 } else { |
|
1324 ret = get_errno(send(fd, host_msg, len, flags)); |
|
1325 } |
|
1326 unlock_user(host_msg, msg, 0); |
|
1327 return ret; |
|
1328 } |
|
1329 |
|
1330 /* do_recvfrom() Must return target values and target errnos. */ |
|
1331 static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, |
|
1332 abi_ulong target_addr, |
|
1333 abi_ulong target_addrlen) |
|
1334 { |
|
1335 socklen_t addrlen; |
|
1336 void *addr; |
|
1337 void *host_msg; |
|
1338 abi_long ret; |
|
1339 |
|
1340 host_msg = lock_user(VERIFY_WRITE, msg, len, 0); |
|
1341 if (!host_msg) |
|
1342 return -TARGET_EFAULT; |
|
1343 if (target_addr) { |
|
1344 if (get_user_u32(addrlen, target_addrlen)) { |
|
1345 ret = -TARGET_EFAULT; |
|
1346 goto fail; |
|
1347 } |
|
1348 addr = alloca(addrlen); |
|
1349 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen)); |
|
1350 } else { |
|
1351 addr = NULL; /* To keep compiler quiet. */ |
|
1352 ret = get_errno(recv(fd, host_msg, len, flags)); |
|
1353 } |
|
1354 if (!is_error(ret)) { |
|
1355 if (target_addr) { |
|
1356 host_to_target_sockaddr(target_addr, addr, addrlen); |
|
1357 if (put_user_u32(addrlen, target_addrlen)) { |
|
1358 ret = -TARGET_EFAULT; |
|
1359 goto fail; |
|
1360 } |
|
1361 } |
|
1362 unlock_user(host_msg, msg, len); |
|
1363 } else { |
|
1364 fail: |
|
1365 unlock_user(host_msg, msg, 0); |
|
1366 } |
|
1367 return ret; |
|
1368 } |
|
1369 |
|
1370 #ifdef TARGET_NR_socketcall |
|
1371 /* do_socketcall() Must return target values and target errnos. */ |
|
1372 static abi_long do_socketcall(int num, abi_ulong vptr) |
|
1373 { |
|
1374 abi_long ret; |
|
1375 const int n = sizeof(abi_ulong); |
|
1376 |
|
1377 switch(num) { |
|
1378 case SOCKOP_socket: |
|
1379 { |
|
1380 int domain, type, protocol; |
|
1381 |
|
1382 if (get_user_s32(domain, vptr) |
|
1383 || get_user_s32(type, vptr + n) |
|
1384 || get_user_s32(protocol, vptr + 2 * n)) |
|
1385 return -TARGET_EFAULT; |
|
1386 |
|
1387 ret = do_socket(domain, type, protocol); |
|
1388 } |
|
1389 break; |
|
1390 case SOCKOP_bind: |
|
1391 { |
|
1392 int sockfd; |
|
1393 abi_ulong target_addr; |
|
1394 socklen_t addrlen; |
|
1395 |
|
1396 if (get_user_s32(sockfd, vptr) |
|
1397 || get_user_ual(target_addr, vptr + n) |
|
1398 || get_user_u32(addrlen, vptr + 2 * n)) |
|
1399 return -TARGET_EFAULT; |
|
1400 |
|
1401 ret = do_bind(sockfd, target_addr, addrlen); |
|
1402 } |
|
1403 break; |
|
1404 case SOCKOP_connect: |
|
1405 { |
|
1406 int sockfd; |
|
1407 abi_ulong target_addr; |
|
1408 socklen_t addrlen; |
|
1409 |
|
1410 if (get_user_s32(sockfd, vptr) |
|
1411 || get_user_ual(target_addr, vptr + n) |
|
1412 || get_user_u32(addrlen, vptr + 2 * n)) |
|
1413 return -TARGET_EFAULT; |
|
1414 |
|
1415 ret = do_connect(sockfd, target_addr, addrlen); |
|
1416 } |
|
1417 break; |
|
1418 case SOCKOP_listen: |
|
1419 { |
|
1420 int sockfd, backlog; |
|
1421 |
|
1422 if (get_user_s32(sockfd, vptr) |
|
1423 || get_user_s32(backlog, vptr + n)) |
|
1424 return -TARGET_EFAULT; |
|
1425 |
|
1426 ret = get_errno(listen(sockfd, backlog)); |
|
1427 } |
|
1428 break; |
|
1429 case SOCKOP_accept: |
|
1430 { |
|
1431 int sockfd; |
|
1432 abi_ulong target_addr, target_addrlen; |
|
1433 |
|
1434 if (get_user_s32(sockfd, vptr) |
|
1435 || get_user_ual(target_addr, vptr + n) |
|
1436 || get_user_u32(target_addrlen, vptr + 2 * n)) |
|
1437 return -TARGET_EFAULT; |
|
1438 |
|
1439 ret = do_accept(sockfd, target_addr, target_addrlen); |
|
1440 } |
|
1441 break; |
|
1442 case SOCKOP_getsockname: |
|
1443 { |
|
1444 int sockfd; |
|
1445 abi_ulong target_addr, target_addrlen; |
|
1446 |
|
1447 if (get_user_s32(sockfd, vptr) |
|
1448 || get_user_ual(target_addr, vptr + n) |
|
1449 || get_user_u32(target_addrlen, vptr + 2 * n)) |
|
1450 return -TARGET_EFAULT; |
|
1451 |
|
1452 ret = do_getsockname(sockfd, target_addr, target_addrlen); |
|
1453 } |
|
1454 break; |
|
1455 case SOCKOP_getpeername: |
|
1456 { |
|
1457 int sockfd; |
|
1458 abi_ulong target_addr, target_addrlen; |
|
1459 |
|
1460 if (get_user_s32(sockfd, vptr) |
|
1461 || get_user_ual(target_addr, vptr + n) |
|
1462 || get_user_u32(target_addrlen, vptr + 2 * n)) |
|
1463 return -TARGET_EFAULT; |
|
1464 |
|
1465 ret = do_getpeername(sockfd, target_addr, target_addrlen); |
|
1466 } |
|
1467 break; |
|
1468 case SOCKOP_socketpair: |
|
1469 { |
|
1470 int domain, type, protocol; |
|
1471 abi_ulong tab; |
|
1472 |
|
1473 if (get_user_s32(domain, vptr) |
|
1474 || get_user_s32(type, vptr + n) |
|
1475 || get_user_s32(protocol, vptr + 2 * n) |
|
1476 || get_user_ual(tab, vptr + 3 * n)) |
|
1477 return -TARGET_EFAULT; |
|
1478 |
|
1479 ret = do_socketpair(domain, type, protocol, tab); |
|
1480 } |
|
1481 break; |
|
1482 case SOCKOP_send: |
|
1483 { |
|
1484 int sockfd; |
|
1485 abi_ulong msg; |
|
1486 size_t len; |
|
1487 int flags; |
|
1488 |
|
1489 if (get_user_s32(sockfd, vptr) |
|
1490 || get_user_ual(msg, vptr + n) |
|
1491 || get_user_ual(len, vptr + 2 * n) |
|
1492 || get_user_s32(flags, vptr + 3 * n)) |
|
1493 return -TARGET_EFAULT; |
|
1494 |
|
1495 ret = do_sendto(sockfd, msg, len, flags, 0, 0); |
|
1496 } |
|
1497 break; |
|
1498 case SOCKOP_recv: |
|
1499 { |
|
1500 int sockfd; |
|
1501 abi_ulong msg; |
|
1502 size_t len; |
|
1503 int flags; |
|
1504 |
|
1505 if (get_user_s32(sockfd, vptr) |
|
1506 || get_user_ual(msg, vptr + n) |
|
1507 || get_user_ual(len, vptr + 2 * n) |
|
1508 || get_user_s32(flags, vptr + 3 * n)) |
|
1509 return -TARGET_EFAULT; |
|
1510 |
|
1511 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0); |
|
1512 } |
|
1513 break; |
|
1514 case SOCKOP_sendto: |
|
1515 { |
|
1516 int sockfd; |
|
1517 abi_ulong msg; |
|
1518 size_t len; |
|
1519 int flags; |
|
1520 abi_ulong addr; |
|
1521 socklen_t addrlen; |
|
1522 |
|
1523 if (get_user_s32(sockfd, vptr) |
|
1524 || get_user_ual(msg, vptr + n) |
|
1525 || get_user_ual(len, vptr + 2 * n) |
|
1526 || get_user_s32(flags, vptr + 3 * n) |
|
1527 || get_user_ual(addr, vptr + 4 * n) |
|
1528 || get_user_u32(addrlen, vptr + 5 * n)) |
|
1529 return -TARGET_EFAULT; |
|
1530 |
|
1531 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen); |
|
1532 } |
|
1533 break; |
|
1534 case SOCKOP_recvfrom: |
|
1535 { |
|
1536 int sockfd; |
|
1537 abi_ulong msg; |
|
1538 size_t len; |
|
1539 int flags; |
|
1540 abi_ulong addr; |
|
1541 socklen_t addrlen; |
|
1542 |
|
1543 if (get_user_s32(sockfd, vptr) |
|
1544 || get_user_ual(msg, vptr + n) |
|
1545 || get_user_ual(len, vptr + 2 * n) |
|
1546 || get_user_s32(flags, vptr + 3 * n) |
|
1547 || get_user_ual(addr, vptr + 4 * n) |
|
1548 || get_user_u32(addrlen, vptr + 5 * n)) |
|
1549 return -TARGET_EFAULT; |
|
1550 |
|
1551 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen); |
|
1552 } |
|
1553 break; |
|
1554 case SOCKOP_shutdown: |
|
1555 { |
|
1556 int sockfd, how; |
|
1557 |
|
1558 if (get_user_s32(sockfd, vptr) |
|
1559 || get_user_s32(how, vptr + n)) |
|
1560 return -TARGET_EFAULT; |
|
1561 |
|
1562 ret = get_errno(shutdown(sockfd, how)); |
|
1563 } |
|
1564 break; |
|
1565 case SOCKOP_sendmsg: |
|
1566 case SOCKOP_recvmsg: |
|
1567 { |
|
1568 int fd; |
|
1569 abi_ulong target_msg; |
|
1570 int flags; |
|
1571 |
|
1572 if (get_user_s32(fd, vptr) |
|
1573 || get_user_ual(target_msg, vptr + n) |
|
1574 || get_user_s32(flags, vptr + 2 * n)) |
|
1575 return -TARGET_EFAULT; |
|
1576 |
|
1577 ret = do_sendrecvmsg(fd, target_msg, flags, |
|
1578 (num == SOCKOP_sendmsg)); |
|
1579 } |
|
1580 break; |
|
1581 case SOCKOP_setsockopt: |
|
1582 { |
|
1583 int sockfd; |
|
1584 int level; |
|
1585 int optname; |
|
1586 abi_ulong optval; |
|
1587 socklen_t optlen; |
|
1588 |
|
1589 if (get_user_s32(sockfd, vptr) |
|
1590 || get_user_s32(level, vptr + n) |
|
1591 || get_user_s32(optname, vptr + 2 * n) |
|
1592 || get_user_ual(optval, vptr + 3 * n) |
|
1593 || get_user_u32(optlen, vptr + 4 * n)) |
|
1594 return -TARGET_EFAULT; |
|
1595 |
|
1596 ret = do_setsockopt(sockfd, level, optname, optval, optlen); |
|
1597 } |
|
1598 break; |
|
1599 case SOCKOP_getsockopt: |
|
1600 { |
|
1601 int sockfd; |
|
1602 int level; |
|
1603 int optname; |
|
1604 abi_ulong optval; |
|
1605 socklen_t optlen; |
|
1606 |
|
1607 if (get_user_s32(sockfd, vptr) |
|
1608 || get_user_s32(level, vptr + n) |
|
1609 || get_user_s32(optname, vptr + 2 * n) |
|
1610 || get_user_ual(optval, vptr + 3 * n) |
|
1611 || get_user_u32(optlen, vptr + 4 * n)) |
|
1612 return -TARGET_EFAULT; |
|
1613 |
|
1614 ret = do_getsockopt(sockfd, level, optname, optval, optlen); |
|
1615 } |
|
1616 break; |
|
1617 default: |
|
1618 gemu_log("Unsupported socketcall: %d\n", num); |
|
1619 ret = -TARGET_ENOSYS; |
|
1620 break; |
|
1621 } |
|
1622 return ret; |
|
1623 } |
|
1624 #endif |
|
1625 |
|
1626 #ifdef TARGET_NR_ipc |
|
1627 #define N_SHM_REGIONS 32 |
|
1628 |
|
1629 static struct shm_region { |
|
1630 abi_ulong start; |
|
1631 abi_ulong size; |
|
1632 } shm_regions[N_SHM_REGIONS]; |
|
1633 #endif |
|
1634 |
|
1635 struct target_ipc_perm |
|
1636 { |
|
1637 abi_long __key; |
|
1638 abi_ulong uid; |
|
1639 abi_ulong gid; |
|
1640 abi_ulong cuid; |
|
1641 abi_ulong cgid; |
|
1642 unsigned short int mode; |
|
1643 unsigned short int __pad1; |
|
1644 unsigned short int __seq; |
|
1645 unsigned short int __pad2; |
|
1646 abi_ulong __unused1; |
|
1647 abi_ulong __unused2; |
|
1648 }; |
|
1649 |
|
1650 struct target_semid_ds |
|
1651 { |
|
1652 struct target_ipc_perm sem_perm; |
|
1653 abi_ulong sem_otime; |
|
1654 abi_ulong __unused1; |
|
1655 abi_ulong sem_ctime; |
|
1656 abi_ulong __unused2; |
|
1657 abi_ulong sem_nsems; |
|
1658 abi_ulong __unused3; |
|
1659 abi_ulong __unused4; |
|
1660 }; |
|
1661 |
|
1662 static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, |
|
1663 abi_ulong target_addr) |
|
1664 { |
|
1665 struct target_ipc_perm *target_ip; |
|
1666 struct target_semid_ds *target_sd; |
|
1667 |
|
1668 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) |
|
1669 return -TARGET_EFAULT; |
|
1670 target_ip=&(target_sd->sem_perm); |
|
1671 host_ip->__key = tswapl(target_ip->__key); |
|
1672 host_ip->uid = tswapl(target_ip->uid); |
|
1673 host_ip->gid = tswapl(target_ip->gid); |
|
1674 host_ip->cuid = tswapl(target_ip->cuid); |
|
1675 host_ip->cgid = tswapl(target_ip->cgid); |
|
1676 host_ip->mode = tswapl(target_ip->mode); |
|
1677 unlock_user_struct(target_sd, target_addr, 0); |
|
1678 return 0; |
|
1679 } |
|
1680 |
|
1681 static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, |
|
1682 struct ipc_perm *host_ip) |
|
1683 { |
|
1684 struct target_ipc_perm *target_ip; |
|
1685 struct target_semid_ds *target_sd; |
|
1686 |
|
1687 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) |
|
1688 return -TARGET_EFAULT; |
|
1689 target_ip = &(target_sd->sem_perm); |
|
1690 target_ip->__key = tswapl(host_ip->__key); |
|
1691 target_ip->uid = tswapl(host_ip->uid); |
|
1692 target_ip->gid = tswapl(host_ip->gid); |
|
1693 target_ip->cuid = tswapl(host_ip->cuid); |
|
1694 target_ip->cgid = tswapl(host_ip->cgid); |
|
1695 target_ip->mode = tswapl(host_ip->mode); |
|
1696 unlock_user_struct(target_sd, target_addr, 1); |
|
1697 return 0; |
|
1698 } |
|
1699 |
|
1700 static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, |
|
1701 abi_ulong target_addr) |
|
1702 { |
|
1703 struct target_semid_ds *target_sd; |
|
1704 |
|
1705 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) |
|
1706 return -TARGET_EFAULT; |
|
1707 target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); |
|
1708 host_sd->sem_nsems = tswapl(target_sd->sem_nsems); |
|
1709 host_sd->sem_otime = tswapl(target_sd->sem_otime); |
|
1710 host_sd->sem_ctime = tswapl(target_sd->sem_ctime); |
|
1711 unlock_user_struct(target_sd, target_addr, 0); |
|
1712 return 0; |
|
1713 } |
|
1714 |
|
1715 static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, |
|
1716 struct semid_ds *host_sd) |
|
1717 { |
|
1718 struct target_semid_ds *target_sd; |
|
1719 |
|
1720 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) |
|
1721 return -TARGET_EFAULT; |
|
1722 host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); |
|
1723 target_sd->sem_nsems = tswapl(host_sd->sem_nsems); |
|
1724 target_sd->sem_otime = tswapl(host_sd->sem_otime); |
|
1725 target_sd->sem_ctime = tswapl(host_sd->sem_ctime); |
|
1726 unlock_user_struct(target_sd, target_addr, 1); |
|
1727 return 0; |
|
1728 } |
|
1729 |
|
1730 union semun { |
|
1731 int val; |
|
1732 struct semid_ds *buf; |
|
1733 unsigned short *array; |
|
1734 }; |
|
1735 |
|
1736 union target_semun { |
|
1737 int val; |
|
1738 abi_long buf; |
|
1739 unsigned short int *array; |
|
1740 }; |
|
1741 |
|
1742 static inline abi_long target_to_host_semun(int cmd, |
|
1743 union semun *host_su, |
|
1744 abi_ulong target_addr, |
|
1745 struct semid_ds *ds) |
|
1746 { |
|
1747 union target_semun *target_su; |
|
1748 |
|
1749 switch( cmd ) { |
|
1750 case IPC_STAT: |
|
1751 case IPC_SET: |
|
1752 if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) |
|
1753 return -TARGET_EFAULT; |
|
1754 target_to_host_semid_ds(ds,target_su->buf); |
|
1755 host_su->buf = ds; |
|
1756 unlock_user_struct(target_su, target_addr, 0); |
|
1757 break; |
|
1758 case GETVAL: |
|
1759 case SETVAL: |
|
1760 if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) |
|
1761 return -TARGET_EFAULT; |
|
1762 host_su->val = tswapl(target_su->val); |
|
1763 unlock_user_struct(target_su, target_addr, 0); |
|
1764 break; |
|
1765 case GETALL: |
|
1766 case SETALL: |
|
1767 if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) |
|
1768 return -TARGET_EFAULT; |
|
1769 *host_su->array = tswap16(*target_su->array); |
|
1770 unlock_user_struct(target_su, target_addr, 0); |
|
1771 break; |
|
1772 default: |
|
1773 gemu_log("semun operation not fully supported: %d\n", (int)cmd); |
|
1774 } |
|
1775 return 0; |
|
1776 } |
|
1777 |
|
1778 static inline abi_long host_to_target_semun(int cmd, |
|
1779 abi_ulong target_addr, |
|
1780 union semun *host_su, |
|
1781 struct semid_ds *ds) |
|
1782 { |
|
1783 union target_semun *target_su; |
|
1784 |
|
1785 switch( cmd ) { |
|
1786 case IPC_STAT: |
|
1787 case IPC_SET: |
|
1788 if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) |
|
1789 return -TARGET_EFAULT; |
|
1790 host_to_target_semid_ds(target_su->buf,ds); |
|
1791 unlock_user_struct(target_su, target_addr, 1); |
|
1792 break; |
|
1793 case GETVAL: |
|
1794 case SETVAL: |
|
1795 if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) |
|
1796 return -TARGET_EFAULT; |
|
1797 target_su->val = tswapl(host_su->val); |
|
1798 unlock_user_struct(target_su, target_addr, 1); |
|
1799 break; |
|
1800 case GETALL: |
|
1801 case SETALL: |
|
1802 if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) |
|
1803 return -TARGET_EFAULT; |
|
1804 *target_su->array = tswap16(*host_su->array); |
|
1805 unlock_user_struct(target_su, target_addr, 1); |
|
1806 break; |
|
1807 default: |
|
1808 gemu_log("semun operation not fully supported: %d\n", (int)cmd); |
|
1809 } |
|
1810 return 0; |
|
1811 } |
|
1812 |
|
1813 static inline abi_long do_semctl(int first, int second, int third, |
|
1814 abi_long ptr) |
|
1815 { |
|
1816 union semun arg; |
|
1817 struct semid_ds dsarg; |
|
1818 int cmd = third&0xff; |
|
1819 abi_long ret = 0; |
|
1820 |
|
1821 switch( cmd ) { |
|
1822 case GETVAL: |
|
1823 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1824 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1825 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1826 break; |
|
1827 case SETVAL: |
|
1828 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1829 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1830 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1831 break; |
|
1832 case GETALL: |
|
1833 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1834 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1835 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1836 break; |
|
1837 case SETALL: |
|
1838 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1839 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1840 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1841 break; |
|
1842 case IPC_STAT: |
|
1843 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1844 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1845 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1846 break; |
|
1847 case IPC_SET: |
|
1848 target_to_host_semun(cmd,&arg,ptr,&dsarg); |
|
1849 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1850 host_to_target_semun(cmd,ptr,&arg,&dsarg); |
|
1851 break; |
|
1852 default: |
|
1853 ret = get_errno(semctl(first, second, cmd, arg)); |
|
1854 } |
|
1855 |
|
1856 return ret; |
|
1857 } |
|
1858 |
|
1859 struct target_msqid_ds |
|
1860 { |
|
1861 struct target_ipc_perm msg_perm; |
|
1862 abi_ulong msg_stime; |
|
1863 #if TARGET_ABI_BITS == 32 |
|
1864 abi_ulong __unused1; |
|
1865 #endif |
|
1866 abi_ulong msg_rtime; |
|
1867 #if TARGET_ABI_BITS == 32 |
|
1868 abi_ulong __unused2; |
|
1869 #endif |
|
1870 abi_ulong msg_ctime; |
|
1871 #if TARGET_ABI_BITS == 32 |
|
1872 abi_ulong __unused3; |
|
1873 #endif |
|
1874 abi_ulong __msg_cbytes; |
|
1875 abi_ulong msg_qnum; |
|
1876 abi_ulong msg_qbytes; |
|
1877 abi_ulong msg_lspid; |
|
1878 abi_ulong msg_lrpid; |
|
1879 abi_ulong __unused4; |
|
1880 abi_ulong __unused5; |
|
1881 }; |
|
1882 |
|
1883 static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, |
|
1884 abi_ulong target_addr) |
|
1885 { |
|
1886 struct target_msqid_ds *target_md; |
|
1887 |
|
1888 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) |
|
1889 return -TARGET_EFAULT; |
|
1890 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr)) |
|
1891 return -TARGET_EFAULT; |
|
1892 host_md->msg_stime = tswapl(target_md->msg_stime); |
|
1893 host_md->msg_rtime = tswapl(target_md->msg_rtime); |
|
1894 host_md->msg_ctime = tswapl(target_md->msg_ctime); |
|
1895 host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes); |
|
1896 host_md->msg_qnum = tswapl(target_md->msg_qnum); |
|
1897 host_md->msg_qbytes = tswapl(target_md->msg_qbytes); |
|
1898 host_md->msg_lspid = tswapl(target_md->msg_lspid); |
|
1899 host_md->msg_lrpid = tswapl(target_md->msg_lrpid); |
|
1900 unlock_user_struct(target_md, target_addr, 0); |
|
1901 return 0; |
|
1902 } |
|
1903 |
|
1904 static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, |
|
1905 struct msqid_ds *host_md) |
|
1906 { |
|
1907 struct target_msqid_ds *target_md; |
|
1908 |
|
1909 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) |
|
1910 return -TARGET_EFAULT; |
|
1911 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm))) |
|
1912 return -TARGET_EFAULT; |
|
1913 target_md->msg_stime = tswapl(host_md->msg_stime); |
|
1914 target_md->msg_rtime = tswapl(host_md->msg_rtime); |
|
1915 target_md->msg_ctime = tswapl(host_md->msg_ctime); |
|
1916 target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes); |
|
1917 target_md->msg_qnum = tswapl(host_md->msg_qnum); |
|
1918 target_md->msg_qbytes = tswapl(host_md->msg_qbytes); |
|
1919 target_md->msg_lspid = tswapl(host_md->msg_lspid); |
|
1920 target_md->msg_lrpid = tswapl(host_md->msg_lrpid); |
|
1921 unlock_user_struct(target_md, target_addr, 1); |
|
1922 return 0; |
|
1923 } |
|
1924 |
|
1925 struct target_msginfo { |
|
1926 int msgpool; |
|
1927 int msgmap; |
|
1928 int msgmax; |
|
1929 int msgmnb; |
|
1930 int msgmni; |
|
1931 int msgssz; |
|
1932 int msgtql; |
|
1933 unsigned short int msgseg; |
|
1934 }; |
|
1935 |
|
1936 static inline abi_long host_to_target_msginfo(abi_ulong target_addr, |
|
1937 struct msginfo *host_msginfo) |
|
1938 { |
|
1939 struct target_msginfo *target_msginfo; |
|
1940 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0)) |
|
1941 return -TARGET_EFAULT; |
|
1942 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool); |
|
1943 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap); |
|
1944 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax); |
|
1945 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb); |
|
1946 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni); |
|
1947 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz); |
|
1948 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql); |
|
1949 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg); |
|
1950 unlock_user_struct(target_msginfo, target_addr, 1); |
|
1951 return 0; |
|
1952 } |
|
1953 |
|
1954 static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr) |
|
1955 { |
|
1956 struct msqid_ds dsarg; |
|
1957 struct msginfo msginfo; |
|
1958 abi_long ret = -TARGET_EINVAL; |
|
1959 |
|
1960 cmd &= 0xff; |
|
1961 |
|
1962 switch (cmd) { |
|
1963 case IPC_STAT: |
|
1964 case IPC_SET: |
|
1965 case MSG_STAT: |
|
1966 if (target_to_host_msqid_ds(&dsarg,ptr)) |
|
1967 return -TARGET_EFAULT; |
|
1968 ret = get_errno(msgctl(msgid, cmd, &dsarg)); |
|
1969 if (host_to_target_msqid_ds(ptr,&dsarg)) |
|
1970 return -TARGET_EFAULT; |
|
1971 break; |
|
1972 case IPC_RMID: |
|
1973 ret = get_errno(msgctl(msgid, cmd, NULL)); |
|
1974 break; |
|
1975 case IPC_INFO: |
|
1976 case MSG_INFO: |
|
1977 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo)); |
|
1978 if (host_to_target_msginfo(ptr, &msginfo)) |
|
1979 return -TARGET_EFAULT; |
|
1980 break; |
|
1981 } |
|
1982 |
|
1983 return ret; |
|
1984 } |
|
1985 |
|
1986 struct target_msgbuf { |
|
1987 abi_long mtype; |
|
1988 char mtext[1]; |
|
1989 }; |
|
1990 |
|
1991 static inline abi_long do_msgsnd(int msqid, abi_long msgp, |
|
1992 unsigned int msgsz, int msgflg) |
|
1993 { |
|
1994 struct target_msgbuf *target_mb; |
|
1995 struct msgbuf *host_mb; |
|
1996 abi_long ret = 0; |
|
1997 |
|
1998 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) |
|
1999 return -TARGET_EFAULT; |
|
2000 host_mb = malloc(msgsz+sizeof(long)); |
|
2001 host_mb->mtype = (abi_long) tswapl(target_mb->mtype); |
|
2002 memcpy(host_mb->mtext, target_mb->mtext, msgsz); |
|
2003 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg)); |
|
2004 free(host_mb); |
|
2005 unlock_user_struct(target_mb, msgp, 0); |
|
2006 |
|
2007 return ret; |
|
2008 } |
|
2009 |
|
2010 static inline abi_long do_msgrcv(int msqid, abi_long msgp, |
|
2011 unsigned int msgsz, abi_long msgtyp, |
|
2012 int msgflg) |
|
2013 { |
|
2014 struct target_msgbuf *target_mb; |
|
2015 char *target_mtext; |
|
2016 struct msgbuf *host_mb; |
|
2017 abi_long ret = 0; |
|
2018 |
|
2019 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) |
|
2020 return -TARGET_EFAULT; |
|
2021 |
|
2022 host_mb = malloc(msgsz+sizeof(long)); |
|
2023 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg)); |
|
2024 |
|
2025 if (ret > 0) { |
|
2026 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); |
|
2027 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0); |
|
2028 if (!target_mtext) { |
|
2029 ret = -TARGET_EFAULT; |
|
2030 goto end; |
|
2031 } |
|
2032 memcpy(target_mb->mtext, host_mb->mtext, ret); |
|
2033 unlock_user(target_mtext, target_mtext_addr, ret); |
|
2034 } |
|
2035 |
|
2036 target_mb->mtype = tswapl(host_mb->mtype); |
|
2037 free(host_mb); |
|
2038 |
|
2039 end: |
|
2040 if (target_mb) |
|
2041 unlock_user_struct(target_mb, msgp, 1); |
|
2042 return ret; |
|
2043 } |
|
2044 |
|
2045 #ifdef TARGET_NR_ipc |
|
2046 /* ??? This only works with linear mappings. */ |
|
2047 /* do_ipc() must return target values and target errnos. */ |
|
2048 static abi_long do_ipc(unsigned int call, int first, |
|
2049 int second, int third, |
|
2050 abi_long ptr, abi_long fifth) |
|
2051 { |
|
2052 int version; |
|
2053 abi_long ret = 0; |
|
2054 struct shmid_ds shm_info; |
|
2055 int i; |
|
2056 |
|
2057 version = call >> 16; |
|
2058 call &= 0xffff; |
|
2059 |
|
2060 switch (call) { |
|
2061 case IPCOP_semop: |
|
2062 ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); |
|
2063 break; |
|
2064 |
|
2065 case IPCOP_semget: |
|
2066 ret = get_errno(semget(first, second, third)); |
|
2067 break; |
|
2068 |
|
2069 case IPCOP_semctl: |
|
2070 ret = do_semctl(first, second, third, ptr); |
|
2071 break; |
|
2072 |
|
2073 case IPCOP_semtimedop: |
|
2074 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); |
|
2075 ret = -TARGET_ENOSYS; |
|
2076 break; |
|
2077 |
|
2078 case IPCOP_msgget: |
|
2079 ret = get_errno(msgget(first, second)); |
|
2080 break; |
|
2081 |
|
2082 case IPCOP_msgsnd: |
|
2083 ret = do_msgsnd(first, ptr, second, third); |
|
2084 break; |
|
2085 |
|
2086 case IPCOP_msgctl: |
|
2087 ret = do_msgctl(first, second, ptr); |
|
2088 break; |
|
2089 |
|
2090 case IPCOP_msgrcv: |
|
2091 switch (version) { |
|
2092 case 0: |
|
2093 { |
|
2094 struct target_ipc_kludge { |
|
2095 abi_long msgp; |
|
2096 abi_long msgtyp; |
|
2097 } *tmp; |
|
2098 |
|
2099 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) { |
|
2100 ret = -TARGET_EFAULT; |
|
2101 break; |
|
2102 } |
|
2103 |
|
2104 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third); |
|
2105 |
|
2106 unlock_user_struct(tmp, ptr, 0); |
|
2107 break; |
|
2108 } |
|
2109 default: |
|
2110 ret = do_msgrcv(first, ptr, second, fifth, third); |
|
2111 } |
|
2112 break; |
|
2113 |
|
2114 case IPCOP_shmat: |
|
2115 { |
|
2116 abi_ulong raddr; |
|
2117 void *host_addr; |
|
2118 /* SHM_* flags are the same on all linux platforms */ |
|
2119 host_addr = shmat(first, (void *)g2h(ptr), second); |
|
2120 if (host_addr == (void *)-1) { |
|
2121 ret = get_errno((long)host_addr); |
|
2122 break; |
|
2123 } |
|
2124 raddr = h2g((unsigned long)host_addr); |
|
2125 /* find out the length of the shared memory segment */ |
|
2126 |
|
2127 ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); |
|
2128 if (is_error(ret)) { |
|
2129 /* can't get length, bail out */ |
|
2130 shmdt(host_addr); |
|
2131 break; |
|
2132 } |
|
2133 page_set_flags(raddr, raddr + shm_info.shm_segsz, |
|
2134 PAGE_VALID | PAGE_READ | |
|
2135 ((second & SHM_RDONLY)? 0: PAGE_WRITE)); |
|
2136 for (i = 0; i < N_SHM_REGIONS; ++i) { |
|
2137 if (shm_regions[i].start == 0) { |
|
2138 shm_regions[i].start = raddr; |
|
2139 shm_regions[i].size = shm_info.shm_segsz; |
|
2140 break; |
|
2141 } |
|
2142 } |
|
2143 if (put_user_ual(raddr, third)) |
|
2144 return -TARGET_EFAULT; |
|
2145 ret = 0; |
|
2146 } |
|
2147 break; |
|
2148 case IPCOP_shmdt: |
|
2149 for (i = 0; i < N_SHM_REGIONS; ++i) { |
|
2150 if (shm_regions[i].start == ptr) { |
|
2151 shm_regions[i].start = 0; |
|
2152 page_set_flags(ptr, shm_regions[i].size, 0); |
|
2153 break; |
|
2154 } |
|
2155 } |
|
2156 ret = get_errno(shmdt((void *)g2h(ptr))); |
|
2157 break; |
|
2158 |
|
2159 case IPCOP_shmget: |
|
2160 /* IPC_* flag values are the same on all linux platforms */ |
|
2161 ret = get_errno(shmget(first, second, third)); |
|
2162 break; |
|
2163 |
|
2164 /* IPC_* and SHM_* command values are the same on all linux platforms */ |
|
2165 case IPCOP_shmctl: |
|
2166 switch(second) { |
|
2167 case IPC_RMID: |
|
2168 case SHM_LOCK: |
|
2169 case SHM_UNLOCK: |
|
2170 ret = get_errno(shmctl(first, second, NULL)); |
|
2171 break; |
|
2172 default: |
|
2173 goto unimplemented; |
|
2174 } |
|
2175 break; |
|
2176 default: |
|
2177 unimplemented: |
|
2178 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); |
|
2179 ret = -TARGET_ENOSYS; |
|
2180 break; |
|
2181 } |
|
2182 return ret; |
|
2183 } |
|
2184 #endif |
|
2185 |
|
2186 /* kernel structure types definitions */ |
|
2187 #define IFNAMSIZ 16 |
|
2188 |
|
2189 #define STRUCT(name, list...) STRUCT_ ## name, |
|
2190 #define STRUCT_SPECIAL(name) STRUCT_ ## name, |
|
2191 enum { |
|
2192 #include "syscall_types.h" |
|
2193 }; |
|
2194 #undef STRUCT |
|
2195 #undef STRUCT_SPECIAL |
|
2196 |
|
2197 #define STRUCT(name, list...) static const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; |
|
2198 #define STRUCT_SPECIAL(name) |
|
2199 #include "syscall_types.h" |
|
2200 #undef STRUCT |
|
2201 #undef STRUCT_SPECIAL |
|
2202 |
|
2203 typedef struct IOCTLEntry { |
|
2204 unsigned int target_cmd; |
|
2205 unsigned int host_cmd; |
|
2206 const char *name; |
|
2207 int access; |
|
2208 const argtype arg_type[5]; |
|
2209 } IOCTLEntry; |
|
2210 |
|
2211 #define IOC_R 0x0001 |
|
2212 #define IOC_W 0x0002 |
|
2213 #define IOC_RW (IOC_R | IOC_W) |
|
2214 |
|
2215 #define MAX_STRUCT_SIZE 4096 |
|
2216 |
|
2217 static IOCTLEntry ioctl_entries[] = { |
|
2218 #define IOCTL(cmd, access, types...) \ |
|
2219 { TARGET_ ## cmd, cmd, #cmd, access, { types } }, |
|
2220 #include "ioctls.h" |
|
2221 { 0, 0, }, |
|
2222 }; |
|
2223 |
|
2224 /* ??? Implement proper locking for ioctls. */ |
|
2225 /* do_ioctl() Must return target values and target errnos. */ |
|
2226 static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) |
|
2227 { |
|
2228 const IOCTLEntry *ie; |
|
2229 const argtype *arg_type; |
|
2230 abi_long ret; |
|
2231 uint8_t buf_temp[MAX_STRUCT_SIZE]; |
|
2232 int target_size; |
|
2233 void *argptr; |
|
2234 |
|
2235 ie = ioctl_entries; |
|
2236 for(;;) { |
|
2237 if (ie->target_cmd == 0) { |
|
2238 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); |
|
2239 return -TARGET_ENOSYS; |
|
2240 } |
|
2241 if (ie->target_cmd == cmd) |
|
2242 break; |
|
2243 ie++; |
|
2244 } |
|
2245 arg_type = ie->arg_type; |
|
2246 #if defined(DEBUG) |
|
2247 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name); |
|
2248 #endif |
|
2249 switch(arg_type[0]) { |
|
2250 case TYPE_NULL: |
|
2251 /* no argument */ |
|
2252 ret = get_errno(ioctl(fd, ie->host_cmd)); |
|
2253 break; |
|
2254 case TYPE_PTRVOID: |
|
2255 case TYPE_INT: |
|
2256 /* int argment */ |
|
2257 ret = get_errno(ioctl(fd, ie->host_cmd, arg)); |
|
2258 break; |
|
2259 case TYPE_PTR: |
|
2260 arg_type++; |
|
2261 target_size = thunk_type_size(arg_type, 0); |
|
2262 switch(ie->access) { |
|
2263 case IOC_R: |
|
2264 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); |
|
2265 if (!is_error(ret)) { |
|
2266 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); |
|
2267 if (!argptr) |
|
2268 return -TARGET_EFAULT; |
|
2269 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); |
|
2270 unlock_user(argptr, arg, target_size); |
|
2271 } |
|
2272 break; |
|
2273 case IOC_W: |
|
2274 argptr = lock_user(VERIFY_READ, arg, target_size, 1); |
|
2275 if (!argptr) |
|
2276 return -TARGET_EFAULT; |
|
2277 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); |
|
2278 unlock_user(argptr, arg, 0); |
|
2279 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); |
|
2280 break; |
|
2281 default: |
|
2282 case IOC_RW: |
|
2283 argptr = lock_user(VERIFY_READ, arg, target_size, 1); |
|
2284 if (!argptr) |
|
2285 return -TARGET_EFAULT; |
|
2286 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); |
|
2287 unlock_user(argptr, arg, 0); |
|
2288 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); |
|
2289 if (!is_error(ret)) { |
|
2290 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); |
|
2291 if (!argptr) |
|
2292 return -TARGET_EFAULT; |
|
2293 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); |
|
2294 unlock_user(argptr, arg, target_size); |
|
2295 } |
|
2296 break; |
|
2297 } |
|
2298 break; |
|
2299 default: |
|
2300 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", |
|
2301 (long)cmd, arg_type[0]); |
|
2302 ret = -TARGET_ENOSYS; |
|
2303 break; |
|
2304 } |
|
2305 return ret; |
|
2306 } |
|
2307 |
|
2308 static const bitmask_transtbl iflag_tbl[] = { |
|
2309 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK }, |
|
2310 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT }, |
|
2311 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR }, |
|
2312 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK }, |
|
2313 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK }, |
|
2314 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP }, |
|
2315 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR }, |
|
2316 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR }, |
|
2317 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL }, |
|
2318 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC }, |
|
2319 { TARGET_IXON, TARGET_IXON, IXON, IXON }, |
|
2320 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY }, |
|
2321 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF }, |
|
2322 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL }, |
|
2323 { 0, 0, 0, 0 } |
|
2324 }; |
|
2325 |
|
2326 static const bitmask_transtbl oflag_tbl[] = { |
|
2327 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST }, |
|
2328 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC }, |
|
2329 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR }, |
|
2330 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL }, |
|
2331 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR }, |
|
2332 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET }, |
|
2333 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL }, |
|
2334 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL }, |
|
2335 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 }, |
|
2336 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 }, |
|
2337 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 }, |
|
2338 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 }, |
|
2339 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 }, |
|
2340 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 }, |
|
2341 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 }, |
|
2342 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 }, |
|
2343 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 }, |
|
2344 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 }, |
|
2345 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 }, |
|
2346 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 }, |
|
2347 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 }, |
|
2348 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 }, |
|
2349 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 }, |
|
2350 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 }, |
|
2351 { 0, 0, 0, 0 } |
|
2352 }; |
|
2353 |
|
2354 static const bitmask_transtbl cflag_tbl[] = { |
|
2355 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 }, |
|
2356 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 }, |
|
2357 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 }, |
|
2358 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 }, |
|
2359 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 }, |
|
2360 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 }, |
|
2361 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 }, |
|
2362 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 }, |
|
2363 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 }, |
|
2364 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 }, |
|
2365 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 }, |
|
2366 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 }, |
|
2367 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 }, |
|
2368 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 }, |
|
2369 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 }, |
|
2370 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 }, |
|
2371 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 }, |
|
2372 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 }, |
|
2373 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 }, |
|
2374 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 }, |
|
2375 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 }, |
|
2376 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 }, |
|
2377 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 }, |
|
2378 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 }, |
|
2379 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB }, |
|
2380 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD }, |
|
2381 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB }, |
|
2382 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD }, |
|
2383 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL }, |
|
2384 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL }, |
|
2385 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS }, |
|
2386 { 0, 0, 0, 0 } |
|
2387 }; |
|
2388 |
|
2389 static const bitmask_transtbl lflag_tbl[] = { |
|
2390 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG }, |
|
2391 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON }, |
|
2392 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE }, |
|
2393 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO }, |
|
2394 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE }, |
|
2395 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK }, |
|
2396 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL }, |
|
2397 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH }, |
|
2398 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP }, |
|
2399 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL }, |
|
2400 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT }, |
|
2401 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE }, |
|
2402 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO }, |
|
2403 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN }, |
|
2404 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN }, |
|
2405 { 0, 0, 0, 0 } |
|
2406 }; |
|
2407 |
|
2408 static void target_to_host_termios (void *dst, const void *src) |
|
2409 { |
|
2410 struct host_termios *host = dst; |
|
2411 const struct target_termios *target = src; |
|
2412 |
|
2413 host->c_iflag = |
|
2414 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); |
|
2415 host->c_oflag = |
|
2416 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl); |
|
2417 host->c_cflag = |
|
2418 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); |
|
2419 host->c_lflag = |
|
2420 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); |
|
2421 host->c_line = target->c_line; |
|
2422 |
|
2423 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; |
|
2424 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; |
|
2425 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; |
|
2426 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; |
|
2427 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; |
|
2428 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; |
|
2429 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; |
|
2430 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; |
|
2431 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; |
|
2432 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; |
|
2433 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; |
|
2434 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; |
|
2435 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; |
|
2436 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; |
|
2437 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; |
|
2438 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; |
|
2439 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; |
|
2440 } |
|
2441 |
|
2442 static void host_to_target_termios (void *dst, const void *src) |
|
2443 { |
|
2444 struct target_termios *target = dst; |
|
2445 const struct host_termios *host = src; |
|
2446 |
|
2447 target->c_iflag = |
|
2448 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl)); |
|
2449 target->c_oflag = |
|
2450 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl)); |
|
2451 target->c_cflag = |
|
2452 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); |
|
2453 target->c_lflag = |
|
2454 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); |
|
2455 target->c_line = host->c_line; |
|
2456 |
|
2457 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; |
|
2458 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; |
|
2459 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; |
|
2460 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL]; |
|
2461 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF]; |
|
2462 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME]; |
|
2463 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN]; |
|
2464 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC]; |
|
2465 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART]; |
|
2466 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP]; |
|
2467 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP]; |
|
2468 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL]; |
|
2469 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT]; |
|
2470 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD]; |
|
2471 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE]; |
|
2472 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT]; |
|
2473 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; |
|
2474 } |
|
2475 |
|
2476 static const StructEntry struct_termios_def = { |
|
2477 .convert = { host_to_target_termios, target_to_host_termios }, |
|
2478 .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, |
|
2479 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, |
|
2480 }; |
|
2481 |
|
2482 static bitmask_transtbl mmap_flags_tbl[] = { |
|
2483 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED }, |
|
2484 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE }, |
|
2485 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, |
|
2486 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS }, |
|
2487 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN }, |
|
2488 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE }, |
|
2489 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE }, |
|
2490 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED }, |
|
2491 { 0, 0, 0, 0 } |
|
2492 }; |
|
2493 |
|
2494 static bitmask_transtbl fcntl_flags_tbl[] = { |
|
2495 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, |
|
2496 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, }, |
|
2497 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, }, |
|
2498 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, }, |
|
2499 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, }, |
|
2500 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, }, |
|
2501 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, }, |
|
2502 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, }, |
|
2503 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, }, |
|
2504 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, }, |
|
2505 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, }, |
|
2506 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, }, |
|
2507 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, }, |
|
2508 #if defined(O_DIRECT) |
|
2509 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, }, |
|
2510 #endif |
|
2511 { 0, 0, 0, 0 } |
|
2512 }; |
|
2513 |
|
2514 #if defined(TARGET_I386) |
|
2515 |
|
2516 /* NOTE: there is really one LDT for all the threads */ |
|
2517 static uint8_t *ldt_table; |
|
2518 |
|
2519 static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount) |
|
2520 { |
|
2521 int size; |
|
2522 void *p; |
|
2523 |
|
2524 if (!ldt_table) |
|
2525 return 0; |
|
2526 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; |
|
2527 if (size > bytecount) |
|
2528 size = bytecount; |
|
2529 p = lock_user(VERIFY_WRITE, ptr, size, 0); |
|
2530 if (!p) |
|
2531 return -TARGET_EFAULT; |
|
2532 /* ??? Should this by byteswapped? */ |
|
2533 memcpy(p, ldt_table, size); |
|
2534 unlock_user(p, ptr, size); |
|
2535 return size; |
|
2536 } |
|
2537 |
|
2538 /* XXX: add locking support */ |
|
2539 static abi_long write_ldt(CPUX86State *env, |
|
2540 abi_ulong ptr, unsigned long bytecount, int oldmode) |
|
2541 { |
|
2542 struct target_modify_ldt_ldt_s ldt_info; |
|
2543 struct target_modify_ldt_ldt_s *target_ldt_info; |
|
2544 int seg_32bit, contents, read_exec_only, limit_in_pages; |
|
2545 int seg_not_present, useable, lm; |
|
2546 uint32_t *lp, entry_1, entry_2; |
|
2547 |
|
2548 if (bytecount != sizeof(ldt_info)) |
|
2549 return -TARGET_EINVAL; |
|
2550 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) |
|
2551 return -TARGET_EFAULT; |
|
2552 ldt_info.entry_number = tswap32(target_ldt_info->entry_number); |
|
2553 ldt_info.base_addr = tswapl(target_ldt_info->base_addr); |
|
2554 ldt_info.limit = tswap32(target_ldt_info->limit); |
|
2555 ldt_info.flags = tswap32(target_ldt_info->flags); |
|
2556 unlock_user_struct(target_ldt_info, ptr, 0); |
|
2557 |
|
2558 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) |
|
2559 return -TARGET_EINVAL; |
|
2560 seg_32bit = ldt_info.flags & 1; |
|
2561 contents = (ldt_info.flags >> 1) & 3; |
|
2562 read_exec_only = (ldt_info.flags >> 3) & 1; |
|
2563 limit_in_pages = (ldt_info.flags >> 4) & 1; |
|
2564 seg_not_present = (ldt_info.flags >> 5) & 1; |
|
2565 useable = (ldt_info.flags >> 6) & 1; |
|
2566 #ifdef TARGET_ABI32 |
|
2567 lm = 0; |
|
2568 #else |
|
2569 lm = (ldt_info.flags >> 7) & 1; |
|
2570 #endif |
|
2571 if (contents == 3) { |
|
2572 if (oldmode) |
|
2573 return -TARGET_EINVAL; |
|
2574 if (seg_not_present == 0) |
|
2575 return -TARGET_EINVAL; |
|
2576 } |
|
2577 /* allocate the LDT */ |
|
2578 if (!ldt_table) { |
|
2579 env->ldt.base = target_mmap(0, |
|
2580 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE, |
|
2581 PROT_READ|PROT_WRITE, |
|
2582 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
|
2583 if (env->ldt.base == -1) |
|
2584 return -TARGET_ENOMEM; |
|
2585 memset(g2h(env->ldt.base), 0, |
|
2586 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); |
|
2587 env->ldt.limit = 0xffff; |
|
2588 ldt_table = g2h(env->ldt.base); |
|
2589 } |
|
2590 |
|
2591 /* NOTE: same code as Linux kernel */ |
|
2592 /* Allow LDTs to be cleared by the user. */ |
|
2593 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { |
|
2594 if (oldmode || |
|
2595 (contents == 0 && |
|
2596 read_exec_only == 1 && |
|
2597 seg_32bit == 0 && |
|
2598 limit_in_pages == 0 && |
|
2599 seg_not_present == 1 && |
|
2600 useable == 0 )) { |
|
2601 entry_1 = 0; |
|
2602 entry_2 = 0; |
|
2603 goto install; |
|
2604 } |
|
2605 } |
|
2606 |
|
2607 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | |
|
2608 (ldt_info.limit & 0x0ffff); |
|
2609 entry_2 = (ldt_info.base_addr & 0xff000000) | |
|
2610 ((ldt_info.base_addr & 0x00ff0000) >> 16) | |
|
2611 (ldt_info.limit & 0xf0000) | |
|
2612 ((read_exec_only ^ 1) << 9) | |
|
2613 (contents << 10) | |
|
2614 ((seg_not_present ^ 1) << 15) | |
|
2615 (seg_32bit << 22) | |
|
2616 (limit_in_pages << 23) | |
|
2617 (lm << 21) | |
|
2618 0x7000; |
|
2619 if (!oldmode) |
|
2620 entry_2 |= (useable << 20); |
|
2621 |
|
2622 /* Install the new entry ... */ |
|
2623 install: |
|
2624 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); |
|
2625 lp[0] = tswap32(entry_1); |
|
2626 lp[1] = tswap32(entry_2); |
|
2627 return 0; |
|
2628 } |
|
2629 |
|
2630 /* specific and weird i386 syscalls */ |
|
2631 static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, |
|
2632 unsigned long bytecount) |
|
2633 { |
|
2634 abi_long ret; |
|
2635 |
|
2636 switch (func) { |
|
2637 case 0: |
|
2638 ret = read_ldt(ptr, bytecount); |
|
2639 break; |
|
2640 case 1: |
|
2641 ret = write_ldt(env, ptr, bytecount, 1); |
|
2642 break; |
|
2643 case 0x11: |
|
2644 ret = write_ldt(env, ptr, bytecount, 0); |
|
2645 break; |
|
2646 default: |
|
2647 ret = -TARGET_ENOSYS; |
|
2648 break; |
|
2649 } |
|
2650 return ret; |
|
2651 } |
|
2652 |
|
2653 #if defined(TARGET_I386) && defined(TARGET_ABI32) |
|
2654 static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) |
|
2655 { |
|
2656 uint64_t *gdt_table = g2h(env->gdt.base); |
|
2657 struct target_modify_ldt_ldt_s ldt_info; |
|
2658 struct target_modify_ldt_ldt_s *target_ldt_info; |
|
2659 int seg_32bit, contents, read_exec_only, limit_in_pages; |
|
2660 int seg_not_present, useable, lm; |
|
2661 uint32_t *lp, entry_1, entry_2; |
|
2662 int i; |
|
2663 |
|
2664 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); |
|
2665 if (!target_ldt_info) |
|
2666 return -TARGET_EFAULT; |
|
2667 ldt_info.entry_number = tswap32(target_ldt_info->entry_number); |
|
2668 ldt_info.base_addr = tswapl(target_ldt_info->base_addr); |
|
2669 ldt_info.limit = tswap32(target_ldt_info->limit); |
|
2670 ldt_info.flags = tswap32(target_ldt_info->flags); |
|
2671 if (ldt_info.entry_number == -1) { |
|
2672 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) { |
|
2673 if (gdt_table[i] == 0) { |
|
2674 ldt_info.entry_number = i; |
|
2675 target_ldt_info->entry_number = tswap32(i); |
|
2676 break; |
|
2677 } |
|
2678 } |
|
2679 } |
|
2680 unlock_user_struct(target_ldt_info, ptr, 1); |
|
2681 |
|
2682 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || |
|
2683 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX) |
|
2684 return -TARGET_EINVAL; |
|
2685 seg_32bit = ldt_info.flags & 1; |
|
2686 contents = (ldt_info.flags >> 1) & 3; |
|
2687 read_exec_only = (ldt_info.flags >> 3) & 1; |
|
2688 limit_in_pages = (ldt_info.flags >> 4) & 1; |
|
2689 seg_not_present = (ldt_info.flags >> 5) & 1; |
|
2690 useable = (ldt_info.flags >> 6) & 1; |
|
2691 #ifdef TARGET_ABI32 |
|
2692 lm = 0; |
|
2693 #else |
|
2694 lm = (ldt_info.flags >> 7) & 1; |
|
2695 #endif |
|
2696 |
|
2697 if (contents == 3) { |
|
2698 if (seg_not_present == 0) |
|
2699 return -TARGET_EINVAL; |
|
2700 } |
|
2701 |
|
2702 /* NOTE: same code as Linux kernel */ |
|
2703 /* Allow LDTs to be cleared by the user. */ |
|
2704 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { |
|
2705 if ((contents == 0 && |
|
2706 read_exec_only == 1 && |
|
2707 seg_32bit == 0 && |
|
2708 limit_in_pages == 0 && |
|
2709 seg_not_present == 1 && |
|
2710 useable == 0 )) { |
|
2711 entry_1 = 0; |
|
2712 entry_2 = 0; |
|
2713 goto install; |
|
2714 } |
|
2715 } |
|
2716 |
|
2717 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | |
|
2718 (ldt_info.limit & 0x0ffff); |
|
2719 entry_2 = (ldt_info.base_addr & 0xff000000) | |
|
2720 ((ldt_info.base_addr & 0x00ff0000) >> 16) | |
|
2721 (ldt_info.limit & 0xf0000) | |
|
2722 ((read_exec_only ^ 1) << 9) | |
|
2723 (contents << 10) | |
|
2724 ((seg_not_present ^ 1) << 15) | |
|
2725 (seg_32bit << 22) | |
|
2726 (limit_in_pages << 23) | |
|
2727 (useable << 20) | |
|
2728 (lm << 21) | |
|
2729 0x7000; |
|
2730 |
|
2731 /* Install the new entry ... */ |
|
2732 install: |
|
2733 lp = (uint32_t *)(gdt_table + ldt_info.entry_number); |
|
2734 lp[0] = tswap32(entry_1); |
|
2735 lp[1] = tswap32(entry_2); |
|
2736 return 0; |
|
2737 } |
|
2738 |
|
2739 static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) |
|
2740 { |
|
2741 struct target_modify_ldt_ldt_s *target_ldt_info; |
|
2742 uint64_t *gdt_table = g2h(env->gdt.base); |
|
2743 uint32_t base_addr, limit, flags; |
|
2744 int seg_32bit, contents, read_exec_only, limit_in_pages, idx; |
|
2745 int seg_not_present, useable, lm; |
|
2746 uint32_t *lp, entry_1, entry_2; |
|
2747 |
|
2748 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); |
|
2749 if (!target_ldt_info) |
|
2750 return -TARGET_EFAULT; |
|
2751 idx = tswap32(target_ldt_info->entry_number); |
|
2752 if (idx < TARGET_GDT_ENTRY_TLS_MIN || |
|
2753 idx > TARGET_GDT_ENTRY_TLS_MAX) { |
|
2754 unlock_user_struct(target_ldt_info, ptr, 1); |
|
2755 return -TARGET_EINVAL; |
|
2756 } |
|
2757 lp = (uint32_t *)(gdt_table + idx); |
|
2758 entry_1 = tswap32(lp[0]); |
|
2759 entry_2 = tswap32(lp[1]); |
|
2760 |
|
2761 read_exec_only = ((entry_2 >> 9) & 1) ^ 1; |
|
2762 contents = (entry_2 >> 10) & 3; |
|
2763 seg_not_present = ((entry_2 >> 15) & 1) ^ 1; |
|
2764 seg_32bit = (entry_2 >> 22) & 1; |
|
2765 limit_in_pages = (entry_2 >> 23) & 1; |
|
2766 useable = (entry_2 >> 20) & 1; |
|
2767 #ifdef TARGET_ABI32 |
|
2768 lm = 0; |
|
2769 #else |
|
2770 lm = (entry_2 >> 21) & 1; |
|
2771 #endif |
|
2772 flags = (seg_32bit << 0) | (contents << 1) | |
|
2773 (read_exec_only << 3) | (limit_in_pages << 4) | |
|
2774 (seg_not_present << 5) | (useable << 6) | (lm << 7); |
|
2775 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000); |
|
2776 base_addr = (entry_1 >> 16) | |
|
2777 (entry_2 & 0xff000000) | |
|
2778 ((entry_2 & 0xff) << 16); |
|
2779 target_ldt_info->base_addr = tswapl(base_addr); |
|
2780 target_ldt_info->limit = tswap32(limit); |
|
2781 target_ldt_info->flags = tswap32(flags); |
|
2782 unlock_user_struct(target_ldt_info, ptr, 1); |
|
2783 return 0; |
|
2784 } |
|
2785 #endif /* TARGET_I386 && TARGET_ABI32 */ |
|
2786 |
|
2787 #ifndef TARGET_ABI32 |
|
2788 static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) |
|
2789 { |
|
2790 abi_long ret; |
|
2791 abi_ulong val; |
|
2792 int idx; |
|
2793 |
|
2794 switch(code) { |
|
2795 case TARGET_ARCH_SET_GS: |
|
2796 case TARGET_ARCH_SET_FS: |
|
2797 if (code == TARGET_ARCH_SET_GS) |
|
2798 idx = R_GS; |
|
2799 else |
|
2800 idx = R_FS; |
|
2801 cpu_x86_load_seg(env, idx, 0); |
|
2802 env->segs[idx].base = addr; |
|
2803 break; |
|
2804 case TARGET_ARCH_GET_GS: |
|
2805 case TARGET_ARCH_GET_FS: |
|
2806 if (code == TARGET_ARCH_GET_GS) |
|
2807 idx = R_GS; |
|
2808 else |
|
2809 idx = R_FS; |
|
2810 val = env->segs[idx].base; |
|
2811 if (put_user(val, addr, abi_ulong)) |
|
2812 return -TARGET_EFAULT; |
|
2813 break; |
|
2814 default: |
|
2815 ret = -TARGET_EINVAL; |
|
2816 break; |
|
2817 } |
|
2818 return 0; |
|
2819 } |
|
2820 #endif |
|
2821 |
|
2822 #endif /* defined(TARGET_I386) */ |
|
2823 |
|
2824 #if defined(USE_NPTL) |
|
2825 |
|
2826 #define NEW_STACK_SIZE PTHREAD_STACK_MIN |
|
2827 |
|
2828 static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER; |
|
2829 typedef struct { |
|
2830 CPUState *env; |
|
2831 pthread_mutex_t mutex; |
|
2832 pthread_cond_t cond; |
|
2833 pthread_t thread; |
|
2834 uint32_t tid; |
|
2835 abi_ulong child_tidptr; |
|
2836 abi_ulong parent_tidptr; |
|
2837 sigset_t sigmask; |
|
2838 } new_thread_info; |
|
2839 |
|
2840 static void *clone_func(void *arg) |
|
2841 { |
|
2842 new_thread_info *info = arg; |
|
2843 CPUState *env; |
|
2844 |
|
2845 env = info->env; |
|
2846 thread_env = env; |
|
2847 info->tid = gettid(); |
|
2848 if (info->child_tidptr) |
|
2849 put_user_u32(info->tid, info->child_tidptr); |
|
2850 if (info->parent_tidptr) |
|
2851 put_user_u32(info->tid, info->parent_tidptr); |
|
2852 /* Enable signals. */ |
|
2853 sigprocmask(SIG_SETMASK, &info->sigmask, NULL); |
|
2854 /* Signal to the parent that we're ready. */ |
|
2855 pthread_mutex_lock(&info->mutex); |
|
2856 pthread_cond_broadcast(&info->cond); |
|
2857 pthread_mutex_unlock(&info->mutex); |
|
2858 /* Wait until the parent has finshed initializing the tls state. */ |
|
2859 pthread_mutex_lock(&clone_lock); |
|
2860 pthread_mutex_unlock(&clone_lock); |
|
2861 cpu_loop(env); |
|
2862 /* never exits */ |
|
2863 return NULL; |
|
2864 } |
|
2865 #else |
|
2866 /* this stack is the equivalent of the kernel stack associated with a |
|
2867 thread/process */ |
|
2868 #define NEW_STACK_SIZE 8192 |
|
2869 |
|
2870 #ifdef USE_NPTL |
|
2871 static spinlock_t nptl_lock = SPIN_LOCK_UNLOCKED; |
|
2872 #endif |
|
2873 |
|
2874 static int clone_func(void *arg) |
|
2875 { |
|
2876 CPUState *env = arg; |
|
2877 #ifdef HAVE_NPTL |
|
2878 /* Wait until the parent has finshed initializing the tls state. */ |
|
2879 while (!spin_trylock(&nptl_lock)) |
|
2880 usleep(1); |
|
2881 spin_unlock(&nptl_lock); |
|
2882 #endif |
|
2883 cpu_loop(env); |
|
2884 /* never exits */ |
|
2885 return 0; |
|
2886 } |
|
2887 #endif |
|
2888 |
|
2889 /* do_fork() Must return host values and target errnos (unlike most |
|
2890 do_*() functions). */ |
|
2891 static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, |
|
2892 abi_ulong parent_tidptr, target_ulong newtls, |
|
2893 abi_ulong child_tidptr) |
|
2894 { |
|
2895 int ret; |
|
2896 TaskState *ts; |
|
2897 uint8_t *new_stack; |
|
2898 CPUState *new_env; |
|
2899 #if defined(USE_NPTL) |
|
2900 unsigned int nptl_flags; |
|
2901 sigset_t sigmask; |
|
2902 #endif |
|
2903 |
|
2904 /* Emulate vfork() with fork() */ |
|
2905 if (flags & CLONE_VFORK) |
|
2906 flags &= ~(CLONE_VFORK | CLONE_VM); |
|
2907 |
|
2908 if (flags & CLONE_VM) { |
|
2909 #if defined(USE_NPTL) |
|
2910 new_thread_info info; |
|
2911 pthread_attr_t attr; |
|
2912 #endif |
|
2913 ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE); |
|
2914 init_task_state(ts); |
|
2915 new_stack = ts->stack; |
|
2916 /* we create a new CPU instance. */ |
|
2917 new_env = cpu_copy(env); |
|
2918 /* Init regs that differ from the parent. */ |
|
2919 cpu_clone_regs(new_env, newsp); |
|
2920 new_env->opaque = ts; |
|
2921 #if defined(USE_NPTL) |
|
2922 nptl_flags = flags; |
|
2923 flags &= ~CLONE_NPTL_FLAGS2; |
|
2924 |
|
2925 /* TODO: Implement CLONE_CHILD_CLEARTID. */ |
|
2926 if (nptl_flags & CLONE_SETTLS) |
|
2927 cpu_set_tls (new_env, newtls); |
|
2928 |
|
2929 /* Grab a mutex so that thread setup appears atomic. */ |
|
2930 pthread_mutex_lock(&clone_lock); |
|
2931 |
|
2932 memset(&info, 0, sizeof(info)); |
|
2933 pthread_mutex_init(&info.mutex, NULL); |
|
2934 pthread_mutex_lock(&info.mutex); |
|
2935 pthread_cond_init(&info.cond, NULL); |
|
2936 info.env = new_env; |
|
2937 if (nptl_flags & CLONE_CHILD_SETTID) |
|
2938 info.child_tidptr = child_tidptr; |
|
2939 if (nptl_flags & CLONE_PARENT_SETTID) |
|
2940 info.parent_tidptr = parent_tidptr; |
|
2941 |
|
2942 ret = pthread_attr_init(&attr); |
|
2943 ret = pthread_attr_setstack(&attr, new_stack, NEW_STACK_SIZE); |
|
2944 /* It is not safe to deliver signals until the child has finished |
|
2945 initializing, so temporarily block all signals. */ |
|
2946 sigfillset(&sigmask); |
|
2947 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); |
|
2948 |
|
2949 ret = pthread_create(&info.thread, &attr, clone_func, &info); |
|
2950 |
|
2951 sigprocmask(SIG_SETMASK, &info.sigmask, NULL); |
|
2952 pthread_attr_destroy(&attr); |
|
2953 if (ret == 0) { |
|
2954 /* Wait for the child to initialize. */ |
|
2955 pthread_cond_wait(&info.cond, &info.mutex); |
|
2956 ret = info.tid; |
|
2957 if (flags & CLONE_PARENT_SETTID) |
|
2958 put_user_u32(ret, parent_tidptr); |
|
2959 } else { |
|
2960 ret = -1; |
|
2961 } |
|
2962 pthread_mutex_unlock(&info.mutex); |
|
2963 pthread_cond_destroy(&info.cond); |
|
2964 pthread_mutex_destroy(&info.mutex); |
|
2965 pthread_mutex_unlock(&clone_lock); |
|
2966 #else |
|
2967 if (flags & CLONE_NPTL_FLAGS2) |
|
2968 return -EINVAL; |
|
2969 /* This is probably going to die very quickly, but do it anyway. */ |
|
2970 #ifdef USE_NPTL |
|
2971 nptl_flags = flags; |
|
2972 flags &= ~CLONE_NPTL_FLAGS2; |
|
2973 |
|
2974 if (nptl_flags & CLONE_CHILD_CLEARTID) { |
|
2975 ts->child_tidptr = child_tidptr; |
|
2976 } |
|
2977 |
|
2978 if (nptl_flags & CLONE_SETTLS) |
|
2979 cpu_set_tls (new_env, newtls); |
|
2980 |
|
2981 /* Grab the global cpu lock so that the thread setup appears |
|
2982 atomic. */ |
|
2983 if (nptl_flags & CLONE_CHILD_SETTID) |
|
2984 spin_lock(&nptl_lock); |
|
2985 |
|
2986 #else |
|
2987 if (flags & CLONE_NPTL_FLAGS2) |
|
2988 return -EINVAL; |
|
2989 #endif |
|
2990 #ifdef __ia64__ |
|
2991 ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); |
|
2992 #else |
|
2993 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); |
|
2994 #endif |
|
2995 #endif |
|
2996 } else { |
|
2997 /* if no CLONE_VM, we consider it is a fork */ |
|
2998 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) |
|
2999 return -EINVAL; |
|
3000 fork_start(); |
|
3001 ret = fork(); |
|
3002 if (ret == 0) { |
|
3003 /* Child Process. */ |
|
3004 cpu_clone_regs(env, newsp); |
|
3005 fork_end(1); |
|
3006 #if defined(USE_NPTL) |
|
3007 /* There is a race condition here. The parent process could |
|
3008 theoretically read the TID in the child process before the child |
|
3009 tid is set. This would require using either ptrace |
|
3010 (not implemented) or having *_tidptr to point at a shared memory |
|
3011 mapping. We can't repeat the spinlock hack used above because |
|
3012 the child process gets its own copy of the lock. */ |
|
3013 if (flags & CLONE_CHILD_SETTID) |
|
3014 put_user_u32(gettid(), child_tidptr); |
|
3015 if (flags & CLONE_PARENT_SETTID) |
|
3016 put_user_u32(gettid(), parent_tidptr); |
|
3017 ts = (TaskState *)env->opaque; |
|
3018 if (flags & CLONE_SETTLS) |
|
3019 cpu_set_tls (env, newtls); |
|
3020 /* TODO: Implement CLONE_CHILD_CLEARTID. */ |
|
3021 #endif |
|
3022 } else { |
|
3023 fork_end(0); |
|
3024 } |
|
3025 } |
|
3026 return ret; |
|
3027 } |
|
3028 |
|
3029 static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) |
|
3030 { |
|
3031 struct flock fl; |
|
3032 struct target_flock *target_fl; |
|
3033 struct flock64 fl64; |
|
3034 struct target_flock64 *target_fl64; |
|
3035 abi_long ret; |
|
3036 |
|
3037 switch(cmd) { |
|
3038 case TARGET_F_GETLK: |
|
3039 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) |
|
3040 return -TARGET_EFAULT; |
|
3041 fl.l_type = tswap16(target_fl->l_type); |
|
3042 fl.l_whence = tswap16(target_fl->l_whence); |
|
3043 fl.l_start = tswapl(target_fl->l_start); |
|
3044 fl.l_len = tswapl(target_fl->l_len); |
|
3045 fl.l_pid = tswapl(target_fl->l_pid); |
|
3046 unlock_user_struct(target_fl, arg, 0); |
|
3047 ret = get_errno(fcntl(fd, cmd, &fl)); |
|
3048 if (ret == 0) { |
|
3049 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) |
|
3050 return -TARGET_EFAULT; |
|
3051 target_fl->l_type = tswap16(fl.l_type); |
|
3052 target_fl->l_whence = tswap16(fl.l_whence); |
|
3053 target_fl->l_start = tswapl(fl.l_start); |
|
3054 target_fl->l_len = tswapl(fl.l_len); |
|
3055 target_fl->l_pid = tswapl(fl.l_pid); |
|
3056 unlock_user_struct(target_fl, arg, 1); |
|
3057 } |
|
3058 break; |
|
3059 |
|
3060 case TARGET_F_SETLK: |
|
3061 case TARGET_F_SETLKW: |
|
3062 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) |
|
3063 return -TARGET_EFAULT; |
|
3064 fl.l_type = tswap16(target_fl->l_type); |
|
3065 fl.l_whence = tswap16(target_fl->l_whence); |
|
3066 fl.l_start = tswapl(target_fl->l_start); |
|
3067 fl.l_len = tswapl(target_fl->l_len); |
|
3068 fl.l_pid = tswapl(target_fl->l_pid); |
|
3069 unlock_user_struct(target_fl, arg, 0); |
|
3070 ret = get_errno(fcntl(fd, cmd, &fl)); |
|
3071 break; |
|
3072 |
|
3073 case TARGET_F_GETLK64: |
|
3074 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) |
|
3075 return -TARGET_EFAULT; |
|
3076 fl64.l_type = tswap16(target_fl64->l_type) >> 1; |
|
3077 fl64.l_whence = tswap16(target_fl64->l_whence); |
|
3078 fl64.l_start = tswapl(target_fl64->l_start); |
|
3079 fl64.l_len = tswapl(target_fl64->l_len); |
|
3080 fl64.l_pid = tswap16(target_fl64->l_pid); |
|
3081 unlock_user_struct(target_fl64, arg, 0); |
|
3082 ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); |
|
3083 if (ret == 0) { |
|
3084 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) |
|
3085 return -TARGET_EFAULT; |
|
3086 target_fl64->l_type = tswap16(fl64.l_type) >> 1; |
|
3087 target_fl64->l_whence = tswap16(fl64.l_whence); |
|
3088 target_fl64->l_start = tswapl(fl64.l_start); |
|
3089 target_fl64->l_len = tswapl(fl64.l_len); |
|
3090 target_fl64->l_pid = tswapl(fl64.l_pid); |
|
3091 unlock_user_struct(target_fl64, arg, 1); |
|
3092 } |
|
3093 break; |
|
3094 case TARGET_F_SETLK64: |
|
3095 case TARGET_F_SETLKW64: |
|
3096 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) |
|
3097 return -TARGET_EFAULT; |
|
3098 fl64.l_type = tswap16(target_fl64->l_type) >> 1; |
|
3099 fl64.l_whence = tswap16(target_fl64->l_whence); |
|
3100 fl64.l_start = tswapl(target_fl64->l_start); |
|
3101 fl64.l_len = tswapl(target_fl64->l_len); |
|
3102 fl64.l_pid = tswap16(target_fl64->l_pid); |
|
3103 unlock_user_struct(target_fl64, arg, 0); |
|
3104 ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); |
|
3105 break; |
|
3106 |
|
3107 case F_GETFL: |
|
3108 ret = get_errno(fcntl(fd, cmd, arg)); |
|
3109 if (ret >= 0) { |
|
3110 ret = host_to_target_bitmask(ret, fcntl_flags_tbl); |
|
3111 } |
|
3112 break; |
|
3113 |
|
3114 case F_SETFL: |
|
3115 ret = get_errno(fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl))); |
|
3116 break; |
|
3117 |
|
3118 default: |
|
3119 ret = get_errno(fcntl(fd, cmd, arg)); |
|
3120 break; |
|
3121 } |
|
3122 return ret; |
|
3123 } |
|
3124 |
|
3125 #ifdef USE_UID16 |
|
3126 |
|
3127 static inline int high2lowuid(int uid) |
|
3128 { |
|
3129 if (uid > 65535) |
|
3130 return 65534; |
|
3131 else |
|
3132 return uid; |
|
3133 } |
|
3134 |
|
3135 static inline int high2lowgid(int gid) |
|
3136 { |
|
3137 if (gid > 65535) |
|
3138 return 65534; |
|
3139 else |
|
3140 return gid; |
|
3141 } |
|
3142 |
|
3143 static inline int low2highuid(int uid) |
|
3144 { |
|
3145 if ((int16_t)uid == -1) |
|
3146 return -1; |
|
3147 else |
|
3148 return uid; |
|
3149 } |
|
3150 |
|
3151 static inline int low2highgid(int gid) |
|
3152 { |
|
3153 if ((int16_t)gid == -1) |
|
3154 return -1; |
|
3155 else |
|
3156 return gid; |
|
3157 } |
|
3158 |
|
3159 #endif /* USE_UID16 */ |
|
3160 |
|
3161 void syscall_init(void) |
|
3162 { |
|
3163 IOCTLEntry *ie; |
|
3164 const argtype *arg_type; |
|
3165 int size; |
|
3166 int i; |
|
3167 |
|
3168 #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); |
|
3169 #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); |
|
3170 #include "syscall_types.h" |
|
3171 #undef STRUCT |
|
3172 #undef STRUCT_SPECIAL |
|
3173 |
|
3174 /* we patch the ioctl size if necessary. We rely on the fact that |
|
3175 no ioctl has all the bits at '1' in the size field */ |
|
3176 ie = ioctl_entries; |
|
3177 while (ie->target_cmd != 0) { |
|
3178 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) == |
|
3179 TARGET_IOC_SIZEMASK) { |
|
3180 arg_type = ie->arg_type; |
|
3181 if (arg_type[0] != TYPE_PTR) { |
|
3182 fprintf(stderr, "cannot patch size for ioctl 0x%x\n", |
|
3183 ie->target_cmd); |
|
3184 exit(1); |
|
3185 } |
|
3186 arg_type++; |
|
3187 size = thunk_type_size(arg_type, 0); |
|
3188 ie->target_cmd = (ie->target_cmd & |
|
3189 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | |
|
3190 (size << TARGET_IOC_SIZESHIFT); |
|
3191 } |
|
3192 |
|
3193 /* Build target_to_host_errno_table[] table from |
|
3194 * host_to_target_errno_table[]. */ |
|
3195 for (i=0; i < ERRNO_TABLE_SIZE; i++) |
|
3196 target_to_host_errno_table[host_to_target_errno_table[i]] = i; |
|
3197 |
|
3198 /* automatic consistency check if same arch */ |
|
3199 #if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \ |
|
3200 (defined(__x86_64__) && defined(TARGET_X86_64)) |
|
3201 if (unlikely(ie->target_cmd != ie->host_cmd)) { |
|
3202 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n", |
|
3203 ie->name, ie->target_cmd, ie->host_cmd); |
|
3204 } |
|
3205 #endif |
|
3206 ie++; |
|
3207 } |
|
3208 } |
|
3209 |
|
3210 #if TARGET_ABI_BITS == 32 |
|
3211 static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) |
|
3212 { |
|
3213 #ifdef TARGET_WORDS_BIGENDIAN |
|
3214 return ((uint64_t)word0 << 32) | word1; |
|
3215 #else |
|
3216 return ((uint64_t)word1 << 32) | word0; |
|
3217 #endif |
|
3218 } |
|
3219 #else /* TARGET_ABI_BITS == 32 */ |
|
3220 static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) |
|
3221 { |
|
3222 return word0; |
|
3223 } |
|
3224 #endif /* TARGET_ABI_BITS != 32 */ |
|
3225 |
|
3226 #ifdef TARGET_NR_truncate64 |
|
3227 static inline abi_long target_truncate64(void *cpu_env, const char *arg1, |
|
3228 abi_long arg2, |
|
3229 abi_long arg3, |
|
3230 abi_long arg4) |
|
3231 { |
|
3232 #ifdef TARGET_ARM |
|
3233 if (((CPUARMState *)cpu_env)->eabi) |
|
3234 { |
|
3235 arg2 = arg3; |
|
3236 arg3 = arg4; |
|
3237 } |
|
3238 #endif |
|
3239 return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); |
|
3240 } |
|
3241 #endif |
|
3242 |
|
3243 #ifdef TARGET_NR_ftruncate64 |
|
3244 static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, |
|
3245 abi_long arg2, |
|
3246 abi_long arg3, |
|
3247 abi_long arg4) |
|
3248 { |
|
3249 #ifdef TARGET_ARM |
|
3250 if (((CPUARMState *)cpu_env)->eabi) |
|
3251 { |
|
3252 arg2 = arg3; |
|
3253 arg3 = arg4; |
|
3254 } |
|
3255 #endif |
|
3256 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); |
|
3257 } |
|
3258 #endif |
|
3259 |
|
3260 static inline abi_long target_to_host_timespec(struct timespec *host_ts, |
|
3261 abi_ulong target_addr) |
|
3262 { |
|
3263 struct target_timespec *target_ts; |
|
3264 |
|
3265 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) |
|
3266 return -TARGET_EFAULT; |
|
3267 host_ts->tv_sec = tswapl(target_ts->tv_sec); |
|
3268 host_ts->tv_nsec = tswapl(target_ts->tv_nsec); |
|
3269 unlock_user_struct(target_ts, target_addr, 0); |
|
3270 return 0; |
|
3271 } |
|
3272 |
|
3273 static inline abi_long host_to_target_timespec(abi_ulong target_addr, |
|
3274 struct timespec *host_ts) |
|
3275 { |
|
3276 struct target_timespec *target_ts; |
|
3277 |
|
3278 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) |
|
3279 return -TARGET_EFAULT; |
|
3280 target_ts->tv_sec = tswapl(host_ts->tv_sec); |
|
3281 target_ts->tv_nsec = tswapl(host_ts->tv_nsec); |
|
3282 unlock_user_struct(target_ts, target_addr, 1); |
|
3283 return 0; |
|
3284 } |
|
3285 |
|
3286 #ifdef TARGET_NR_stat64 |
|
3287 static inline abi_long host_to_target_stat64(void *cpu_env, |
|
3288 abi_ulong target_addr, |
|
3289 struct stat *host_st) |
|
3290 { |
|
3291 #ifdef TARGET_ARM |
|
3292 if (((CPUARMState *)cpu_env)->eabi) { |
|
3293 struct target_eabi_stat64 *target_st; |
|
3294 |
|
3295 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) |
|
3296 return -TARGET_EFAULT; |
|
3297 memset(target_st, 0, sizeof(struct target_eabi_stat64)); |
|
3298 __put_user(host_st->st_dev, &target_st->st_dev); |
|
3299 __put_user(host_st->st_ino, &target_st->st_ino); |
|
3300 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO |
|
3301 __put_user(host_st->st_ino, &target_st->__st_ino); |
|
3302 #endif |
|
3303 __put_user(host_st->st_mode, &target_st->st_mode); |
|
3304 __put_user(host_st->st_nlink, &target_st->st_nlink); |
|
3305 __put_user(host_st->st_uid, &target_st->st_uid); |
|
3306 __put_user(host_st->st_gid, &target_st->st_gid); |
|
3307 __put_user(host_st->st_rdev, &target_st->st_rdev); |
|
3308 __put_user(host_st->st_size, &target_st->st_size); |
|
3309 __put_user(host_st->st_blksize, &target_st->st_blksize); |
|
3310 __put_user(host_st->st_blocks, &target_st->st_blocks); |
|
3311 __put_user(host_st->st_atime, &target_st->target_st_atime); |
|
3312 __put_user(host_st->st_mtime, &target_st->target_st_mtime); |
|
3313 __put_user(host_st->st_ctime, &target_st->target_st_ctime); |
|
3314 unlock_user_struct(target_st, target_addr, 1); |
|
3315 } else |
|
3316 #endif |
|
3317 { |
|
3318 struct target_stat64 *target_st; |
|
3319 |
|
3320 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) |
|
3321 return -TARGET_EFAULT; |
|
3322 memset(target_st, 0, sizeof(struct target_stat64)); |
|
3323 __put_user(host_st->st_dev, &target_st->st_dev); |
|
3324 __put_user(host_st->st_ino, &target_st->st_ino); |
|
3325 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO |
|
3326 __put_user(host_st->st_ino, &target_st->__st_ino); |
|
3327 #endif |
|
3328 __put_user(host_st->st_mode, &target_st->st_mode); |
|
3329 __put_user(host_st->st_nlink, &target_st->st_nlink); |
|
3330 __put_user(host_st->st_uid, &target_st->st_uid); |
|
3331 __put_user(host_st->st_gid, &target_st->st_gid); |
|
3332 __put_user(host_st->st_rdev, &target_st->st_rdev); |
|
3333 /* XXX: better use of kernel struct */ |
|
3334 __put_user(host_st->st_size, &target_st->st_size); |
|
3335 __put_user(host_st->st_blksize, &target_st->st_blksize); |
|
3336 __put_user(host_st->st_blocks, &target_st->st_blocks); |
|
3337 __put_user(host_st->st_atime, &target_st->target_st_atime); |
|
3338 __put_user(host_st->st_mtime, &target_st->target_st_mtime); |
|
3339 __put_user(host_st->st_ctime, &target_st->target_st_ctime); |
|
3340 unlock_user_struct(target_st, target_addr, 1); |
|
3341 } |
|
3342 |
|
3343 return 0; |
|
3344 } |
|
3345 #endif |
|
3346 |
|
3347 #if defined(USE_NPTL) |
|
3348 /* ??? Using host futex calls even when target atomic operations |
|
3349 are not really atomic probably breaks things. However implementing |
|
3350 futexes locally would make futexes shared between multiple processes |
|
3351 tricky. However they're probably useless because guest atomic |
|
3352 operations won't work either. */ |
|
3353 static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, |
|
3354 target_ulong uaddr2, int val3) |
|
3355 { |
|
3356 struct timespec ts, *pts; |
|
3357 |
|
3358 /* ??? We assume FUTEX_* constants are the same on both host |
|
3359 and target. */ |
|
3360 switch (op) { |
|
3361 case FUTEX_WAIT: |
|
3362 if (timeout) { |
|
3363 pts = &ts; |
|
3364 target_to_host_timespec(pts, timeout); |
|
3365 } else { |
|
3366 pts = NULL; |
|
3367 } |
|
3368 return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val), |
|
3369 pts, NULL, 0)); |
|
3370 case FUTEX_WAKE: |
|
3371 return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0)); |
|
3372 case FUTEX_FD: |
|
3373 return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0)); |
|
3374 case FUTEX_REQUEUE: |
|
3375 return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val, |
|
3376 NULL, g2h(uaddr2), 0)); |
|
3377 case FUTEX_CMP_REQUEUE: |
|
3378 return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val, |
|
3379 NULL, g2h(uaddr2), tswap32(val3))); |
|
3380 default: |
|
3381 return -TARGET_ENOSYS; |
|
3382 } |
|
3383 } |
|
3384 #endif |
|
3385 |
|
3386 int get_osversion(void) |
|
3387 { |
|
3388 static int osversion; |
|
3389 struct new_utsname buf; |
|
3390 const char *s; |
|
3391 int i, n, tmp; |
|
3392 if (osversion) |
|
3393 return osversion; |
|
3394 if (qemu_uname_release && *qemu_uname_release) { |
|
3395 s = qemu_uname_release; |
|
3396 } else { |
|
3397 if (sys_uname(&buf)) |
|
3398 return 0; |
|
3399 s = buf.release; |
|
3400 } |
|
3401 tmp = 0; |
|
3402 for (i = 0; i < 3; i++) { |
|
3403 n = 0; |
|
3404 while (*s >= '0' && *s <= '9') { |
|
3405 n *= 10; |
|
3406 n += *s - '0'; |
|
3407 s++; |
|
3408 } |
|
3409 tmp = (tmp << 8) + n; |
|
3410 if (*s == '.') |
|
3411 s++; |
|
3412 } |
|
3413 osversion = tmp; |
|
3414 return osversion; |
|
3415 } |
|
3416 |
|
3417 /* do_syscall() should always have a single exit point at the end so |
|
3418 that actions, such as logging of syscall results, can be performed. |
|
3419 All errnos that do_syscall() returns must be -TARGET_<errcode>. */ |
|
3420 abi_long do_syscall(void *cpu_env, int num, abi_long arg1, |
|
3421 abi_long arg2, abi_long arg3, abi_long arg4, |
|
3422 abi_long arg5, abi_long arg6) |
|
3423 { |
|
3424 abi_long ret; |
|
3425 struct stat st; |
|
3426 struct statfs stfs; |
|
3427 void *p; |
|
3428 |
|
3429 #ifdef DEBUG |
|
3430 gemu_log("syscall %d", num); |
|
3431 #endif |
|
3432 if(do_strace) |
|
3433 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); |
|
3434 |
|
3435 switch(num) { |
|
3436 case TARGET_NR_exit: |
|
3437 #ifdef HAVE_GPROF |
|
3438 _mcleanup(); |
|
3439 #endif |
|
3440 gdb_exit(cpu_env, arg1); |
|
3441 /* XXX: should free thread stack and CPU env */ |
|
3442 sys_exit(arg1); |
|
3443 ret = 0; /* avoid warning */ |
|
3444 break; |
|
3445 case TARGET_NR_read: |
|
3446 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) |
|
3447 goto efault; |
|
3448 ret = get_errno(read(arg1, p, arg3)); |
|
3449 unlock_user(p, arg2, ret); |
|
3450 break; |
|
3451 case TARGET_NR_write: |
|
3452 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) |
|
3453 goto efault; |
|
3454 ret = get_errno(write(arg1, p, arg3)); |
|
3455 unlock_user(p, arg2, 0); |
|
3456 break; |
|
3457 case TARGET_NR_open: |
|
3458 if (!(p = lock_user_string(arg1))) |
|
3459 goto efault; |
|
3460 ret = get_errno(open(path(p), |
|
3461 target_to_host_bitmask(arg2, fcntl_flags_tbl), |
|
3462 arg3)); |
|
3463 unlock_user(p, arg1, 0); |
|
3464 break; |
|
3465 #if defined(TARGET_NR_openat) && defined(__NR_openat) |
|
3466 case TARGET_NR_openat: |
|
3467 if (!(p = lock_user_string(arg2))) |
|
3468 goto efault; |
|
3469 ret = get_errno(sys_openat(arg1, |
|
3470 path(p), |
|
3471 target_to_host_bitmask(arg3, fcntl_flags_tbl), |
|
3472 arg4)); |
|
3473 unlock_user(p, arg2, 0); |
|
3474 break; |
|
3475 #endif |
|
3476 case TARGET_NR_close: |
|
3477 ret = get_errno(close(arg1)); |
|
3478 break; |
|
3479 case TARGET_NR_brk: |
|
3480 ret = do_brk(arg1); |
|
3481 break; |
|
3482 case TARGET_NR_fork: |
|
3483 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0)); |
|
3484 break; |
|
3485 #ifdef TARGET_NR_waitpid |
|
3486 case TARGET_NR_waitpid: |
|
3487 { |
|
3488 int status; |
|
3489 ret = get_errno(waitpid(arg1, &status, arg3)); |
|
3490 if (!is_error(ret) && arg2 |
|
3491 && put_user_s32(status, arg2)) |
|
3492 goto efault; |
|
3493 } |
|
3494 break; |
|
3495 #endif |
|
3496 #ifdef TARGET_NR_waitid |
|
3497 case TARGET_NR_waitid: |
|
3498 { |
|
3499 siginfo_t info; |
|
3500 info.si_pid = 0; |
|
3501 ret = get_errno(waitid(arg1, arg2, &info, arg4)); |
|
3502 if (!is_error(ret) && arg3 && info.si_pid != 0) { |
|
3503 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0))) |
|
3504 goto efault; |
|
3505 host_to_target_siginfo(p, &info); |
|
3506 unlock_user(p, arg3, sizeof(target_siginfo_t)); |
|
3507 } |
|
3508 } |
|
3509 break; |
|
3510 #endif |
|
3511 #ifdef TARGET_NR_creat /* not on alpha */ |
|
3512 case TARGET_NR_creat: |
|
3513 if (!(p = lock_user_string(arg1))) |
|
3514 goto efault; |
|
3515 ret = get_errno(creat(p, arg2)); |
|
3516 unlock_user(p, arg1, 0); |
|
3517 break; |
|
3518 #endif |
|
3519 case TARGET_NR_link: |
|
3520 { |
|
3521 void * p2; |
|
3522 p = lock_user_string(arg1); |
|
3523 p2 = lock_user_string(arg2); |
|
3524 if (!p || !p2) |
|
3525 ret = -TARGET_EFAULT; |
|
3526 else |
|
3527 ret = get_errno(link(p, p2)); |
|
3528 unlock_user(p2, arg2, 0); |
|
3529 unlock_user(p, arg1, 0); |
|
3530 } |
|
3531 break; |
|
3532 #if defined(TARGET_NR_linkat) && defined(__NR_linkat) |
|
3533 case TARGET_NR_linkat: |
|
3534 { |
|
3535 void * p2 = NULL; |
|
3536 if (!arg2 || !arg4) |
|
3537 goto efault; |
|
3538 p = lock_user_string(arg2); |
|
3539 p2 = lock_user_string(arg4); |
|
3540 if (!p || !p2) |
|
3541 ret = -TARGET_EFAULT; |
|
3542 else |
|
3543 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); |
|
3544 unlock_user(p, arg2, 0); |
|
3545 unlock_user(p2, arg4, 0); |
|
3546 } |
|
3547 break; |
|
3548 #endif |
|
3549 case TARGET_NR_unlink: |
|
3550 if (!(p = lock_user_string(arg1))) |
|
3551 goto efault; |
|
3552 ret = get_errno(unlink(p)); |
|
3553 unlock_user(p, arg1, 0); |
|
3554 break; |
|
3555 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) |
|
3556 case TARGET_NR_unlinkat: |
|
3557 if (!(p = lock_user_string(arg2))) |
|
3558 goto efault; |
|
3559 ret = get_errno(sys_unlinkat(arg1, p, arg3)); |
|
3560 unlock_user(p, arg2, 0); |
|
3561 break; |
|
3562 #endif |
|
3563 case TARGET_NR_execve: |
|
3564 { |
|
3565 char **argp, **envp; |
|
3566 int argc, envc; |
|
3567 abi_ulong gp; |
|
3568 abi_ulong guest_argp; |
|
3569 abi_ulong guest_envp; |
|
3570 abi_ulong addr; |
|
3571 char **q; |
|
3572 |
|
3573 argc = 0; |
|
3574 guest_argp = arg2; |
|
3575 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { |
|
3576 if (get_user_ual(addr, gp)) |
|
3577 goto efault; |
|
3578 if (!addr) |
|
3579 break; |
|
3580 argc++; |
|
3581 } |
|
3582 envc = 0; |
|
3583 guest_envp = arg3; |
|
3584 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { |
|
3585 if (get_user_ual(addr, gp)) |
|
3586 goto efault; |
|
3587 if (!addr) |
|
3588 break; |
|
3589 envc++; |
|
3590 } |
|
3591 |
|
3592 argp = alloca((argc + 1) * sizeof(void *)); |
|
3593 envp = alloca((envc + 1) * sizeof(void *)); |
|
3594 |
|
3595 for (gp = guest_argp, q = argp; gp; |
|
3596 gp += sizeof(abi_ulong), q++) { |
|
3597 if (get_user_ual(addr, gp)) |
|
3598 goto execve_efault; |
|
3599 if (!addr) |
|
3600 break; |
|
3601 if (!(*q = lock_user_string(addr))) |
|
3602 goto execve_efault; |
|
3603 } |
|
3604 *q = NULL; |
|
3605 |
|
3606 for (gp = guest_envp, q = envp; gp; |
|
3607 gp += sizeof(abi_ulong), q++) { |
|
3608 if (get_user_ual(addr, gp)) |
|
3609 goto execve_efault; |
|
3610 if (!addr) |
|
3611 break; |
|
3612 if (!(*q = lock_user_string(addr))) |
|
3613 goto execve_efault; |
|
3614 } |
|
3615 *q = NULL; |
|
3616 |
|
3617 if (!(p = lock_user_string(arg1))) |
|
3618 goto execve_efault; |
|
3619 ret = get_errno(execve(p, argp, envp)); |
|
3620 unlock_user(p, arg1, 0); |
|
3621 |
|
3622 goto execve_end; |
|
3623 |
|
3624 execve_efault: |
|
3625 ret = -TARGET_EFAULT; |
|
3626 |
|
3627 execve_end: |
|
3628 for (gp = guest_argp, q = argp; *q; |
|
3629 gp += sizeof(abi_ulong), q++) { |
|
3630 if (get_user_ual(addr, gp) |
|
3631 || !addr) |
|
3632 break; |
|
3633 unlock_user(*q, addr, 0); |
|
3634 } |
|
3635 for (gp = guest_envp, q = envp; *q; |
|
3636 gp += sizeof(abi_ulong), q++) { |
|
3637 if (get_user_ual(addr, gp) |
|
3638 || !addr) |
|
3639 break; |
|
3640 unlock_user(*q, addr, 0); |
|
3641 } |
|
3642 } |
|
3643 break; |
|
3644 case TARGET_NR_chdir: |
|
3645 if (!(p = lock_user_string(arg1))) |
|
3646 goto efault; |
|
3647 ret = get_errno(chdir(p)); |
|
3648 unlock_user(p, arg1, 0); |
|
3649 break; |
|
3650 #ifdef TARGET_NR_time |
|
3651 case TARGET_NR_time: |
|
3652 { |
|
3653 time_t host_time; |
|
3654 ret = get_errno(time(&host_time)); |
|
3655 if (!is_error(ret) |
|
3656 && arg1 |
|
3657 && put_user_sal(host_time, arg1)) |
|
3658 goto efault; |
|
3659 } |
|
3660 break; |
|
3661 #endif |
|
3662 case TARGET_NR_mknod: |
|
3663 if (!(p = lock_user_string(arg1))) |
|
3664 goto efault; |
|
3665 ret = get_errno(mknod(p, arg2, arg3)); |
|
3666 unlock_user(p, arg1, 0); |
|
3667 break; |
|
3668 #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) |
|
3669 case TARGET_NR_mknodat: |
|
3670 if (!(p = lock_user_string(arg2))) |
|
3671 goto efault; |
|
3672 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); |
|
3673 unlock_user(p, arg2, 0); |
|
3674 break; |
|
3675 #endif |
|
3676 case TARGET_NR_chmod: |
|
3677 if (!(p = lock_user_string(arg1))) |
|
3678 goto efault; |
|
3679 ret = get_errno(chmod(p, arg2)); |
|
3680 unlock_user(p, arg1, 0); |
|
3681 break; |
|
3682 #ifdef TARGET_NR_break |
|
3683 case TARGET_NR_break: |
|
3684 goto unimplemented; |
|
3685 #endif |
|
3686 #ifdef TARGET_NR_oldstat |
|
3687 case TARGET_NR_oldstat: |
|
3688 goto unimplemented; |
|
3689 #endif |
|
3690 case TARGET_NR_lseek: |
|
3691 ret = get_errno(lseek(arg1, arg2, arg3)); |
|
3692 break; |
|
3693 #ifdef TARGET_NR_getxpid |
|
3694 case TARGET_NR_getxpid: |
|
3695 #else |
|
3696 case TARGET_NR_getpid: |
|
3697 #endif |
|
3698 ret = get_errno(getpid()); |
|
3699 break; |
|
3700 case TARGET_NR_mount: |
|
3701 { |
|
3702 /* need to look at the data field */ |
|
3703 void *p2, *p3; |
|
3704 p = lock_user_string(arg1); |
|
3705 p2 = lock_user_string(arg2); |
|
3706 p3 = lock_user_string(arg3); |
|
3707 if (!p || !p2 || !p3) |
|
3708 ret = -TARGET_EFAULT; |
|
3709 else |
|
3710 /* FIXME - arg5 should be locked, but it isn't clear how to |
|
3711 * do that since it's not guaranteed to be a NULL-terminated |
|
3712 * string. |
|
3713 */ |
|
3714 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5))); |
|
3715 unlock_user(p, arg1, 0); |
|
3716 unlock_user(p2, arg2, 0); |
|
3717 unlock_user(p3, arg3, 0); |
|
3718 break; |
|
3719 } |
|
3720 #ifdef TARGET_NR_umount |
|
3721 case TARGET_NR_umount: |
|
3722 if (!(p = lock_user_string(arg1))) |
|
3723 goto efault; |
|
3724 ret = get_errno(umount(p)); |
|
3725 unlock_user(p, arg1, 0); |
|
3726 break; |
|
3727 #endif |
|
3728 #ifdef TARGET_NR_stime /* not on alpha */ |
|
3729 case TARGET_NR_stime: |
|
3730 { |
|
3731 time_t host_time; |
|
3732 if (get_user_sal(host_time, arg1)) |
|
3733 goto efault; |
|
3734 ret = get_errno(stime(&host_time)); |
|
3735 } |
|
3736 break; |
|
3737 #endif |
|
3738 case TARGET_NR_ptrace: |
|
3739 if (gdb_wrapper) { |
|
3740 /* Pretend something else is attached to the target process. */ |
|
3741 ret = -EPERM; |
|
3742 break; |
|
3743 } |
|
3744 goto unimplemented; |
|
3745 #ifdef TARGET_NR_alarm /* not on alpha */ |
|
3746 case TARGET_NR_alarm: |
|
3747 ret = alarm(arg1); |
|
3748 break; |
|
3749 #endif |
|
3750 #ifdef TARGET_NR_oldfstat |
|
3751 case TARGET_NR_oldfstat: |
|
3752 goto unimplemented; |
|
3753 #endif |
|
3754 #ifdef TARGET_NR_pause /* not on alpha */ |
|
3755 case TARGET_NR_pause: |
|
3756 ret = get_errno(pause()); |
|
3757 break; |
|
3758 #endif |
|
3759 #ifdef TARGET_NR_utime |
|
3760 case TARGET_NR_utime: |
|
3761 { |
|
3762 struct utimbuf tbuf, *host_tbuf; |
|
3763 struct target_utimbuf *target_tbuf; |
|
3764 if (arg2) { |
|
3765 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1)) |
|
3766 goto efault; |
|
3767 tbuf.actime = tswapl(target_tbuf->actime); |
|
3768 tbuf.modtime = tswapl(target_tbuf->modtime); |
|
3769 unlock_user_struct(target_tbuf, arg2, 0); |
|
3770 host_tbuf = &tbuf; |
|
3771 } else { |
|
3772 host_tbuf = NULL; |
|
3773 } |
|
3774 if (!(p = lock_user_string(arg1))) |
|
3775 goto efault; |
|
3776 ret = get_errno(utime(p, host_tbuf)); |
|
3777 unlock_user(p, arg1, 0); |
|
3778 } |
|
3779 break; |
|
3780 #endif |
|
3781 case TARGET_NR_utimes: |
|
3782 { |
|
3783 struct timeval *tvp, tv[2]; |
|
3784 if (arg2) { |
|
3785 if (copy_from_user_timeval(&tv[0], arg2) |
|
3786 || copy_from_user_timeval(&tv[1], |
|
3787 arg2 + sizeof(struct target_timeval))) |
|
3788 goto efault; |
|
3789 tvp = tv; |
|
3790 } else { |
|
3791 tvp = NULL; |
|
3792 } |
|
3793 if (!(p = lock_user_string(arg1))) |
|
3794 goto efault; |
|
3795 ret = get_errno(utimes(p, tvp)); |
|
3796 unlock_user(p, arg1, 0); |
|
3797 } |
|
3798 break; |
|
3799 #if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) |
|
3800 case TARGET_NR_futimesat: |
|
3801 { |
|
3802 struct timeval *tvp, tv[2]; |
|
3803 if (arg3) { |
|
3804 if (copy_from_user_timeval(&tv[0], arg3) |
|
3805 || copy_from_user_timeval(&tv[1], |
|
3806 arg3 + sizeof(struct target_timeval))) |
|
3807 goto efault; |
|
3808 tvp = tv; |
|
3809 } else { |
|
3810 tvp = NULL; |
|
3811 } |
|
3812 if (!(p = lock_user_string(arg2))) |
|
3813 goto efault; |
|
3814 ret = get_errno(sys_futimesat(arg1, path(p), tvp)); |
|
3815 unlock_user(p, arg2, 0); |
|
3816 } |
|
3817 break; |
|
3818 #endif |
|
3819 #ifdef TARGET_NR_stty |
|
3820 case TARGET_NR_stty: |
|
3821 goto unimplemented; |
|
3822 #endif |
|
3823 #ifdef TARGET_NR_gtty |
|
3824 case TARGET_NR_gtty: |
|
3825 goto unimplemented; |
|
3826 #endif |
|
3827 case TARGET_NR_access: |
|
3828 if (!(p = lock_user_string(arg1))) |
|
3829 goto efault; |
|
3830 ret = get_errno(access(p, arg2)); |
|
3831 unlock_user(p, arg1, 0); |
|
3832 break; |
|
3833 #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) |
|
3834 case TARGET_NR_faccessat: |
|
3835 if (!(p = lock_user_string(arg2))) |
|
3836 goto efault; |
|
3837 ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); |
|
3838 unlock_user(p, arg2, 0); |
|
3839 break; |
|
3840 #endif |
|
3841 #ifdef TARGET_NR_nice /* not on alpha */ |
|
3842 case TARGET_NR_nice: |
|
3843 ret = get_errno(nice(arg1)); |
|
3844 break; |
|
3845 #endif |
|
3846 #ifdef TARGET_NR_ftime |
|
3847 case TARGET_NR_ftime: |
|
3848 goto unimplemented; |
|
3849 #endif |
|
3850 case TARGET_NR_sync: |
|
3851 sync(); |
|
3852 ret = 0; |
|
3853 break; |
|
3854 case TARGET_NR_kill: |
|
3855 ret = get_errno(kill(arg1, target_to_host_signal(arg2))); |
|
3856 break; |
|
3857 case TARGET_NR_rename: |
|
3858 { |
|
3859 void *p2; |
|
3860 p = lock_user_string(arg1); |
|
3861 p2 = lock_user_string(arg2); |
|
3862 if (!p || !p2) |
|
3863 ret = -TARGET_EFAULT; |
|
3864 else |
|
3865 ret = get_errno(rename(p, p2)); |
|
3866 unlock_user(p2, arg2, 0); |
|
3867 unlock_user(p, arg1, 0); |
|
3868 } |
|
3869 break; |
|
3870 #if defined(TARGET_NR_renameat) && defined(__NR_renameat) |
|
3871 case TARGET_NR_renameat: |
|
3872 { |
|
3873 void *p2; |
|
3874 p = lock_user_string(arg2); |
|
3875 p2 = lock_user_string(arg4); |
|
3876 if (!p || !p2) |
|
3877 ret = -TARGET_EFAULT; |
|
3878 else |
|
3879 ret = get_errno(sys_renameat(arg1, p, arg3, p2)); |
|
3880 unlock_user(p2, arg4, 0); |
|
3881 unlock_user(p, arg2, 0); |
|
3882 } |
|
3883 break; |
|
3884 #endif |
|
3885 case TARGET_NR_mkdir: |
|
3886 if (!(p = lock_user_string(arg1))) |
|
3887 goto efault; |
|
3888 ret = get_errno(mkdir(p, arg2)); |
|
3889 unlock_user(p, arg1, 0); |
|
3890 break; |
|
3891 #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) |
|
3892 case TARGET_NR_mkdirat: |
|
3893 if (!(p = lock_user_string(arg2))) |
|
3894 goto efault; |
|
3895 ret = get_errno(sys_mkdirat(arg1, p, arg3)); |
|
3896 unlock_user(p, arg2, 0); |
|
3897 break; |
|
3898 #endif |
|
3899 case TARGET_NR_rmdir: |
|
3900 if (!(p = lock_user_string(arg1))) |
|
3901 goto efault; |
|
3902 ret = get_errno(rmdir(p)); |
|
3903 unlock_user(p, arg1, 0); |
|
3904 break; |
|
3905 case TARGET_NR_dup: |
|
3906 ret = get_errno(dup(arg1)); |
|
3907 break; |
|
3908 case TARGET_NR_pipe: |
|
3909 { |
|
3910 int host_pipe[2]; |
|
3911 ret = get_errno(pipe(host_pipe)); |
|
3912 if (!is_error(ret)) { |
|
3913 #if defined(TARGET_MIPS) |
|
3914 CPUMIPSState *env = (CPUMIPSState*)cpu_env; |
|
3915 env->active_tc.gpr[3] = host_pipe[1]; |
|
3916 ret = host_pipe[0]; |
|
3917 #elif defined(TARGET_SH4) |
|
3918 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; |
|
3919 ret = host_pipe[0]; |
|
3920 #else |
|
3921 if (put_user_s32(host_pipe[0], arg1) |
|
3922 || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0]))) |
|
3923 goto efault; |
|
3924 #endif |
|
3925 } |
|
3926 } |
|
3927 break; |
|
3928 case TARGET_NR_times: |
|
3929 { |
|
3930 struct target_tms *tmsp; |
|
3931 struct tms tms; |
|
3932 ret = get_errno(times(&tms)); |
|
3933 if (arg1) { |
|
3934 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0); |
|
3935 if (!tmsp) |
|
3936 goto efault; |
|
3937 tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); |
|
3938 tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); |
|
3939 tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); |
|
3940 tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime)); |
|
3941 } |
|
3942 if (!is_error(ret)) |
|
3943 ret = host_to_target_clock_t(ret); |
|
3944 } |
|
3945 break; |
|
3946 #ifdef TARGET_NR_prof |
|
3947 case TARGET_NR_prof: |
|
3948 goto unimplemented; |
|
3949 #endif |
|
3950 #ifdef TARGET_NR_signal |
|
3951 case TARGET_NR_signal: |
|
3952 goto unimplemented; |
|
3953 #endif |
|
3954 case TARGET_NR_acct: |
|
3955 if (!(p = lock_user_string(arg1))) |
|
3956 goto efault; |
|
3957 ret = get_errno(acct(path(p))); |
|
3958 unlock_user(p, arg1, 0); |
|
3959 break; |
|
3960 #ifdef TARGET_NR_umount2 /* not on alpha */ |
|
3961 case TARGET_NR_umount2: |
|
3962 if (!(p = lock_user_string(arg1))) |
|
3963 goto efault; |
|
3964 ret = get_errno(umount2(p, arg2)); |
|
3965 unlock_user(p, arg1, 0); |
|
3966 break; |
|
3967 #endif |
|
3968 #ifdef TARGET_NR_lock |
|
3969 case TARGET_NR_lock: |
|
3970 goto unimplemented; |
|
3971 #endif |
|
3972 case TARGET_NR_ioctl: |
|
3973 ret = do_ioctl(arg1, arg2, arg3); |
|
3974 break; |
|
3975 case TARGET_NR_fcntl: |
|
3976 ret = do_fcntl(arg1, arg2, arg3); |
|
3977 break; |
|
3978 #ifdef TARGET_NR_mpx |
|
3979 case TARGET_NR_mpx: |
|
3980 goto unimplemented; |
|
3981 #endif |
|
3982 case TARGET_NR_setpgid: |
|
3983 ret = get_errno(setpgid(arg1, arg2)); |
|
3984 break; |
|
3985 #ifdef TARGET_NR_ulimit |
|
3986 case TARGET_NR_ulimit: |
|
3987 goto unimplemented; |
|
3988 #endif |
|
3989 #ifdef TARGET_NR_oldolduname |
|
3990 case TARGET_NR_oldolduname: |
|
3991 goto unimplemented; |
|
3992 #endif |
|
3993 case TARGET_NR_umask: |
|
3994 ret = get_errno(umask(arg1)); |
|
3995 break; |
|
3996 case TARGET_NR_chroot: |
|
3997 if (!(p = lock_user_string(arg1))) |
|
3998 goto efault; |
|
3999 ret = get_errno(chroot(p)); |
|
4000 unlock_user(p, arg1, 0); |
|
4001 break; |
|
4002 case TARGET_NR_ustat: |
|
4003 goto unimplemented; |
|
4004 case TARGET_NR_dup2: |
|
4005 ret = get_errno(dup2(arg1, arg2)); |
|
4006 break; |
|
4007 #ifdef TARGET_NR_getppid /* not on alpha */ |
|
4008 case TARGET_NR_getppid: |
|
4009 ret = get_errno(getppid()); |
|
4010 break; |
|
4011 #endif |
|
4012 case TARGET_NR_getpgrp: |
|
4013 ret = get_errno(getpgrp()); |
|
4014 break; |
|
4015 case TARGET_NR_setsid: |
|
4016 ret = get_errno(setsid()); |
|
4017 break; |
|
4018 #ifdef TARGET_NR_sigaction |
|
4019 case TARGET_NR_sigaction: |
|
4020 { |
|
4021 #if !defined(TARGET_MIPS) |
|
4022 struct target_old_sigaction *old_act; |
|
4023 struct target_sigaction act, oact, *pact; |
|
4024 if (arg2) { |
|
4025 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) |
|
4026 goto efault; |
|
4027 act._sa_handler = old_act->_sa_handler; |
|
4028 target_siginitset(&act.sa_mask, old_act->sa_mask); |
|
4029 act.sa_flags = old_act->sa_flags; |
|
4030 act.sa_restorer = old_act->sa_restorer; |
|
4031 unlock_user_struct(old_act, arg2, 0); |
|
4032 pact = &act; |
|
4033 } else { |
|
4034 pact = NULL; |
|
4035 } |
|
4036 ret = get_errno(do_sigaction(arg1, pact, &oact)); |
|
4037 if (!is_error(ret) && arg3) { |
|
4038 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) |
|
4039 goto efault; |
|
4040 old_act->_sa_handler = oact._sa_handler; |
|
4041 old_act->sa_mask = oact.sa_mask.sig[0]; |
|
4042 old_act->sa_flags = oact.sa_flags; |
|
4043 old_act->sa_restorer = oact.sa_restorer; |
|
4044 unlock_user_struct(old_act, arg3, 1); |
|
4045 } |
|
4046 #else |
|
4047 struct target_sigaction act, oact, *pact, *old_act; |
|
4048 |
|
4049 if (arg2) { |
|
4050 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) |
|
4051 goto efault; |
|
4052 act._sa_handler = old_act->_sa_handler; |
|
4053 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); |
|
4054 act.sa_flags = old_act->sa_flags; |
|
4055 unlock_user_struct(old_act, arg2, 0); |
|
4056 pact = &act; |
|
4057 } else { |
|
4058 pact = NULL; |
|
4059 } |
|
4060 |
|
4061 ret = get_errno(do_sigaction(arg1, pact, &oact)); |
|
4062 |
|
4063 if (!is_error(ret) && arg3) { |
|
4064 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) |
|
4065 goto efault; |
|
4066 old_act->_sa_handler = oact._sa_handler; |
|
4067 old_act->sa_flags = oact.sa_flags; |
|
4068 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; |
|
4069 old_act->sa_mask.sig[1] = 0; |
|
4070 old_act->sa_mask.sig[2] = 0; |
|
4071 old_act->sa_mask.sig[3] = 0; |
|
4072 unlock_user_struct(old_act, arg3, 1); |
|
4073 } |
|
4074 #endif |
|
4075 } |
|
4076 break; |
|
4077 #endif |
|
4078 case TARGET_NR_rt_sigaction: |
|
4079 { |
|
4080 struct target_sigaction *act; |
|
4081 struct target_sigaction *oact; |
|
4082 |
|
4083 if (arg2) { |
|
4084 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) |
|
4085 goto efault; |
|
4086 } else |
|
4087 act = NULL; |
|
4088 if (arg3) { |
|
4089 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) { |
|
4090 ret = -TARGET_EFAULT; |
|
4091 goto rt_sigaction_fail; |
|
4092 } |
|
4093 } else |
|
4094 oact = NULL; |
|
4095 ret = get_errno(do_sigaction(arg1, act, oact)); |
|
4096 rt_sigaction_fail: |
|
4097 if (act) |
|
4098 unlock_user_struct(act, arg2, 0); |
|
4099 if (oact) |
|
4100 unlock_user_struct(oact, arg3, 1); |
|
4101 } |
|
4102 break; |
|
4103 #ifdef TARGET_NR_sgetmask /* not on alpha */ |
|
4104 case TARGET_NR_sgetmask: |
|
4105 { |
|
4106 sigset_t cur_set; |
|
4107 abi_ulong target_set; |
|
4108 sigprocmask(0, NULL, &cur_set); |
|
4109 host_to_target_old_sigset(&target_set, &cur_set); |
|
4110 ret = target_set; |
|
4111 } |
|
4112 break; |
|
4113 #endif |
|
4114 #ifdef TARGET_NR_ssetmask /* not on alpha */ |
|
4115 case TARGET_NR_ssetmask: |
|
4116 { |
|
4117 sigset_t set, oset, cur_set; |
|
4118 abi_ulong target_set = arg1; |
|
4119 sigprocmask(0, NULL, &cur_set); |
|
4120 target_to_host_old_sigset(&set, &target_set); |
|
4121 sigorset(&set, &set, &cur_set); |
|
4122 sigprocmask(SIG_SETMASK, &set, &oset); |
|
4123 host_to_target_old_sigset(&target_set, &oset); |
|
4124 ret = target_set; |
|
4125 } |
|
4126 break; |
|
4127 #endif |
|
4128 #ifdef TARGET_NR_sigprocmask |
|
4129 case TARGET_NR_sigprocmask: |
|
4130 { |
|
4131 int how = arg1; |
|
4132 sigset_t set, oldset, *set_ptr; |
|
4133 |
|
4134 if (arg2) { |
|
4135 switch(how) { |
|
4136 case TARGET_SIG_BLOCK: |
|
4137 how = SIG_BLOCK; |
|
4138 break; |
|
4139 case TARGET_SIG_UNBLOCK: |
|
4140 how = SIG_UNBLOCK; |
|
4141 break; |
|
4142 case TARGET_SIG_SETMASK: |
|
4143 how = SIG_SETMASK; |
|
4144 break; |
|
4145 default: |
|
4146 ret = -TARGET_EINVAL; |
|
4147 goto fail; |
|
4148 } |
|
4149 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) |
|
4150 goto efault; |
|
4151 target_to_host_old_sigset(&set, p); |
|
4152 unlock_user(p, arg2, 0); |
|
4153 set_ptr = &set; |
|
4154 } else { |
|
4155 how = 0; |
|
4156 set_ptr = NULL; |
|
4157 } |
|
4158 ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); |
|
4159 if (!is_error(ret) && arg3) { |
|
4160 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) |
|
4161 goto efault; |
|
4162 host_to_target_old_sigset(p, &oldset); |
|
4163 unlock_user(p, arg3, sizeof(target_sigset_t)); |
|
4164 } |
|
4165 } |
|
4166 break; |
|
4167 #endif |
|
4168 case TARGET_NR_rt_sigprocmask: |
|
4169 { |
|
4170 int how = arg1; |
|
4171 sigset_t set, oldset, *set_ptr; |
|
4172 |
|
4173 if (arg2) { |
|
4174 switch(how) { |
|
4175 case TARGET_SIG_BLOCK: |
|
4176 how = SIG_BLOCK; |
|
4177 break; |
|
4178 case TARGET_SIG_UNBLOCK: |
|
4179 how = SIG_UNBLOCK; |
|
4180 break; |
|
4181 case TARGET_SIG_SETMASK: |
|
4182 how = SIG_SETMASK; |
|
4183 break; |
|
4184 default: |
|
4185 ret = -TARGET_EINVAL; |
|
4186 goto fail; |
|
4187 } |
|
4188 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) |
|
4189 goto efault; |
|
4190 target_to_host_sigset(&set, p); |
|
4191 unlock_user(p, arg2, 0); |
|
4192 set_ptr = &set; |
|
4193 } else { |
|
4194 how = 0; |
|
4195 set_ptr = NULL; |
|
4196 } |
|
4197 ret = get_errno(sigprocmask(how, set_ptr, &oldset)); |
|
4198 if (!is_error(ret) && arg3) { |
|
4199 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) |
|
4200 goto efault; |
|
4201 host_to_target_sigset(p, &oldset); |
|
4202 unlock_user(p, arg3, sizeof(target_sigset_t)); |
|
4203 } |
|
4204 } |
|
4205 break; |
|
4206 #ifdef TARGET_NR_sigpending |
|
4207 case TARGET_NR_sigpending: |
|
4208 { |
|
4209 sigset_t set; |
|
4210 ret = get_errno(sigpending(&set)); |
|
4211 if (!is_error(ret)) { |
|
4212 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) |
|
4213 goto efault; |
|
4214 host_to_target_old_sigset(p, &set); |
|
4215 unlock_user(p, arg1, sizeof(target_sigset_t)); |
|
4216 } |
|
4217 } |
|
4218 break; |
|
4219 #endif |
|
4220 case TARGET_NR_rt_sigpending: |
|
4221 { |
|
4222 sigset_t set; |
|
4223 ret = get_errno(sigpending(&set)); |
|
4224 if (!is_error(ret)) { |
|
4225 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) |
|
4226 goto efault; |
|
4227 host_to_target_sigset(p, &set); |
|
4228 unlock_user(p, arg1, sizeof(target_sigset_t)); |
|
4229 } |
|
4230 } |
|
4231 break; |
|
4232 #ifdef TARGET_NR_sigsuspend |
|
4233 case TARGET_NR_sigsuspend: |
|
4234 { |
|
4235 sigset_t set; |
|
4236 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) |
|
4237 goto efault; |
|
4238 target_to_host_old_sigset(&set, p); |
|
4239 unlock_user(p, arg1, 0); |
|
4240 ret = get_errno(sigsuspend(&set)); |
|
4241 } |
|
4242 break; |
|
4243 #endif |
|
4244 case TARGET_NR_rt_sigsuspend: |
|
4245 { |
|
4246 sigset_t set; |
|
4247 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) |
|
4248 goto efault; |
|
4249 target_to_host_sigset(&set, p); |
|
4250 unlock_user(p, arg1, 0); |
|
4251 ret = get_errno(sigsuspend(&set)); |
|
4252 } |
|
4253 break; |
|
4254 case TARGET_NR_rt_sigtimedwait: |
|
4255 { |
|
4256 sigset_t set; |
|
4257 struct timespec uts, *puts; |
|
4258 siginfo_t uinfo; |
|
4259 |
|
4260 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) |
|
4261 goto efault; |
|
4262 target_to_host_sigset(&set, p); |
|
4263 unlock_user(p, arg1, 0); |
|
4264 if (arg3) { |
|
4265 puts = &uts; |
|
4266 target_to_host_timespec(puts, arg3); |
|
4267 } else { |
|
4268 puts = NULL; |
|
4269 } |
|
4270 ret = get_errno(sigtimedwait(&set, &uinfo, puts)); |
|
4271 if (!is_error(ret) && arg2) { |
|
4272 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0))) |
|
4273 goto efault; |
|
4274 host_to_target_siginfo(p, &uinfo); |
|
4275 unlock_user(p, arg2, sizeof(target_siginfo_t)); |
|
4276 } |
|
4277 } |
|
4278 break; |
|
4279 case TARGET_NR_rt_sigqueueinfo: |
|
4280 { |
|
4281 siginfo_t uinfo; |
|
4282 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1))) |
|
4283 goto efault; |
|
4284 target_to_host_siginfo(&uinfo, p); |
|
4285 unlock_user(p, arg1, 0); |
|
4286 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); |
|
4287 } |
|
4288 break; |
|
4289 #ifdef TARGET_NR_sigreturn |
|
4290 case TARGET_NR_sigreturn: |
|
4291 /* NOTE: ret is eax, so not transcoding must be done */ |
|
4292 ret = do_sigreturn(cpu_env); |
|
4293 break; |
|
4294 #endif |
|
4295 case TARGET_NR_rt_sigreturn: |
|
4296 /* NOTE: ret is eax, so not transcoding must be done */ |
|
4297 ret = do_rt_sigreturn(cpu_env); |
|
4298 break; |
|
4299 case TARGET_NR_sethostname: |
|
4300 if (!(p = lock_user_string(arg1))) |
|
4301 goto efault; |
|
4302 ret = get_errno(sethostname(p, arg2)); |
|
4303 unlock_user(p, arg1, 0); |
|
4304 break; |
|
4305 case TARGET_NR_setrlimit: |
|
4306 { |
|
4307 /* XXX: convert resource ? */ |
|
4308 int resource = arg1; |
|
4309 struct target_rlimit *target_rlim; |
|
4310 struct rlimit rlim; |
|
4311 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) |
|
4312 goto efault; |
|
4313 rlim.rlim_cur = tswapl(target_rlim->rlim_cur); |
|
4314 rlim.rlim_max = tswapl(target_rlim->rlim_max); |
|
4315 unlock_user_struct(target_rlim, arg2, 0); |
|
4316 ret = get_errno(setrlimit(resource, &rlim)); |
|
4317 } |
|
4318 break; |
|
4319 case TARGET_NR_getrlimit: |
|
4320 { |
|
4321 /* XXX: convert resource ? */ |
|
4322 int resource = arg1; |
|
4323 struct target_rlimit *target_rlim; |
|
4324 struct rlimit rlim; |
|
4325 |
|
4326 ret = get_errno(getrlimit(resource, &rlim)); |
|
4327 if (!is_error(ret)) { |
|
4328 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) |
|
4329 goto efault; |
|
4330 rlim.rlim_cur = tswapl(target_rlim->rlim_cur); |
|
4331 rlim.rlim_max = tswapl(target_rlim->rlim_max); |
|
4332 unlock_user_struct(target_rlim, arg2, 1); |
|
4333 } |
|
4334 } |
|
4335 break; |
|
4336 case TARGET_NR_getrusage: |
|
4337 { |
|
4338 struct rusage rusage; |
|
4339 ret = get_errno(getrusage(arg1, &rusage)); |
|
4340 if (!is_error(ret)) { |
|
4341 host_to_target_rusage(arg2, &rusage); |
|
4342 } |
|
4343 } |
|
4344 break; |
|
4345 case TARGET_NR_gettimeofday: |
|
4346 { |
|
4347 struct timeval tv; |
|
4348 ret = get_errno(gettimeofday(&tv, NULL)); |
|
4349 if (!is_error(ret)) { |
|
4350 if (copy_to_user_timeval(arg1, &tv)) |
|
4351 goto efault; |
|
4352 } |
|
4353 } |
|
4354 break; |
|
4355 case TARGET_NR_settimeofday: |
|
4356 { |
|
4357 struct timeval tv; |
|
4358 if (copy_from_user_timeval(&tv, arg1)) |
|
4359 goto efault; |
|
4360 ret = get_errno(settimeofday(&tv, NULL)); |
|
4361 } |
|
4362 break; |
|
4363 #ifdef TARGET_NR_select |
|
4364 case TARGET_NR_select: |
|
4365 { |
|
4366 struct target_sel_arg_struct *sel; |
|
4367 abi_ulong inp, outp, exp, tvp; |
|
4368 long nsel; |
|
4369 |
|
4370 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) |
|
4371 goto efault; |
|
4372 nsel = tswapl(sel->n); |
|
4373 inp = tswapl(sel->inp); |
|
4374 outp = tswapl(sel->outp); |
|
4375 exp = tswapl(sel->exp); |
|
4376 tvp = tswapl(sel->tvp); |
|
4377 unlock_user_struct(sel, arg1, 0); |
|
4378 ret = do_select(nsel, inp, outp, exp, tvp); |
|
4379 } |
|
4380 break; |
|
4381 #endif |
|
4382 case TARGET_NR_symlink: |
|
4383 { |
|
4384 void *p2; |
|
4385 p = lock_user_string(arg1); |
|
4386 p2 = lock_user_string(arg2); |
|
4387 if (!p || !p2) |
|
4388 ret = -TARGET_EFAULT; |
|
4389 else |
|
4390 ret = get_errno(symlink(p, p2)); |
|
4391 unlock_user(p2, arg2, 0); |
|
4392 unlock_user(p, arg1, 0); |
|
4393 } |
|
4394 break; |
|
4395 #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) |
|
4396 case TARGET_NR_symlinkat: |
|
4397 { |
|
4398 void *p2; |
|
4399 p = lock_user_string(arg1); |
|
4400 p2 = lock_user_string(arg3); |
|
4401 if (!p || !p2) |
|
4402 ret = -TARGET_EFAULT; |
|
4403 else |
|
4404 ret = get_errno(sys_symlinkat(p, arg2, p2)); |
|
4405 unlock_user(p2, arg3, 0); |
|
4406 unlock_user(p, arg1, 0); |
|
4407 } |
|
4408 break; |
|
4409 #endif |
|
4410 #ifdef TARGET_NR_oldlstat |
|
4411 case TARGET_NR_oldlstat: |
|
4412 goto unimplemented; |
|
4413 #endif |
|
4414 case TARGET_NR_readlink: |
|
4415 { |
|
4416 void *p2; |
|
4417 p = lock_user_string(arg1); |
|
4418 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); |
|
4419 if (!p || !p2) |
|
4420 ret = -TARGET_EFAULT; |
|
4421 else |
|
4422 ret = get_errno(readlink(path(p), p2, arg3)); |
|
4423 unlock_user(p2, arg2, ret); |
|
4424 unlock_user(p, arg1, 0); |
|
4425 } |
|
4426 break; |
|
4427 #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) |
|
4428 case TARGET_NR_readlinkat: |
|
4429 { |
|
4430 void *p2; |
|
4431 p = lock_user_string(arg2); |
|
4432 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); |
|
4433 if (!p || !p2) |
|
4434 ret = -TARGET_EFAULT; |
|
4435 else |
|
4436 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); |
|
4437 unlock_user(p2, arg3, ret); |
|
4438 unlock_user(p, arg2, 0); |
|
4439 } |
|
4440 break; |
|
4441 #endif |
|
4442 #ifdef TARGET_NR_uselib |
|
4443 case TARGET_NR_uselib: |
|
4444 goto unimplemented; |
|
4445 #endif |
|
4446 #ifdef TARGET_NR_swapon |
|
4447 case TARGET_NR_swapon: |
|
4448 if (!(p = lock_user_string(arg1))) |
|
4449 goto efault; |
|
4450 ret = get_errno(swapon(p, arg2)); |
|
4451 unlock_user(p, arg1, 0); |
|
4452 break; |
|
4453 #endif |
|
4454 case TARGET_NR_reboot: |
|
4455 goto unimplemented; |
|
4456 #ifdef TARGET_NR_readdir |
|
4457 case TARGET_NR_readdir: |
|
4458 goto unimplemented; |
|
4459 #endif |
|
4460 #ifdef TARGET_NR_mmap |
|
4461 case TARGET_NR_mmap: |
|
4462 #if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) |
|
4463 { |
|
4464 abi_ulong *v; |
|
4465 abi_ulong v1, v2, v3, v4, v5, v6; |
|
4466 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1))) |
|
4467 goto efault; |
|
4468 v1 = tswapl(v[0]); |
|
4469 v2 = tswapl(v[1]); |
|
4470 v3 = tswapl(v[2]); |
|
4471 v4 = tswapl(v[3]); |
|
4472 v5 = tswapl(v[4]); |
|
4473 v6 = tswapl(v[5]); |
|
4474 unlock_user(v, arg1, 0); |
|
4475 ret = get_errno(target_mmap(v1, v2, v3, |
|
4476 target_to_host_bitmask(v4, mmap_flags_tbl), |
|
4477 v5, v6)); |
|
4478 } |
|
4479 #else |
|
4480 ret = get_errno(target_mmap(arg1, arg2, arg3, |
|
4481 target_to_host_bitmask(arg4, mmap_flags_tbl), |
|
4482 arg5, |
|
4483 arg6)); |
|
4484 #endif |
|
4485 break; |
|
4486 #endif |
|
4487 #ifdef TARGET_NR_mmap2 |
|
4488 case TARGET_NR_mmap2: |
|
4489 #ifndef MMAP_SHIFT |
|
4490 #define MMAP_SHIFT 12 |
|
4491 #endif |
|
4492 ret = get_errno(target_mmap(arg1, arg2, arg3, |
|
4493 target_to_host_bitmask(arg4, mmap_flags_tbl), |
|
4494 arg5, |
|
4495 arg6 << MMAP_SHIFT)); |
|
4496 break; |
|
4497 #endif |
|
4498 case TARGET_NR_munmap: |
|
4499 ret = get_errno(target_munmap(arg1, arg2)); |
|
4500 break; |
|
4501 case TARGET_NR_mprotect: |
|
4502 { |
|
4503 TaskState *ts = ((CPUState *)cpu_env)->opaque; |
|
4504 /* Special hack for libc making the stack executable. */ |
|
4505 if ((arg3 & TARGET_PROT_GROWSDOWN) |
|
4506 && (arg1 + TARGET_PAGE_SIZE == ts->info->stack_base)) { |
|
4507 arg3 &= ~TARGET_PROT_GROWSDOWN; |
|
4508 arg1 = ts->info->stack_base - x86_stack_size; |
|
4509 arg2 = x86_stack_size; |
|
4510 } |
|
4511 } |
|
4512 ret = get_errno(target_mprotect(arg1, arg2, arg3)); |
|
4513 break; |
|
4514 #ifdef TARGET_NR_mremap |
|
4515 case TARGET_NR_mremap: |
|
4516 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); |
|
4517 break; |
|
4518 #endif |
|
4519 /* ??? msync/mlock/munlock are broken for softmmu. */ |
|
4520 #ifdef TARGET_NR_msync |
|
4521 case TARGET_NR_msync: |
|
4522 ret = get_errno(msync(g2h(arg1), arg2, arg3)); |
|
4523 break; |
|
4524 #endif |
|
4525 #ifdef TARGET_NR_mlock |
|
4526 case TARGET_NR_mlock: |
|
4527 ret = get_errno(mlock(g2h(arg1), arg2)); |
|
4528 break; |
|
4529 #endif |
|
4530 #ifdef TARGET_NR_munlock |
|
4531 case TARGET_NR_munlock: |
|
4532 ret = get_errno(munlock(g2h(arg1), arg2)); |
|
4533 break; |
|
4534 #endif |
|
4535 #ifdef TARGET_NR_mlockall |
|
4536 case TARGET_NR_mlockall: |
|
4537 ret = get_errno(mlockall(arg1)); |
|
4538 break; |
|
4539 #endif |
|
4540 #ifdef TARGET_NR_munlockall |
|
4541 case TARGET_NR_munlockall: |
|
4542 ret = get_errno(munlockall()); |
|
4543 break; |
|
4544 #endif |
|
4545 case TARGET_NR_truncate: |
|
4546 if (!(p = lock_user_string(arg1))) |
|
4547 goto efault; |
|
4548 ret = get_errno(truncate(p, arg2)); |
|
4549 unlock_user(p, arg1, 0); |
|
4550 break; |
|
4551 case TARGET_NR_ftruncate: |
|
4552 ret = get_errno(ftruncate(arg1, arg2)); |
|
4553 break; |
|
4554 case TARGET_NR_fchmod: |
|
4555 ret = get_errno(fchmod(arg1, arg2)); |
|
4556 break; |
|
4557 #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) |
|
4558 case TARGET_NR_fchmodat: |
|
4559 if (!(p = lock_user_string(arg2))) |
|
4560 goto efault; |
|
4561 ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); |
|
4562 unlock_user(p, arg2, 0); |
|
4563 break; |
|
4564 #endif |
|
4565 case TARGET_NR_getpriority: |
|
4566 /* libc does special remapping of the return value of |
|
4567 * sys_getpriority() so it's just easiest to call |
|
4568 * sys_getpriority() directly rather than through libc. */ |
|
4569 ret = sys_getpriority(arg1, arg2); |
|
4570 break; |
|
4571 case TARGET_NR_setpriority: |
|
4572 ret = get_errno(setpriority(arg1, arg2, arg3)); |
|
4573 break; |
|
4574 #ifdef TARGET_NR_profil |
|
4575 case TARGET_NR_profil: |
|
4576 goto unimplemented; |
|
4577 #endif |
|
4578 case TARGET_NR_statfs: |
|
4579 if (!(p = lock_user_string(arg1))) |
|
4580 goto efault; |
|
4581 ret = get_errno(statfs(path(p), &stfs)); |
|
4582 unlock_user(p, arg1, 0); |
|
4583 convert_statfs: |
|
4584 if (!is_error(ret)) { |
|
4585 struct target_statfs *target_stfs; |
|
4586 |
|
4587 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0)) |
|
4588 goto efault; |
|
4589 __put_user(stfs.f_type, &target_stfs->f_type); |
|
4590 __put_user(stfs.f_bsize, &target_stfs->f_bsize); |
|
4591 __put_user(stfs.f_blocks, &target_stfs->f_blocks); |
|
4592 __put_user(stfs.f_bfree, &target_stfs->f_bfree); |
|
4593 __put_user(stfs.f_bavail, &target_stfs->f_bavail); |
|
4594 __put_user(stfs.f_files, &target_stfs->f_files); |
|
4595 __put_user(stfs.f_ffree, &target_stfs->f_ffree); |
|
4596 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); |
|
4597 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); |
|
4598 __put_user(stfs.f_namelen, &target_stfs->f_namelen); |
|
4599 unlock_user_struct(target_stfs, arg2, 1); |
|
4600 } |
|
4601 break; |
|
4602 case TARGET_NR_fstatfs: |
|
4603 ret = get_errno(fstatfs(arg1, &stfs)); |
|
4604 goto convert_statfs; |
|
4605 #ifdef TARGET_NR_statfs64 |
|
4606 case TARGET_NR_statfs64: |
|
4607 if (!(p = lock_user_string(arg1))) |
|
4608 goto efault; |
|
4609 ret = get_errno(statfs(path(p), &stfs)); |
|
4610 unlock_user(p, arg1, 0); |
|
4611 convert_statfs64: |
|
4612 if (!is_error(ret)) { |
|
4613 struct target_statfs64 *target_stfs; |
|
4614 |
|
4615 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0)) |
|
4616 goto efault; |
|
4617 __put_user(stfs.f_type, &target_stfs->f_type); |
|
4618 __put_user(stfs.f_bsize, &target_stfs->f_bsize); |
|
4619 __put_user(stfs.f_blocks, &target_stfs->f_blocks); |
|
4620 __put_user(stfs.f_bfree, &target_stfs->f_bfree); |
|
4621 __put_user(stfs.f_bavail, &target_stfs->f_bavail); |
|
4622 __put_user(stfs.f_files, &target_stfs->f_files); |
|
4623 __put_user(stfs.f_ffree, &target_stfs->f_ffree); |
|
4624 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); |
|
4625 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); |
|
4626 __put_user(stfs.f_namelen, &target_stfs->f_namelen); |
|
4627 unlock_user_struct(target_stfs, arg3, 1); |
|
4628 } |
|
4629 break; |
|
4630 case TARGET_NR_fstatfs64: |
|
4631 ret = get_errno(fstatfs(arg1, &stfs)); |
|
4632 goto convert_statfs64; |
|
4633 #endif |
|
4634 #ifdef TARGET_NR_ioperm |
|
4635 case TARGET_NR_ioperm: |
|
4636 goto unimplemented; |
|
4637 #endif |
|
4638 #ifdef TARGET_NR_socketcall |
|
4639 case TARGET_NR_socketcall: |
|
4640 ret = do_socketcall(arg1, arg2); |
|
4641 break; |
|
4642 #endif |
|
4643 #ifdef TARGET_NR_accept |
|
4644 case TARGET_NR_accept: |
|
4645 ret = do_accept(arg1, arg2, arg3); |
|
4646 break; |
|
4647 #endif |
|
4648 #ifdef TARGET_NR_bind |
|
4649 case TARGET_NR_bind: |
|
4650 ret = do_bind(arg1, arg2, arg3); |
|
4651 break; |
|
4652 #endif |
|
4653 #ifdef TARGET_NR_connect |
|
4654 case TARGET_NR_connect: |
|
4655 ret = do_connect(arg1, arg2, arg3); |
|
4656 break; |
|
4657 #endif |
|
4658 #ifdef TARGET_NR_getpeername |
|
4659 case TARGET_NR_getpeername: |
|
4660 ret = do_getpeername(arg1, arg2, arg3); |
|
4661 break; |
|
4662 #endif |
|
4663 #ifdef TARGET_NR_getsockname |
|
4664 case TARGET_NR_getsockname: |
|
4665 ret = do_getsockname(arg1, arg2, arg3); |
|
4666 break; |
|
4667 #endif |
|
4668 #ifdef TARGET_NR_getsockopt |
|
4669 case TARGET_NR_getsockopt: |
|
4670 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5); |
|
4671 break; |
|
4672 #endif |
|
4673 #ifdef TARGET_NR_listen |
|
4674 case TARGET_NR_listen: |
|
4675 ret = get_errno(listen(arg1, arg2)); |
|
4676 break; |
|
4677 #endif |
|
4678 #ifdef TARGET_NR_recv |
|
4679 case TARGET_NR_recv: |
|
4680 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0); |
|
4681 break; |
|
4682 #endif |
|
4683 #ifdef TARGET_NR_recvfrom |
|
4684 case TARGET_NR_recvfrom: |
|
4685 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6); |
|
4686 break; |
|
4687 #endif |
|
4688 #ifdef TARGET_NR_recvmsg |
|
4689 case TARGET_NR_recvmsg: |
|
4690 ret = do_sendrecvmsg(arg1, arg2, arg3, 0); |
|
4691 break; |
|
4692 #endif |
|
4693 #ifdef TARGET_NR_send |
|
4694 case TARGET_NR_send: |
|
4695 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0); |
|
4696 break; |
|
4697 #endif |
|
4698 #ifdef TARGET_NR_sendmsg |
|
4699 case TARGET_NR_sendmsg: |
|
4700 ret = do_sendrecvmsg(arg1, arg2, arg3, 1); |
|
4701 break; |
|
4702 #endif |
|
4703 #ifdef TARGET_NR_sendto |
|
4704 case TARGET_NR_sendto: |
|
4705 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); |
|
4706 break; |
|
4707 #endif |
|
4708 #ifdef TARGET_NR_shutdown |
|
4709 case TARGET_NR_shutdown: |
|
4710 ret = get_errno(shutdown(arg1, arg2)); |
|
4711 break; |
|
4712 #endif |
|
4713 #ifdef TARGET_NR_socket |
|
4714 case TARGET_NR_socket: |
|
4715 ret = do_socket(arg1, arg2, arg3); |
|
4716 break; |
|
4717 #endif |
|
4718 #ifdef TARGET_NR_socketpair |
|
4719 case TARGET_NR_socketpair: |
|
4720 ret = do_socketpair(arg1, arg2, arg3, arg4); |
|
4721 break; |
|
4722 #endif |
|
4723 #ifdef TARGET_NR_setsockopt |
|
4724 case TARGET_NR_setsockopt: |
|
4725 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); |
|
4726 break; |
|
4727 #endif |
|
4728 |
|
4729 case TARGET_NR_syslog: |
|
4730 if (!(p = lock_user_string(arg2))) |
|
4731 goto efault; |
|
4732 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); |
|
4733 unlock_user(p, arg2, 0); |
|
4734 break; |
|
4735 |
|
4736 case TARGET_NR_setitimer: |
|
4737 { |
|
4738 struct itimerval value, ovalue, *pvalue; |
|
4739 |
|
4740 if (arg2) { |
|
4741 pvalue = &value; |
|
4742 if (copy_from_user_timeval(&pvalue->it_interval, arg2) |
|
4743 || copy_from_user_timeval(&pvalue->it_value, |
|
4744 arg2 + sizeof(struct target_timeval))) |
|
4745 goto efault; |
|
4746 } else { |
|
4747 pvalue = NULL; |
|
4748 } |
|
4749 ret = get_errno(setitimer(arg1, pvalue, &ovalue)); |
|
4750 if (!is_error(ret) && arg3) { |
|
4751 if (copy_to_user_timeval(arg3, |
|
4752 &ovalue.it_interval) |
|
4753 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval), |
|
4754 &ovalue.it_value)) |
|
4755 goto efault; |
|
4756 } |
|
4757 } |
|
4758 break; |
|
4759 case TARGET_NR_getitimer: |
|
4760 { |
|
4761 struct itimerval value; |
|
4762 |
|
4763 ret = get_errno(getitimer(arg1, &value)); |
|
4764 if (!is_error(ret) && arg2) { |
|
4765 if (copy_to_user_timeval(arg2, |
|
4766 &value.it_interval) |
|
4767 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval), |
|
4768 &value.it_value)) |
|
4769 goto efault; |
|
4770 } |
|
4771 } |
|
4772 break; |
|
4773 case TARGET_NR_stat: |
|
4774 if (!(p = lock_user_string(arg1))) |
|
4775 goto efault; |
|
4776 ret = get_errno(stat(path(p), &st)); |
|
4777 unlock_user(p, arg1, 0); |
|
4778 goto do_stat; |
|
4779 case TARGET_NR_lstat: |
|
4780 if (!(p = lock_user_string(arg1))) |
|
4781 goto efault; |
|
4782 ret = get_errno(lstat(path(p), &st)); |
|
4783 unlock_user(p, arg1, 0); |
|
4784 goto do_stat; |
|
4785 case TARGET_NR_fstat: |
|
4786 { |
|
4787 ret = get_errno(fstat(arg1, &st)); |
|
4788 do_stat: |
|
4789 if (!is_error(ret)) { |
|
4790 struct target_stat *target_st; |
|
4791 |
|
4792 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) |
|
4793 goto efault; |
|
4794 __put_user(st.st_dev, &target_st->st_dev); |
|
4795 __put_user(st.st_ino, &target_st->st_ino); |
|
4796 __put_user(st.st_mode, &target_st->st_mode); |
|
4797 __put_user(st.st_uid, &target_st->st_uid); |
|
4798 __put_user(st.st_gid, &target_st->st_gid); |
|
4799 __put_user(st.st_nlink, &target_st->st_nlink); |
|
4800 __put_user(st.st_rdev, &target_st->st_rdev); |
|
4801 __put_user(st.st_size, &target_st->st_size); |
|
4802 __put_user(st.st_blksize, &target_st->st_blksize); |
|
4803 __put_user(st.st_blocks, &target_st->st_blocks); |
|
4804 __put_user(st.st_atime, &target_st->target_st_atime); |
|
4805 __put_user(st.st_mtime, &target_st->target_st_mtime); |
|
4806 __put_user(st.st_ctime, &target_st->target_st_ctime); |
|
4807 unlock_user_struct(target_st, arg2, 1); |
|
4808 } |
|
4809 } |
|
4810 break; |
|
4811 #ifdef TARGET_NR_olduname |
|
4812 case TARGET_NR_olduname: |
|
4813 goto unimplemented; |
|
4814 #endif |
|
4815 #ifdef TARGET_NR_iopl |
|
4816 case TARGET_NR_iopl: |
|
4817 goto unimplemented; |
|
4818 #endif |
|
4819 case TARGET_NR_vhangup: |
|
4820 ret = get_errno(vhangup()); |
|
4821 break; |
|
4822 #ifdef TARGET_NR_idle |
|
4823 case TARGET_NR_idle: |
|
4824 goto unimplemented; |
|
4825 #endif |
|
4826 #ifdef TARGET_NR_syscall |
|
4827 case TARGET_NR_syscall: |
|
4828 ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); |
|
4829 break; |
|
4830 #endif |
|
4831 case TARGET_NR_wait4: |
|
4832 { |
|
4833 int status; |
|
4834 abi_long status_ptr = arg2; |
|
4835 struct rusage rusage, *rusage_ptr; |
|
4836 abi_ulong target_rusage = arg4; |
|
4837 if (target_rusage) |
|
4838 rusage_ptr = &rusage; |
|
4839 else |
|
4840 rusage_ptr = NULL; |
|
4841 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); |
|
4842 if (!is_error(ret)) { |
|
4843 if (status_ptr) { |
|
4844 if (put_user_s32(status, status_ptr)) |
|
4845 goto efault; |
|
4846 } |
|
4847 if (target_rusage) |
|
4848 host_to_target_rusage(target_rusage, &rusage); |
|
4849 } |
|
4850 } |
|
4851 break; |
|
4852 #ifdef TARGET_NR_swapoff |
|
4853 case TARGET_NR_swapoff: |
|
4854 if (!(p = lock_user_string(arg1))) |
|
4855 goto efault; |
|
4856 ret = get_errno(swapoff(p)); |
|
4857 unlock_user(p, arg1, 0); |
|
4858 break; |
|
4859 #endif |
|
4860 case TARGET_NR_sysinfo: |
|
4861 { |
|
4862 struct target_sysinfo *target_value; |
|
4863 struct sysinfo value; |
|
4864 ret = get_errno(sysinfo(&value)); |
|
4865 if (!is_error(ret) && arg1) |
|
4866 { |
|
4867 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0)) |
|
4868 goto efault; |
|
4869 __put_user(value.uptime, &target_value->uptime); |
|
4870 __put_user(value.loads[0], &target_value->loads[0]); |
|
4871 __put_user(value.loads[1], &target_value->loads[1]); |
|
4872 __put_user(value.loads[2], &target_value->loads[2]); |
|
4873 __put_user(value.totalram, &target_value->totalram); |
|
4874 __put_user(value.freeram, &target_value->freeram); |
|
4875 __put_user(value.sharedram, &target_value->sharedram); |
|
4876 __put_user(value.bufferram, &target_value->bufferram); |
|
4877 __put_user(value.totalswap, &target_value->totalswap); |
|
4878 __put_user(value.freeswap, &target_value->freeswap); |
|
4879 __put_user(value.procs, &target_value->procs); |
|
4880 __put_user(value.totalhigh, &target_value->totalhigh); |
|
4881 __put_user(value.freehigh, &target_value->freehigh); |
|
4882 __put_user(value.mem_unit, &target_value->mem_unit); |
|
4883 unlock_user_struct(target_value, arg1, 1); |
|
4884 } |
|
4885 } |
|
4886 break; |
|
4887 #ifdef TARGET_NR_ipc |
|
4888 case TARGET_NR_ipc: |
|
4889 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); |
|
4890 break; |
|
4891 #endif |
|
4892 |
|
4893 #ifdef TARGET_NR_msgctl |
|
4894 case TARGET_NR_msgctl: |
|
4895 ret = do_msgctl(arg1, arg2, arg3); |
|
4896 break; |
|
4897 #endif |
|
4898 #ifdef TARGET_NR_msgget |
|
4899 case TARGET_NR_msgget: |
|
4900 ret = get_errno(msgget(arg1, arg2)); |
|
4901 break; |
|
4902 #endif |
|
4903 #ifdef TARGET_NR_msgrcv |
|
4904 case TARGET_NR_msgrcv: |
|
4905 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5); |
|
4906 break; |
|
4907 #endif |
|
4908 #ifdef TARGET_NR_msgsnd |
|
4909 case TARGET_NR_msgsnd: |
|
4910 ret = do_msgsnd(arg1, arg2, arg3, arg4); |
|
4911 break; |
|
4912 #endif |
|
4913 case TARGET_NR_fsync: |
|
4914 ret = get_errno(fsync(arg1)); |
|
4915 break; |
|
4916 case TARGET_NR_clone: |
|
4917 #if defined(TARGET_SH4) |
|
4918 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); |
|
4919 #else |
|
4920 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); |
|
4921 #endif |
|
4922 break; |
|
4923 #ifdef __NR_exit_group |
|
4924 /* new thread calls */ |
|
4925 case TARGET_NR_exit_group: |
|
4926 #ifdef HAVE_GPROF |
|
4927 _mcleanup(); |
|
4928 #endif |
|
4929 gdb_exit(cpu_env, arg1); |
|
4930 ret = get_errno(exit_group(arg1)); |
|
4931 break; |
|
4932 #endif |
|
4933 case TARGET_NR_setdomainname: |
|
4934 if (!(p = lock_user_string(arg1))) |
|
4935 goto efault; |
|
4936 ret = get_errno(setdomainname(p, arg2)); |
|
4937 unlock_user(p, arg1, 0); |
|
4938 break; |
|
4939 case TARGET_NR_uname: |
|
4940 /* no need to transcode because we use the linux syscall */ |
|
4941 { |
|
4942 struct new_utsname * buf; |
|
4943 |
|
4944 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0)) |
|
4945 goto efault; |
|
4946 ret = get_errno(sys_uname(buf)); |
|
4947 if (!is_error(ret)) { |
|
4948 /* Overrite the native machine name with whatever is being |
|
4949 emulated. */ |
|
4950 strcpy (buf->machine, UNAME_MACHINE); |
|
4951 /* Allow the user to override the reported release. */ |
|
4952 if (qemu_uname_release && *qemu_uname_release) |
|
4953 strcpy (buf->release, qemu_uname_release); |
|
4954 } |
|
4955 unlock_user_struct(buf, arg1, 1); |
|
4956 } |
|
4957 break; |
|
4958 #ifdef TARGET_I386 |
|
4959 case TARGET_NR_modify_ldt: |
|
4960 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3); |
|
4961 break; |
|
4962 #if !defined(TARGET_X86_64) |
|
4963 case TARGET_NR_vm86old: |
|
4964 goto unimplemented; |
|
4965 case TARGET_NR_vm86: |
|
4966 ret = do_vm86(cpu_env, arg1, arg2); |
|
4967 break; |
|
4968 #endif |
|
4969 #endif |
|
4970 case TARGET_NR_adjtimex: |
|
4971 goto unimplemented; |
|
4972 #ifdef TARGET_NR_create_module |
|
4973 case TARGET_NR_create_module: |
|
4974 #endif |
|
4975 case TARGET_NR_init_module: |
|
4976 case TARGET_NR_delete_module: |
|
4977 #ifdef TARGET_NR_get_kernel_syms |
|
4978 case TARGET_NR_get_kernel_syms: |
|
4979 #endif |
|
4980 goto unimplemented; |
|
4981 case TARGET_NR_quotactl: |
|
4982 goto unimplemented; |
|
4983 case TARGET_NR_getpgid: |
|
4984 ret = get_errno(getpgid(arg1)); |
|
4985 break; |
|
4986 case TARGET_NR_fchdir: |
|
4987 ret = get_errno(fchdir(arg1)); |
|
4988 break; |
|
4989 #ifdef TARGET_NR_bdflush /* not on x86_64 */ |
|
4990 case TARGET_NR_bdflush: |
|
4991 goto unimplemented; |
|
4992 #endif |
|
4993 #ifdef TARGET_NR_sysfs |
|
4994 case TARGET_NR_sysfs: |
|
4995 goto unimplemented; |
|
4996 #endif |
|
4997 case TARGET_NR_personality: |
|
4998 ret = get_errno(personality(arg1)); |
|
4999 break; |
|
5000 #ifdef TARGET_NR_afs_syscall |
|
5001 case TARGET_NR_afs_syscall: |
|
5002 goto unimplemented; |
|
5003 #endif |
|
5004 #ifdef TARGET_NR__llseek /* Not on alpha */ |
|
5005 case TARGET_NR__llseek: |
|
5006 { |
|
5007 #if defined (__x86_64__) |
|
5008 ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); |
|
5009 if (put_user_s64(ret, arg4)) |
|
5010 goto efault; |
|
5011 #else |
|
5012 int64_t res; |
|
5013 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); |
|
5014 if (put_user_s64(res, arg4)) |
|
5015 goto efault; |
|
5016 #endif |
|
5017 } |
|
5018 break; |
|
5019 #endif |
|
5020 case TARGET_NR_getdents: |
|
5021 #if TARGET_ABI_BITS != 32 |
|
5022 goto unimplemented; |
|
5023 #elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 |
|
5024 { |
|
5025 struct target_dirent *target_dirp; |
|
5026 struct linux_dirent *dirp; |
|
5027 abi_long count = arg3; |
|
5028 |
|
5029 dirp = malloc(count); |
|
5030 if (!dirp) { |
|
5031 ret = -TARGET_ENOMEM; |
|
5032 goto fail; |
|
5033 } |
|
5034 |
|
5035 ret = get_errno(sys_getdents(arg1, dirp, count)); |
|
5036 if (!is_error(ret)) { |
|
5037 struct linux_dirent *de; |
|
5038 struct target_dirent *tde; |
|
5039 int len = ret; |
|
5040 int reclen, treclen; |
|
5041 int count1, tnamelen; |
|
5042 |
|
5043 count1 = 0; |
|
5044 de = dirp; |
|
5045 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) |
|
5046 goto efault; |
|
5047 tde = target_dirp; |
|
5048 while (len > 0) { |
|
5049 reclen = de->d_reclen; |
|
5050 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long))); |
|
5051 tde->d_reclen = tswap16(treclen); |
|
5052 tde->d_ino = tswapl(de->d_ino); |
|
5053 tde->d_off = tswapl(de->d_off); |
|
5054 tnamelen = treclen - (2 * sizeof(abi_long) + 2); |
|
5055 if (tnamelen > 256) |
|
5056 tnamelen = 256; |
|
5057 /* XXX: may not be correct */ |
|
5058 pstrcpy(tde->d_name, tnamelen, de->d_name); |
|
5059 de = (struct linux_dirent *)((char *)de + reclen); |
|
5060 len -= reclen; |
|
5061 tde = (struct target_dirent *)((char *)tde + treclen); |
|
5062 count1 += treclen; |
|
5063 } |
|
5064 ret = count1; |
|
5065 unlock_user(target_dirp, arg2, ret); |
|
5066 } |
|
5067 free(dirp); |
|
5068 } |
|
5069 #else |
|
5070 { |
|
5071 struct linux_dirent *dirp; |
|
5072 abi_long count = arg3; |
|
5073 |
|
5074 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) |
|
5075 goto efault; |
|
5076 ret = get_errno(sys_getdents(arg1, dirp, count)); |
|
5077 if (!is_error(ret)) { |
|
5078 struct linux_dirent *de; |
|
5079 int len = ret; |
|
5080 int reclen; |
|
5081 de = dirp; |
|
5082 while (len > 0) { |
|
5083 reclen = de->d_reclen; |
|
5084 if (reclen > len) |
|
5085 break; |
|
5086 de->d_reclen = tswap16(reclen); |
|
5087 tswapls(&de->d_ino); |
|
5088 tswapls(&de->d_off); |
|
5089 de = (struct linux_dirent *)((char *)de + reclen); |
|
5090 len -= reclen; |
|
5091 } |
|
5092 } |
|
5093 unlock_user(dirp, arg2, ret); |
|
5094 } |
|
5095 #endif |
|
5096 break; |
|
5097 #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) |
|
5098 case TARGET_NR_getdents64: |
|
5099 { |
|
5100 struct linux_dirent64 *dirp; |
|
5101 abi_long count = arg3; |
|
5102 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) |
|
5103 goto efault; |
|
5104 ret = get_errno(sys_getdents64(arg1, dirp, count)); |
|
5105 if (!is_error(ret)) { |
|
5106 struct linux_dirent64 *de; |
|
5107 int len = ret; |
|
5108 int reclen; |
|
5109 de = dirp; |
|
5110 while (len > 0) { |
|
5111 reclen = de->d_reclen; |
|
5112 if (reclen > len) |
|
5113 break; |
|
5114 de->d_reclen = tswap16(reclen); |
|
5115 tswap64s((uint64_t *)&de->d_ino); |
|
5116 tswap64s((uint64_t *)&de->d_off); |
|
5117 de = (struct linux_dirent64 *)((char *)de + reclen); |
|
5118 len -= reclen; |
|
5119 } |
|
5120 } |
|
5121 unlock_user(dirp, arg2, ret); |
|
5122 } |
|
5123 break; |
|
5124 #endif /* TARGET_NR_getdents64 */ |
|
5125 #ifdef TARGET_NR__newselect |
|
5126 case TARGET_NR__newselect: |
|
5127 ret = do_select(arg1, arg2, arg3, arg4, arg5); |
|
5128 break; |
|
5129 #endif |
|
5130 #ifdef TARGET_NR_poll |
|
5131 case TARGET_NR_poll: |
|
5132 { |
|
5133 struct target_pollfd *target_pfd; |
|
5134 unsigned int nfds = arg2; |
|
5135 int timeout = arg3; |
|
5136 struct pollfd *pfd; |
|
5137 unsigned int i; |
|
5138 |
|
5139 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); |
|
5140 if (!target_pfd) |
|
5141 goto efault; |
|
5142 pfd = alloca(sizeof(struct pollfd) * nfds); |
|
5143 for(i = 0; i < nfds; i++) { |
|
5144 pfd[i].fd = tswap32(target_pfd[i].fd); |
|
5145 pfd[i].events = tswap16(target_pfd[i].events); |
|
5146 } |
|
5147 ret = get_errno(poll(pfd, nfds, timeout)); |
|
5148 if (!is_error(ret)) { |
|
5149 for(i = 0; i < nfds; i++) { |
|
5150 target_pfd[i].revents = tswap16(pfd[i].revents); |
|
5151 } |
|
5152 ret += nfds * (sizeof(struct target_pollfd) |
|
5153 - sizeof(struct pollfd)); |
|
5154 } |
|
5155 unlock_user(target_pfd, arg1, ret); |
|
5156 } |
|
5157 break; |
|
5158 #endif |
|
5159 case TARGET_NR_flock: |
|
5160 /* NOTE: the flock constant seems to be the same for every |
|
5161 Linux platform */ |
|
5162 ret = get_errno(flock(arg1, arg2)); |
|
5163 break; |
|
5164 case TARGET_NR_readv: |
|
5165 { |
|
5166 int count = arg3; |
|
5167 struct iovec *vec; |
|
5168 |
|
5169 vec = alloca(count * sizeof(struct iovec)); |
|
5170 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) |
|
5171 goto efault; |
|
5172 ret = get_errno(readv(arg1, vec, count)); |
|
5173 unlock_iovec(vec, arg2, count, 1); |
|
5174 } |
|
5175 break; |
|
5176 case TARGET_NR_writev: |
|
5177 { |
|
5178 int count = arg3; |
|
5179 struct iovec *vec; |
|
5180 |
|
5181 vec = alloca(count * sizeof(struct iovec)); |
|
5182 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) |
|
5183 goto efault; |
|
5184 ret = get_errno(writev(arg1, vec, count)); |
|
5185 unlock_iovec(vec, arg2, count, 0); |
|
5186 } |
|
5187 break; |
|
5188 case TARGET_NR_getsid: |
|
5189 ret = get_errno(getsid(arg1)); |
|
5190 break; |
|
5191 #if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */ |
|
5192 case TARGET_NR_fdatasync: |
|
5193 ret = get_errno(fdatasync(arg1)); |
|
5194 break; |
|
5195 #endif |
|
5196 case TARGET_NR__sysctl: |
|
5197 /* We don't implement this, but ENOTDIR is always a safe |
|
5198 return value. */ |
|
5199 ret = -TARGET_ENOTDIR; |
|
5200 break; |
|
5201 case TARGET_NR_sched_setparam: |
|
5202 { |
|
5203 struct sched_param *target_schp; |
|
5204 struct sched_param schp; |
|
5205 |
|
5206 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) |
|
5207 goto efault; |
|
5208 schp.sched_priority = tswap32(target_schp->sched_priority); |
|
5209 unlock_user_struct(target_schp, arg2, 0); |
|
5210 ret = get_errno(sched_setparam(arg1, &schp)); |
|
5211 } |
|
5212 break; |
|
5213 case TARGET_NR_sched_getparam: |
|
5214 { |
|
5215 struct sched_param *target_schp; |
|
5216 struct sched_param schp; |
|
5217 ret = get_errno(sched_getparam(arg1, &schp)); |
|
5218 if (!is_error(ret)) { |
|
5219 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) |
|
5220 goto efault; |
|
5221 target_schp->sched_priority = tswap32(schp.sched_priority); |
|
5222 unlock_user_struct(target_schp, arg2, 1); |
|
5223 } |
|
5224 } |
|
5225 break; |
|
5226 case TARGET_NR_sched_setscheduler: |
|
5227 { |
|
5228 struct sched_param *target_schp; |
|
5229 struct sched_param schp; |
|
5230 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) |
|
5231 goto efault; |
|
5232 schp.sched_priority = tswap32(target_schp->sched_priority); |
|
5233 unlock_user_struct(target_schp, arg3, 0); |
|
5234 ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); |
|
5235 } |
|
5236 break; |
|
5237 case TARGET_NR_sched_getscheduler: |
|
5238 ret = get_errno(sched_getscheduler(arg1)); |
|
5239 break; |
|
5240 case TARGET_NR_sched_yield: |
|
5241 ret = get_errno(sched_yield()); |
|
5242 break; |
|
5243 case TARGET_NR_sched_get_priority_max: |
|
5244 ret = get_errno(sched_get_priority_max(arg1)); |
|
5245 break; |
|
5246 case TARGET_NR_sched_get_priority_min: |
|
5247 ret = get_errno(sched_get_priority_min(arg1)); |
|
5248 break; |
|
5249 case TARGET_NR_sched_rr_get_interval: |
|
5250 { |
|
5251 struct timespec ts; |
|
5252 ret = get_errno(sched_rr_get_interval(arg1, &ts)); |
|
5253 if (!is_error(ret)) { |
|
5254 host_to_target_timespec(arg2, &ts); |
|
5255 } |
|
5256 } |
|
5257 break; |
|
5258 case TARGET_NR_nanosleep: |
|
5259 { |
|
5260 struct timespec req, rem; |
|
5261 target_to_host_timespec(&req, arg1); |
|
5262 ret = get_errno(nanosleep(&req, &rem)); |
|
5263 if (is_error(ret) && arg2) { |
|
5264 host_to_target_timespec(arg2, &rem); |
|
5265 } |
|
5266 } |
|
5267 break; |
|
5268 #ifdef TARGET_NR_query_module |
|
5269 case TARGET_NR_query_module: |
|
5270 goto unimplemented; |
|
5271 #endif |
|
5272 #ifdef TARGET_NR_nfsservctl |
|
5273 case TARGET_NR_nfsservctl: |
|
5274 goto unimplemented; |
|
5275 #endif |
|
5276 case TARGET_NR_prctl: |
|
5277 switch (arg1) |
|
5278 { |
|
5279 case PR_GET_PDEATHSIG: |
|
5280 { |
|
5281 int deathsig; |
|
5282 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5)); |
|
5283 if (!is_error(ret) && arg2 |
|
5284 && put_user_ual(deathsig, arg2)) |
|
5285 goto efault; |
|
5286 } |
|
5287 break; |
|
5288 default: |
|
5289 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5)); |
|
5290 break; |
|
5291 } |
|
5292 break; |
|
5293 #ifdef TARGET_NR_arch_prctl |
|
5294 case TARGET_NR_arch_prctl: |
|
5295 #if defined(TARGET_I386) && !defined(TARGET_ABI32) |
|
5296 ret = do_arch_prctl(cpu_env, arg1, arg2); |
|
5297 break; |
|
5298 #else |
|
5299 goto unimplemented; |
|
5300 #endif |
|
5301 #endif |
|
5302 #ifdef TARGET_NR_pread |
|
5303 case TARGET_NR_pread: |
|
5304 #ifdef TARGET_ARM |
|
5305 if (((CPUARMState *)cpu_env)->eabi) |
|
5306 arg4 = arg5; |
|
5307 #endif |
|
5308 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) |
|
5309 goto efault; |
|
5310 ret = get_errno(pread(arg1, p, arg3, arg4)); |
|
5311 unlock_user(p, arg2, ret); |
|
5312 break; |
|
5313 case TARGET_NR_pwrite: |
|
5314 #ifdef TARGET_ARM |
|
5315 if (((CPUARMState *)cpu_env)->eabi) |
|
5316 arg4 = arg5; |
|
5317 #endif |
|
5318 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) |
|
5319 goto efault; |
|
5320 ret = get_errno(pwrite(arg1, p, arg3, arg4)); |
|
5321 unlock_user(p, arg2, 0); |
|
5322 break; |
|
5323 #endif |
|
5324 #ifdef TARGET_NR_pread64 |
|
5325 case TARGET_NR_pread64: |
|
5326 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) |
|
5327 goto efault; |
|
5328 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); |
|
5329 unlock_user(p, arg2, ret); |
|
5330 break; |
|
5331 case TARGET_NR_pwrite64: |
|
5332 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) |
|
5333 goto efault; |
|
5334 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); |
|
5335 unlock_user(p, arg2, 0); |
|
5336 break; |
|
5337 #endif |
|
5338 case TARGET_NR_getcwd: |
|
5339 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) |
|
5340 goto efault; |
|
5341 ret = get_errno(sys_getcwd1(p, arg2)); |
|
5342 unlock_user(p, arg1, ret); |
|
5343 break; |
|
5344 case TARGET_NR_capget: |
|
5345 goto unimplemented; |
|
5346 case TARGET_NR_capset: |
|
5347 goto unimplemented; |
|
5348 case TARGET_NR_sigaltstack: |
|
5349 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ |
|
5350 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) |
|
5351 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); |
|
5352 break; |
|
5353 #else |
|
5354 goto unimplemented; |
|
5355 #endif |
|
5356 case TARGET_NR_sendfile: |
|
5357 goto unimplemented; |
|
5358 #ifdef TARGET_NR_getpmsg |
|
5359 case TARGET_NR_getpmsg: |
|
5360 goto unimplemented; |
|
5361 #endif |
|
5362 #ifdef TARGET_NR_putpmsg |
|
5363 case TARGET_NR_putpmsg: |
|
5364 goto unimplemented; |
|
5365 #endif |
|
5366 #ifdef TARGET_NR_vfork |
|
5367 case TARGET_NR_vfork: |
|
5368 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, |
|
5369 0, 0, 0, 0)); |
|
5370 break; |
|
5371 #endif |
|
5372 #ifdef TARGET_NR_ugetrlimit |
|
5373 case TARGET_NR_ugetrlimit: |
|
5374 { |
|
5375 struct rlimit rlim; |
|
5376 ret = get_errno(getrlimit(arg1, &rlim)); |
|
5377 if (!is_error(ret)) { |
|
5378 struct target_rlimit *target_rlim; |
|
5379 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) |
|
5380 goto efault; |
|
5381 target_rlim->rlim_cur = tswapl(rlim.rlim_cur); |
|
5382 target_rlim->rlim_max = tswapl(rlim.rlim_max); |
|
5383 unlock_user_struct(target_rlim, arg2, 1); |
|
5384 } |
|
5385 break; |
|
5386 } |
|
5387 #endif |
|
5388 #ifdef TARGET_NR_truncate64 |
|
5389 case TARGET_NR_truncate64: |
|
5390 if (!(p = lock_user_string(arg1))) |
|
5391 goto efault; |
|
5392 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); |
|
5393 unlock_user(p, arg1, 0); |
|
5394 break; |
|
5395 #endif |
|
5396 #ifdef TARGET_NR_ftruncate64 |
|
5397 case TARGET_NR_ftruncate64: |
|
5398 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4); |
|
5399 break; |
|
5400 #endif |
|
5401 #ifdef TARGET_NR_stat64 |
|
5402 case TARGET_NR_stat64: |
|
5403 if (!(p = lock_user_string(arg1))) |
|
5404 goto efault; |
|
5405 ret = get_errno(stat(path(p), &st)); |
|
5406 unlock_user(p, arg1, 0); |
|
5407 if (!is_error(ret)) |
|
5408 ret = host_to_target_stat64(cpu_env, arg2, &st); |
|
5409 break; |
|
5410 #endif |
|
5411 #ifdef TARGET_NR_lstat64 |
|
5412 case TARGET_NR_lstat64: |
|
5413 if (!(p = lock_user_string(arg1))) |
|
5414 goto efault; |
|
5415 ret = get_errno(lstat(path(p), &st)); |
|
5416 unlock_user(p, arg1, 0); |
|
5417 if (!is_error(ret)) |
|
5418 ret = host_to_target_stat64(cpu_env, arg2, &st); |
|
5419 break; |
|
5420 #endif |
|
5421 #ifdef TARGET_NR_fstat64 |
|
5422 case TARGET_NR_fstat64: |
|
5423 ret = get_errno(fstat(arg1, &st)); |
|
5424 if (!is_error(ret)) |
|
5425 ret = host_to_target_stat64(cpu_env, arg2, &st); |
|
5426 break; |
|
5427 #endif |
|
5428 #if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64) |
|
5429 case TARGET_NR_fstatat64: |
|
5430 if (!(p = lock_user_string(arg2))) |
|
5431 goto efault; |
|
5432 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4)); |
|
5433 if (!is_error(ret)) |
|
5434 ret = host_to_target_stat64(cpu_env, arg3, &st); |
|
5435 break; |
|
5436 #endif |
|
5437 #ifdef USE_UID16 |
|
5438 case TARGET_NR_lchown: |
|
5439 if (!(p = lock_user_string(arg1))) |
|
5440 goto efault; |
|
5441 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); |
|
5442 unlock_user(p, arg1, 0); |
|
5443 break; |
|
5444 case TARGET_NR_getuid: |
|
5445 ret = get_errno(high2lowuid(getuid())); |
|
5446 break; |
|
5447 case TARGET_NR_getgid: |
|
5448 ret = get_errno(high2lowgid(getgid())); |
|
5449 break; |
|
5450 case TARGET_NR_geteuid: |
|
5451 ret = get_errno(high2lowuid(geteuid())); |
|
5452 break; |
|
5453 case TARGET_NR_getegid: |
|
5454 ret = get_errno(high2lowgid(getegid())); |
|
5455 break; |
|
5456 case TARGET_NR_setreuid: |
|
5457 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); |
|
5458 break; |
|
5459 case TARGET_NR_setregid: |
|
5460 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); |
|
5461 break; |
|
5462 case TARGET_NR_getgroups: |
|
5463 { |
|
5464 int gidsetsize = arg1; |
|
5465 uint16_t *target_grouplist; |
|
5466 gid_t *grouplist; |
|
5467 int i; |
|
5468 |
|
5469 grouplist = alloca(gidsetsize * sizeof(gid_t)); |
|
5470 ret = get_errno(getgroups(gidsetsize, grouplist)); |
|
5471 if (gidsetsize == 0) |
|
5472 break; |
|
5473 if (!is_error(ret)) { |
|
5474 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); |
|
5475 if (!target_grouplist) |
|
5476 goto efault; |
|
5477 for(i = 0;i < ret; i++) |
|
5478 target_grouplist[i] = tswap16(grouplist[i]); |
|
5479 unlock_user(target_grouplist, arg2, gidsetsize * 2); |
|
5480 } |
|
5481 } |
|
5482 break; |
|
5483 case TARGET_NR_setgroups: |
|
5484 { |
|
5485 int gidsetsize = arg1; |
|
5486 uint16_t *target_grouplist; |
|
5487 gid_t *grouplist; |
|
5488 int i; |
|
5489 |
|
5490 grouplist = alloca(gidsetsize * sizeof(gid_t)); |
|
5491 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); |
|
5492 if (!target_grouplist) { |
|
5493 ret = -TARGET_EFAULT; |
|
5494 goto fail; |
|
5495 } |
|
5496 for(i = 0;i < gidsetsize; i++) |
|
5497 grouplist[i] = tswap16(target_grouplist[i]); |
|
5498 unlock_user(target_grouplist, arg2, 0); |
|
5499 ret = get_errno(setgroups(gidsetsize, grouplist)); |
|
5500 } |
|
5501 break; |
|
5502 case TARGET_NR_fchown: |
|
5503 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); |
|
5504 break; |
|
5505 #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) |
|
5506 case TARGET_NR_fchownat: |
|
5507 if (!(p = lock_user_string(arg2))) |
|
5508 goto efault; |
|
5509 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); |
|
5510 unlock_user(p, arg2, 0); |
|
5511 break; |
|
5512 #endif |
|
5513 #ifdef TARGET_NR_setresuid |
|
5514 case TARGET_NR_setresuid: |
|
5515 ret = get_errno(setresuid(low2highuid(arg1), |
|
5516 low2highuid(arg2), |
|
5517 low2highuid(arg3))); |
|
5518 break; |
|
5519 #endif |
|
5520 #ifdef TARGET_NR_getresuid |
|
5521 case TARGET_NR_getresuid: |
|
5522 { |
|
5523 uid_t ruid, euid, suid; |
|
5524 ret = get_errno(getresuid(&ruid, &euid, &suid)); |
|
5525 if (!is_error(ret)) { |
|
5526 if (put_user_u16(high2lowuid(ruid), arg1) |
|
5527 || put_user_u16(high2lowuid(euid), arg2) |
|
5528 || put_user_u16(high2lowuid(suid), arg3)) |
|
5529 goto efault; |
|
5530 } |
|
5531 } |
|
5532 break; |
|
5533 #endif |
|
5534 #ifdef TARGET_NR_getresgid |
|
5535 case TARGET_NR_setresgid: |
|
5536 ret = get_errno(setresgid(low2highgid(arg1), |
|
5537 low2highgid(arg2), |
|
5538 low2highgid(arg3))); |
|
5539 break; |
|
5540 #endif |
|
5541 #ifdef TARGET_NR_getresgid |
|
5542 case TARGET_NR_getresgid: |
|
5543 { |
|
5544 gid_t rgid, egid, sgid; |
|
5545 ret = get_errno(getresgid(&rgid, &egid, &sgid)); |
|
5546 if (!is_error(ret)) { |
|
5547 if (put_user_u16(high2lowgid(rgid), arg1) |
|
5548 || put_user_u16(high2lowgid(egid), arg2) |
|
5549 || put_user_u16(high2lowgid(sgid), arg3)) |
|
5550 goto efault; |
|
5551 } |
|
5552 } |
|
5553 break; |
|
5554 #endif |
|
5555 case TARGET_NR_chown: |
|
5556 if (!(p = lock_user_string(arg1))) |
|
5557 goto efault; |
|
5558 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); |
|
5559 unlock_user(p, arg1, 0); |
|
5560 break; |
|
5561 case TARGET_NR_setuid: |
|
5562 ret = get_errno(setuid(low2highuid(arg1))); |
|
5563 break; |
|
5564 case TARGET_NR_setgid: |
|
5565 ret = get_errno(setgid(low2highgid(arg1))); |
|
5566 break; |
|
5567 case TARGET_NR_setfsuid: |
|
5568 ret = get_errno(setfsuid(arg1)); |
|
5569 break; |
|
5570 case TARGET_NR_setfsgid: |
|
5571 ret = get_errno(setfsgid(arg1)); |
|
5572 break; |
|
5573 #endif /* USE_UID16 */ |
|
5574 |
|
5575 #ifdef TARGET_NR_lchown32 |
|
5576 case TARGET_NR_lchown32: |
|
5577 if (!(p = lock_user_string(arg1))) |
|
5578 goto efault; |
|
5579 ret = get_errno(lchown(p, arg2, arg3)); |
|
5580 unlock_user(p, arg1, 0); |
|
5581 break; |
|
5582 #endif |
|
5583 #ifdef TARGET_NR_getuid32 |
|
5584 case TARGET_NR_getuid32: |
|
5585 ret = get_errno(getuid()); |
|
5586 break; |
|
5587 #endif |
|
5588 |
|
5589 #if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA) |
|
5590 /* Alpha specific */ |
|
5591 case TARGET_NR_getxuid: |
|
5592 { |
|
5593 uid_t euid; |
|
5594 euid=geteuid(); |
|
5595 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid; |
|
5596 } |
|
5597 ret = get_errno(getuid()); |
|
5598 break; |
|
5599 #endif |
|
5600 #if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA) |
|
5601 /* Alpha specific */ |
|
5602 case TARGET_NR_getxgid: |
|
5603 { |
|
5604 uid_t egid; |
|
5605 egid=getegid(); |
|
5606 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid; |
|
5607 } |
|
5608 ret = get_errno(getgid()); |
|
5609 break; |
|
5610 #endif |
|
5611 |
|
5612 #ifdef TARGET_NR_getgid32 |
|
5613 case TARGET_NR_getgid32: |
|
5614 ret = get_errno(getgid()); |
|
5615 break; |
|
5616 #endif |
|
5617 #ifdef TARGET_NR_geteuid32 |
|
5618 case TARGET_NR_geteuid32: |
|
5619 ret = get_errno(geteuid()); |
|
5620 break; |
|
5621 #endif |
|
5622 #ifdef TARGET_NR_getegid32 |
|
5623 case TARGET_NR_getegid32: |
|
5624 ret = get_errno(getegid()); |
|
5625 break; |
|
5626 #endif |
|
5627 #ifdef TARGET_NR_setreuid32 |
|
5628 case TARGET_NR_setreuid32: |
|
5629 ret = get_errno(setreuid(arg1, arg2)); |
|
5630 break; |
|
5631 #endif |
|
5632 #ifdef TARGET_NR_setregid32 |
|
5633 case TARGET_NR_setregid32: |
|
5634 ret = get_errno(setregid(arg1, arg2)); |
|
5635 break; |
|
5636 #endif |
|
5637 #ifdef TARGET_NR_getgroups32 |
|
5638 case TARGET_NR_getgroups32: |
|
5639 { |
|
5640 int gidsetsize = arg1; |
|
5641 uint32_t *target_grouplist; |
|
5642 gid_t *grouplist; |
|
5643 int i; |
|
5644 |
|
5645 grouplist = alloca(gidsetsize * sizeof(gid_t)); |
|
5646 ret = get_errno(getgroups(gidsetsize, grouplist)); |
|
5647 if (gidsetsize == 0) |
|
5648 break; |
|
5649 if (!is_error(ret)) { |
|
5650 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0); |
|
5651 if (!target_grouplist) { |
|
5652 ret = -TARGET_EFAULT; |
|
5653 goto fail; |
|
5654 } |
|
5655 for(i = 0;i < ret; i++) |
|
5656 target_grouplist[i] = tswap32(grouplist[i]); |
|
5657 unlock_user(target_grouplist, arg2, gidsetsize * 4); |
|
5658 } |
|
5659 } |
|
5660 break; |
|
5661 #endif |
|
5662 #ifdef TARGET_NR_setgroups32 |
|
5663 case TARGET_NR_setgroups32: |
|
5664 { |
|
5665 int gidsetsize = arg1; |
|
5666 uint32_t *target_grouplist; |
|
5667 gid_t *grouplist; |
|
5668 int i; |
|
5669 |
|
5670 grouplist = alloca(gidsetsize * sizeof(gid_t)); |
|
5671 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1); |
|
5672 if (!target_grouplist) { |
|
5673 ret = -TARGET_EFAULT; |
|
5674 goto fail; |
|
5675 } |
|
5676 for(i = 0;i < gidsetsize; i++) |
|
5677 grouplist[i] = tswap32(target_grouplist[i]); |
|
5678 unlock_user(target_grouplist, arg2, 0); |
|
5679 ret = get_errno(setgroups(gidsetsize, grouplist)); |
|
5680 } |
|
5681 break; |
|
5682 #endif |
|
5683 #ifdef TARGET_NR_fchown32 |
|
5684 case TARGET_NR_fchown32: |
|
5685 ret = get_errno(fchown(arg1, arg2, arg3)); |
|
5686 break; |
|
5687 #endif |
|
5688 #ifdef TARGET_NR_setresuid32 |
|
5689 case TARGET_NR_setresuid32: |
|
5690 ret = get_errno(setresuid(arg1, arg2, arg3)); |
|
5691 break; |
|
5692 #endif |
|
5693 #ifdef TARGET_NR_getresuid32 |
|
5694 case TARGET_NR_getresuid32: |
|
5695 { |
|
5696 uid_t ruid, euid, suid; |
|
5697 ret = get_errno(getresuid(&ruid, &euid, &suid)); |
|
5698 if (!is_error(ret)) { |
|
5699 if (put_user_u32(ruid, arg1) |
|
5700 || put_user_u32(euid, arg2) |
|
5701 || put_user_u32(suid, arg3)) |
|
5702 goto efault; |
|
5703 } |
|
5704 } |
|
5705 break; |
|
5706 #endif |
|
5707 #ifdef TARGET_NR_setresgid32 |
|
5708 case TARGET_NR_setresgid32: |
|
5709 ret = get_errno(setresgid(arg1, arg2, arg3)); |
|
5710 break; |
|
5711 #endif |
|
5712 #ifdef TARGET_NR_getresgid32 |
|
5713 case TARGET_NR_getresgid32: |
|
5714 { |
|
5715 gid_t rgid, egid, sgid; |
|
5716 ret = get_errno(getresgid(&rgid, &egid, &sgid)); |
|
5717 if (!is_error(ret)) { |
|
5718 if (put_user_u32(rgid, arg1) |
|
5719 || put_user_u32(egid, arg2) |
|
5720 || put_user_u32(sgid, arg3)) |
|
5721 goto efault; |
|
5722 } |
|
5723 } |
|
5724 break; |
|
5725 #endif |
|
5726 #ifdef TARGET_NR_chown32 |
|
5727 case TARGET_NR_chown32: |
|
5728 if (!(p = lock_user_string(arg1))) |
|
5729 goto efault; |
|
5730 ret = get_errno(chown(p, arg2, arg3)); |
|
5731 unlock_user(p, arg1, 0); |
|
5732 break; |
|
5733 #endif |
|
5734 #ifdef TARGET_NR_setuid32 |
|
5735 case TARGET_NR_setuid32: |
|
5736 ret = get_errno(setuid(arg1)); |
|
5737 break; |
|
5738 #endif |
|
5739 #ifdef TARGET_NR_setgid32 |
|
5740 case TARGET_NR_setgid32: |
|
5741 ret = get_errno(setgid(arg1)); |
|
5742 break; |
|
5743 #endif |
|
5744 #ifdef TARGET_NR_setfsuid32 |
|
5745 case TARGET_NR_setfsuid32: |
|
5746 ret = get_errno(setfsuid(arg1)); |
|
5747 break; |
|
5748 #endif |
|
5749 #ifdef TARGET_NR_setfsgid32 |
|
5750 case TARGET_NR_setfsgid32: |
|
5751 ret = get_errno(setfsgid(arg1)); |
|
5752 break; |
|
5753 #endif |
|
5754 |
|
5755 case TARGET_NR_pivot_root: |
|
5756 goto unimplemented; |
|
5757 #ifdef TARGET_NR_mincore |
|
5758 case TARGET_NR_mincore: |
|
5759 { |
|
5760 void *a; |
|
5761 ret = -TARGET_EFAULT; |
|
5762 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0))) |
|
5763 goto efault; |
|
5764 if (!(p = lock_user_string(arg3))) |
|
5765 goto mincore_fail; |
|
5766 ret = get_errno(mincore(a, arg2, p)); |
|
5767 unlock_user(p, arg3, ret); |
|
5768 mincore_fail: |
|
5769 unlock_user(a, arg1, 0); |
|
5770 } |
|
5771 break; |
|
5772 #endif |
|
5773 #ifdef TARGET_NR_arm_fadvise64_64 |
|
5774 case TARGET_NR_arm_fadvise64_64: |
|
5775 { |
|
5776 /* |
|
5777 * arm_fadvise64_64 looks like fadvise64_64 but |
|
5778 * with different argument order |
|
5779 */ |
|
5780 abi_long temp; |
|
5781 temp = arg3; |
|
5782 arg3 = arg4; |
|
5783 arg4 = temp; |
|
5784 } |
|
5785 #endif |
|
5786 #if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) |
|
5787 #ifdef TARGET_NR_fadvise64_64 |
|
5788 case TARGET_NR_fadvise64_64: |
|
5789 #endif |
|
5790 /* This is a hint, so ignoring and returning success is ok. */ |
|
5791 ret = get_errno(0); |
|
5792 break; |
|
5793 #endif |
|
5794 #ifdef TARGET_NR_madvise |
|
5795 case TARGET_NR_madvise: |
|
5796 /* A straight passthrough may not be safe because qemu sometimes |
|
5797 turns private flie-backed mappings into anonymous mappings. |
|
5798 This will break MADV_DONTNEED. |
|
5799 This is a hint, so ignoring and returning success is ok. */ |
|
5800 ret = get_errno(0); |
|
5801 break; |
|
5802 #endif |
|
5803 #if TARGET_ABI_BITS == 32 |
|
5804 case TARGET_NR_fcntl64: |
|
5805 { |
|
5806 int cmd; |
|
5807 struct flock64 fl; |
|
5808 struct target_flock64 *target_fl; |
|
5809 #ifdef TARGET_ARM |
|
5810 struct target_eabi_flock64 *target_efl; |
|
5811 #endif |
|
5812 |
|
5813 switch(arg2){ |
|
5814 case TARGET_F_GETLK64: |
|
5815 cmd = F_GETLK64; |
|
5816 break; |
|
5817 case TARGET_F_SETLK64: |
|
5818 cmd = F_SETLK64; |
|
5819 break; |
|
5820 case TARGET_F_SETLKW64: |
|
5821 cmd = F_SETLK64; |
|
5822 break; |
|
5823 default: |
|
5824 cmd = arg2; |
|
5825 break; |
|
5826 } |
|
5827 |
|
5828 switch(arg2) { |
|
5829 case TARGET_F_GETLK64: |
|
5830 #ifdef TARGET_ARM |
|
5831 if (((CPUARMState *)cpu_env)->eabi) { |
|
5832 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) |
|
5833 goto efault; |
|
5834 fl.l_type = tswap16(target_efl->l_type); |
|
5835 fl.l_whence = tswap16(target_efl->l_whence); |
|
5836 fl.l_start = tswap64(target_efl->l_start); |
|
5837 fl.l_len = tswap64(target_efl->l_len); |
|
5838 fl.l_pid = tswapl(target_efl->l_pid); |
|
5839 unlock_user_struct(target_efl, arg3, 0); |
|
5840 } else |
|
5841 #endif |
|
5842 { |
|
5843 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) |
|
5844 goto efault; |
|
5845 fl.l_type = tswap16(target_fl->l_type); |
|
5846 fl.l_whence = tswap16(target_fl->l_whence); |
|
5847 fl.l_start = tswap64(target_fl->l_start); |
|
5848 fl.l_len = tswap64(target_fl->l_len); |
|
5849 fl.l_pid = tswapl(target_fl->l_pid); |
|
5850 unlock_user_struct(target_fl, arg3, 0); |
|
5851 } |
|
5852 ret = get_errno(fcntl(arg1, cmd, &fl)); |
|
5853 if (ret == 0) { |
|
5854 #ifdef TARGET_ARM |
|
5855 if (((CPUARMState *)cpu_env)->eabi) { |
|
5856 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) |
|
5857 goto efault; |
|
5858 target_efl->l_type = tswap16(fl.l_type); |
|
5859 target_efl->l_whence = tswap16(fl.l_whence); |
|
5860 target_efl->l_start = tswap64(fl.l_start); |
|
5861 target_efl->l_len = tswap64(fl.l_len); |
|
5862 target_efl->l_pid = tswapl(fl.l_pid); |
|
5863 unlock_user_struct(target_efl, arg3, 1); |
|
5864 } else |
|
5865 #endif |
|
5866 { |
|
5867 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) |
|
5868 goto efault; |
|
5869 target_fl->l_type = tswap16(fl.l_type); |
|
5870 target_fl->l_whence = tswap16(fl.l_whence); |
|
5871 target_fl->l_start = tswap64(fl.l_start); |
|
5872 target_fl->l_len = tswap64(fl.l_len); |
|
5873 target_fl->l_pid = tswapl(fl.l_pid); |
|
5874 unlock_user_struct(target_fl, arg3, 1); |
|
5875 } |
|
5876 } |
|
5877 break; |
|
5878 |
|
5879 case TARGET_F_SETLK64: |
|
5880 case TARGET_F_SETLKW64: |
|
5881 #ifdef TARGET_ARM |
|
5882 if (((CPUARMState *)cpu_env)->eabi) { |
|
5883 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) |
|
5884 goto efault; |
|
5885 fl.l_type = tswap16(target_efl->l_type); |
|
5886 fl.l_whence = tswap16(target_efl->l_whence); |
|
5887 fl.l_start = tswap64(target_efl->l_start); |
|
5888 fl.l_len = tswap64(target_efl->l_len); |
|
5889 fl.l_pid = tswapl(target_efl->l_pid); |
|
5890 unlock_user_struct(target_efl, arg3, 0); |
|
5891 } else |
|
5892 #endif |
|
5893 { |
|
5894 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) |
|
5895 goto efault; |
|
5896 fl.l_type = tswap16(target_fl->l_type); |
|
5897 fl.l_whence = tswap16(target_fl->l_whence); |
|
5898 fl.l_start = tswap64(target_fl->l_start); |
|
5899 fl.l_len = tswap64(target_fl->l_len); |
|
5900 fl.l_pid = tswapl(target_fl->l_pid); |
|
5901 unlock_user_struct(target_fl, arg3, 0); |
|
5902 } |
|
5903 ret = get_errno(fcntl(arg1, cmd, &fl)); |
|
5904 break; |
|
5905 default: |
|
5906 ret = do_fcntl(arg1, cmd, arg3); |
|
5907 break; |
|
5908 } |
|
5909 break; |
|
5910 } |
|
5911 #endif |
|
5912 #ifdef TARGET_NR_cacheflush |
|
5913 case TARGET_NR_cacheflush: |
|
5914 /* self-modifying code is handled automatically, so nothing needed */ |
|
5915 ret = 0; |
|
5916 break; |
|
5917 #endif |
|
5918 #ifdef TARGET_NR_security |
|
5919 case TARGET_NR_security: |
|
5920 goto unimplemented; |
|
5921 #endif |
|
5922 #ifdef TARGET_NR_getpagesize |
|
5923 case TARGET_NR_getpagesize: |
|
5924 ret = TARGET_PAGE_SIZE; |
|
5925 break; |
|
5926 #endif |
|
5927 case TARGET_NR_gettid: |
|
5928 ret = get_errno(gettid()); |
|
5929 break; |
|
5930 #ifdef TARGET_NR_readahead |
|
5931 case TARGET_NR_readahead: |
|
5932 #if TARGET_ABI_BITS == 32 |
|
5933 #ifdef TARGET_ARM |
|
5934 if (((CPUARMState *)cpu_env)->eabi) |
|
5935 { |
|
5936 arg2 = arg3; |
|
5937 arg3 = arg4; |
|
5938 arg4 = arg5; |
|
5939 } |
|
5940 #endif |
|
5941 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4)); |
|
5942 #else |
|
5943 ret = get_errno(readahead(arg1, arg2, arg3)); |
|
5944 #endif |
|
5945 break; |
|
5946 #endif |
|
5947 #ifdef TARGET_NR_setxattr |
|
5948 case TARGET_NR_setxattr: |
|
5949 case TARGET_NR_lsetxattr: |
|
5950 case TARGET_NR_fsetxattr: |
|
5951 case TARGET_NR_getxattr: |
|
5952 case TARGET_NR_lgetxattr: |
|
5953 case TARGET_NR_fgetxattr: |
|
5954 case TARGET_NR_listxattr: |
|
5955 case TARGET_NR_llistxattr: |
|
5956 case TARGET_NR_flistxattr: |
|
5957 case TARGET_NR_removexattr: |
|
5958 case TARGET_NR_lremovexattr: |
|
5959 case TARGET_NR_fremovexattr: |
|
5960 goto unimplemented_nowarn; |
|
5961 #endif |
|
5962 #ifdef TARGET_NR_set_thread_area |
|
5963 case TARGET_NR_set_thread_area: |
|
5964 #if defined(TARGET_MIPS) |
|
5965 ((CPUMIPSState *) cpu_env)->tls_value = arg1; |
|
5966 ret = 0; |
|
5967 break; |
|
5968 #elif defined(TARGET_I386) && defined(TARGET_ABI32) |
|
5969 ret = do_set_thread_area(cpu_env, arg1); |
|
5970 break; |
|
5971 #else |
|
5972 goto unimplemented_nowarn; |
|
5973 #endif |
|
5974 #endif |
|
5975 #ifdef TARGET_NR_get_thread_area |
|
5976 case TARGET_NR_get_thread_area: |
|
5977 #if defined(TARGET_I386) && defined(TARGET_ABI32) |
|
5978 ret = do_get_thread_area(cpu_env, arg1); |
|
5979 #else |
|
5980 goto unimplemented_nowarn; |
|
5981 #endif |
|
5982 #endif |
|
5983 #ifdef TARGET_NR_getdomainname |
|
5984 case TARGET_NR_getdomainname: |
|
5985 goto unimplemented_nowarn; |
|
5986 #endif |
|
5987 |
|
5988 #ifdef TARGET_NR_clock_gettime |
|
5989 case TARGET_NR_clock_gettime: |
|
5990 { |
|
5991 struct timespec ts; |
|
5992 ret = get_errno(clock_gettime(arg1, &ts)); |
|
5993 if (!is_error(ret)) { |
|
5994 host_to_target_timespec(arg2, &ts); |
|
5995 } |
|
5996 break; |
|
5997 } |
|
5998 #endif |
|
5999 #ifdef TARGET_NR_clock_getres |
|
6000 case TARGET_NR_clock_getres: |
|
6001 { |
|
6002 struct timespec ts; |
|
6003 ret = get_errno(clock_getres(arg1, &ts)); |
|
6004 if (!is_error(ret)) { |
|
6005 host_to_target_timespec(arg2, &ts); |
|
6006 } |
|
6007 break; |
|
6008 } |
|
6009 #endif |
|
6010 #ifdef TARGET_NR_clock_nanosleep |
|
6011 case TARGET_NR_clock_nanosleep: |
|
6012 { |
|
6013 struct timespec ts; |
|
6014 target_to_host_timespec(&ts, arg3); |
|
6015 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL)); |
|
6016 if (arg4) |
|
6017 host_to_target_timespec(arg4, &ts); |
|
6018 break; |
|
6019 } |
|
6020 #endif |
|
6021 |
|
6022 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) |
|
6023 case TARGET_NR_set_tid_address: |
|
6024 ret = get_errno(set_tid_address((int *)g2h(arg1))); |
|
6025 break; |
|
6026 #endif |
|
6027 |
|
6028 #if defined(TARGET_NR_tkill) && defined(__NR_tkill) |
|
6029 case TARGET_NR_tkill: |
|
6030 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2))); |
|
6031 break; |
|
6032 #endif |
|
6033 |
|
6034 #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) |
|
6035 case TARGET_NR_tgkill: |
|
6036 ret = get_errno(sys_tgkill((int)arg1, (int)arg2, |
|
6037 target_to_host_signal(arg3))); |
|
6038 break; |
|
6039 #endif |
|
6040 |
|
6041 #ifdef TARGET_NR_set_robust_list |
|
6042 case TARGET_NR_set_robust_list: |
|
6043 goto unimplemented_nowarn; |
|
6044 #endif |
|
6045 |
|
6046 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) |
|
6047 case TARGET_NR_utimensat: |
|
6048 { |
|
6049 struct timespec ts[2]; |
|
6050 target_to_host_timespec(ts, arg3); |
|
6051 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec)); |
|
6052 if (!arg2) |
|
6053 ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); |
|
6054 else { |
|
6055 if (!(p = lock_user_string(arg2))) { |
|
6056 ret = -TARGET_EFAULT; |
|
6057 goto fail; |
|
6058 } |
|
6059 ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); |
|
6060 unlock_user(p, arg2, 0); |
|
6061 } |
|
6062 } |
|
6063 break; |
|
6064 #endif |
|
6065 #if defined(USE_NPTL) |
|
6066 case TARGET_NR_futex: |
|
6067 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6); |
|
6068 break; |
|
6069 #endif |
|
6070 #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init) |
|
6071 case TARGET_NR_inotify_init: |
|
6072 ret = get_errno(sys_inotify_init()); |
|
6073 break; |
|
6074 #endif |
|
6075 #if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch) |
|
6076 case TARGET_NR_inotify_add_watch: |
|
6077 p = lock_user_string(arg2); |
|
6078 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3)); |
|
6079 unlock_user(p, arg2, 0); |
|
6080 break; |
|
6081 #endif |
|
6082 #if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch) |
|
6083 case TARGET_NR_inotify_rm_watch: |
|
6084 ret = get_errno(sys_inotify_rm_watch(arg1, arg2)); |
|
6085 break; |
|
6086 #endif |
|
6087 |
|
6088 default: |
|
6089 unimplemented: |
|
6090 if (show_missing_syscalls) |
|
6091 gemu_log("qemu: Unsupported syscall: %d\n", num); |
|
6092 #if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list) |
|
6093 unimplemented_nowarn: |
|
6094 #endif |
|
6095 ret = -TARGET_ENOSYS; |
|
6096 break; |
|
6097 } |
|
6098 fail: |
|
6099 #ifdef DEBUG |
|
6100 gemu_log(" = %ld\n", ret); |
|
6101 #endif |
|
6102 if(do_strace) |
|
6103 print_syscall_ret(num, ret); |
|
6104 return ret; |
|
6105 efault: |
|
6106 ret = -TARGET_EFAULT; |
|
6107 goto fail; |
|
6108 } |