blob: b9757306acb063349dc2840727578a455f22f947 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * 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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
bellard31e31b82003-02-18 22:55:36 +000031#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000032#include <sys/ipc.h>
33#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/wait.h>
35#include <sys/time.h>
36#include <sys/stat.h>
37#include <sys/mount.h>
ths39b9aae2007-02-11 18:36:44 +000038#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/resource.h>
40#include <sys/mman.h>
41#include <sys/swap.h>
42#include <signal.h>
43#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020044#ifdef __ia64__
45int __clone2(int (*fn)(void *), void *child_stack_base,
46 size_t stack_size, int flags, void *arg, ...);
47#endif
bellard31e31b82003-02-18 22:55:36 +000048#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000049#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000050#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000051#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000052#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000053#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000054#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000055#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000056#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000057#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000058#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000059//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000060#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000061#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020062#include <linux/wireless.h>
aurel320b6d3ae2008-09-15 07:43:43 +000063#include <qemu-common.h>
Juan Quintela9788c9c2009-07-27 16:13:02 +020064#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000065#include <sys/gmon.h>
66#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030067#ifdef CONFIG_EVENTFD
68#include <sys/eventfd.h>
69#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000070#ifdef CONFIG_EPOLL
71#include <sys/epoll.h>
72#endif
bellard31e31b82003-02-18 22:55:36 +000073
74#define termios host_termios
75#define winsize host_winsize
76#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000077#define sgttyb host_sgttyb /* same as target */
78#define tchars host_tchars /* same as target */
79#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000080
81#include <linux/termios.h>
82#include <linux/unistd.h>
83#include <linux/utsname.h>
84#include <linux/cdrom.h>
85#include <linux/hdreg.h>
86#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000087#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000088#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030089#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000090#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000091#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000092#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020093#include <linux/fb.h>
94#include <linux/vt.h>
pbrookd7e40362008-05-23 16:06:43 +000095#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +010096#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +000097
bellard3ef693a2003-03-23 20:17:16 +000098#include "qemu.h"
balrog526ccb72008-07-16 12:13:52 +000099#include "qemu-common.h"
bellard31e31b82003-02-18 22:55:36 +0000100
Juan Quintela2f7bb872009-07-27 16:13:24 +0200101#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000102#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
103 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
104#else
105/* XXX: Hardcode the above values. */
106#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000107#endif
108
bellard72f03902003-02-18 23:33:18 +0000109//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000110
bellard1a9353d2003-03-16 20:28:50 +0000111//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000112#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
113#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000114
bellard70a194b2003-08-11 22:20:16 +0000115
bellard70a194b2003-08-11 22:20:16 +0000116#undef _syscall0
117#undef _syscall1
118#undef _syscall2
119#undef _syscall3
120#undef _syscall4
121#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000122#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000123
bellard83fcb512006-06-14 13:37:16 +0000124#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000125static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000126{ \
127 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000128}
129
bellard83fcb512006-06-14 13:37:16 +0000130#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000131static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000132{ \
133 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000134}
135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
155 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000156static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000157{ \
158 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000159}
bellard83fcb512006-06-14 13:37:16 +0000160
161
162#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
163 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000164static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
165 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
168}
169
bellard70a194b2003-08-11 22:20:16 +0000170
bellard31e31b82003-02-18 22:55:36 +0000171#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000172#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000173#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000174#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000175#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000176#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000177#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000178#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000179#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000180#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000181#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000182#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000183#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000184#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000185#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000186#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000187#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000189#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000190#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000191#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000192#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000193#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000194#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000195#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000196#define __NR_sys_inotify_init __NR_inotify_init
197#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
198#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000199
Alexander Graf42a39fb2011-04-15 17:32:45 +0200200#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
201 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000202#define __NR__llseek __NR_lseek
203#endif
204
bellard72f03902003-02-18 23:33:18 +0000205#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000206_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000207#else
ths0da46a62007-10-20 20:23:07 +0000208/* This is a replacement for the host gettid() and must return a host
209 errno. */
bellard72f03902003-02-18 23:33:18 +0000210static int gettid(void) {
211 return -ENOSYS;
212}
213#endif
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000215#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
216_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
217#endif
218_syscall2(int, sys_getpriority, int, which, int, who);
Richard Hendersond35b2612010-06-04 12:14:10 -0700219#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000220_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
221 loff_t *, res, uint, wh);
222#endif
223_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
224_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
225#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
226_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
227#endif
228#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
229_syscall2(int,sys_tkill,int,tid,int,sig)
230#endif
231#ifdef __NR_exit_group
232_syscall1(int,exit_group,int,error_code)
233#endif
234#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
235_syscall1(int,set_tid_address,int *,tidptr)
236#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200237#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000238#if defined(TARGET_NR_futex) && defined(__NR_futex)
239_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
240 const struct timespec *,timeout,int *,uaddr2,int,val3)
241#endif
242#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500243#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
244_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
245 unsigned long *, user_mask_ptr);
246#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
247_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
248 unsigned long *, user_mask_ptr);
aurel323b3f24a2009-04-15 16:12:13 +0000249
250static bitmask_transtbl fcntl_flags_tbl[] = {
251 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
252 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
253 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
254 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
255 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
256 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
257 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
258 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
259 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
260 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
261 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
262 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
263 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
264#if defined(O_DIRECT)
265 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
266#endif
267 { 0, 0, 0, 0 }
268};
269
270#define COPY_UTSNAME_FIELD(dest, src) \
271 do { \
272 /* __NEW_UTS_LEN doesn't include terminating null */ \
273 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
274 (dest)[__NEW_UTS_LEN] = '\0'; \
275 } while (0)
276
277static int sys_uname(struct new_utsname *buf)
278{
279 struct utsname uts_buf;
280
281 if (uname(&uts_buf) < 0)
282 return (-1);
283
284 /*
285 * Just in case these have some differences, we
286 * translate utsname to new_utsname (which is the
287 * struct linux kernel uses).
288 */
289
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200290 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000291 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
292 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
293 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
294 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
295 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
296#ifdef _GNU_SOURCE
297 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
298#endif
299 return (0);
300
301#undef COPY_UTSNAME_FIELD
302}
303
304static int sys_getcwd1(char *buf, size_t size)
305{
306 if (getcwd(buf, size) == NULL) {
307 /* getcwd() sets errno */
308 return (-1);
309 }
aurel32aaf4ad32009-04-16 14:17:14 +0000310 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000311}
312
313#ifdef CONFIG_ATFILE
314/*
315 * Host system seems to have atfile syscall stubs available. We
316 * now enable them one by one as specified by target syscall_nr.h.
317 */
318
319#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000320static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000321{
aurel32465c9f02009-04-19 08:52:17 +0000322 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000323}
324#endif
325#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000326static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000327{
aurel32465c9f02009-04-19 08:52:17 +0000328 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000329}
330#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300331#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000332static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
333 gid_t group, int flags)
334{
335 return (fchownat(dirfd, pathname, owner, group, flags));
336}
337#endif
338#ifdef __NR_fstatat64
339static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
340 int flags)
341{
342 return (fstatat(dirfd, pathname, buf, flags));
343}
344#endif
345#ifdef __NR_newfstatat
346static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
347 int flags)
348{
349 return (fstatat(dirfd, pathname, buf, flags));
350}
351#endif
352#ifdef TARGET_NR_futimesat
353static int sys_futimesat(int dirfd, const char *pathname,
354 const struct timeval times[2])
355{
356 return (futimesat(dirfd, pathname, times));
357}
358#endif
359#ifdef TARGET_NR_linkat
360static int sys_linkat(int olddirfd, const char *oldpath,
361 int newdirfd, const char *newpath, int flags)
362{
363 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
364}
365#endif
366#ifdef TARGET_NR_mkdirat
367static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
368{
369 return (mkdirat(dirfd, pathname, mode));
370}
371#endif
372#ifdef TARGET_NR_mknodat
373static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
374 dev_t dev)
375{
376 return (mknodat(dirfd, pathname, mode, dev));
377}
378#endif
379#ifdef TARGET_NR_openat
380static int sys_openat(int dirfd, const char *pathname, int flags, ...)
381{
382 /*
383 * open(2) has extra parameter 'mode' when called with
384 * flag O_CREAT.
385 */
386 if ((flags & O_CREAT) != 0) {
387 va_list ap;
388 mode_t mode;
389
390 /*
391 * Get the 'mode' parameter and translate it to
392 * host bits.
393 */
394 va_start(ap, flags);
395 mode = va_arg(ap, mode_t);
396 mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
397 va_end(ap);
398
399 return (openat(dirfd, pathname, flags, mode));
400 }
401 return (openat(dirfd, pathname, flags));
402}
403#endif
404#ifdef TARGET_NR_readlinkat
405static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
406{
407 return (readlinkat(dirfd, pathname, buf, bufsiz));
408}
409#endif
410#ifdef TARGET_NR_renameat
411static int sys_renameat(int olddirfd, const char *oldpath,
412 int newdirfd, const char *newpath)
413{
414 return (renameat(olddirfd, oldpath, newdirfd, newpath));
415}
416#endif
417#ifdef TARGET_NR_symlinkat
418static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
419{
420 return (symlinkat(oldpath, newdirfd, newpath));
421}
422#endif
423#ifdef TARGET_NR_unlinkat
424static int sys_unlinkat(int dirfd, const char *pathname, int flags)
425{
426 return (unlinkat(dirfd, pathname, flags));
427}
428#endif
aurel323b3f24a2009-04-15 16:12:13 +0000429#else /* !CONFIG_ATFILE */
430
431/*
432 * Try direct syscalls instead
433 */
ths92a34c12007-09-24 09:27:49 +0000434#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000435_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000436#endif
ths814d7972007-09-24 09:26:51 +0000437#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000438_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000439#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300440#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000441_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
442 uid_t,owner,gid_t,group,int,flags)
443#endif
aurel329d33b762009-04-08 23:07:05 +0000444#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
445 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000446_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
447 struct stat *,buf,int,flags)
448#endif
balrogac8a6552008-09-20 02:25:39 +0000449#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
450_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
451 const struct timeval *,times)
452#endif
aurel323b3f24a2009-04-15 16:12:13 +0000453#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
454 defined(__NR_newfstatat)
455_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
456 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000457#endif
ths64f0ce42007-09-24 09:25:06 +0000458#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
459_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000460 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000461#endif
ths4472ad02007-09-24 09:22:32 +0000462#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
463_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
464#endif
ths75ac37a2007-09-24 09:23:05 +0000465#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
466_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
467 mode_t,mode,dev_t,dev)
468#endif
ths82424832007-09-24 09:21:55 +0000469#if defined(TARGET_NR_openat) && defined(__NR_openat)
470_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
471#endif
ths5e0ccb12007-09-24 09:26:10 +0000472#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
473_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
474 char *,buf,size_t,bufsize)
475#endif
ths722183f2007-09-24 09:24:37 +0000476#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
477_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
478 int,newdirfd,const char *,newpath)
479#endif
thsb51eaa82007-09-25 16:09:22 +0000480#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000481_syscall3(int,sys_symlinkat,const char *,oldpath,
482 int,newdirfd,const char *,newpath)
483#endif
ths8170f562007-09-24 09:24:11 +0000484#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
485_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
486#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300487
488#endif /* CONFIG_ATFILE */
489
490#ifdef CONFIG_UTIMENSAT
491static int sys_utimensat(int dirfd, const char *pathname,
492 const struct timespec times[2], int flags)
493{
494 if (pathname == NULL)
495 return futimens(dirfd, times);
496 else
497 return utimensat(dirfd, pathname, times, flags);
498}
499#else
ths9007f0e2007-09-25 17:50:37 +0000500#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
501_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
502 const struct timespec *,tsp,int,flags)
503#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300504#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000505
506#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000507#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000508
aurel3239b59762008-10-01 21:46:50 +0000509#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000510static int sys_inotify_init(void)
511{
512 return (inotify_init());
513}
aurel3239b59762008-10-01 21:46:50 +0000514#endif
515#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000516static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
517{
518 return (inotify_add_watch(fd, pathname, mask));
519}
aurel3239b59762008-10-01 21:46:50 +0000520#endif
521#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000522static int sys_inotify_rm_watch(int fd, int32_t wd)
523{
aurel328690e422009-04-17 13:50:32 +0000524 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000525}
aurel3239b59762008-10-01 21:46:50 +0000526#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000527#ifdef CONFIG_INOTIFY1
528#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
529static int sys_inotify_init1(int flags)
530{
531 return (inotify_init1(flags));
532}
533#endif
534#endif
aurel323b3f24a2009-04-15 16:12:13 +0000535#else
536/* Userspace can usually survive runtime without inotify */
537#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000538#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000539#undef TARGET_NR_inotify_add_watch
540#undef TARGET_NR_inotify_rm_watch
541#endif /* CONFIG_INOTIFY */
542
Mike Frysingerd8035d42011-02-07 01:05:51 -0500543#if defined(TARGET_NR_ppoll)
544#ifndef __NR_ppoll
545# define __NR_ppoll -1
546#endif
547#define __NR_sys_ppoll __NR_ppoll
548_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
549 struct timespec *, timeout, const __sigset_t *, sigmask,
550 size_t, sigsetsize)
551#endif
bellard66fb9762003-03-23 01:06:05 +0000552
553extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000554extern int flock(int, int);
555extern int setfsuid(int);
556extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000557extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000558
thsb92c47c2007-11-01 00:07:38 +0000559#define ERRNO_TABLE_SIZE 1200
560
561/* target_to_host_errno_table[] is initialized from
562 * host_to_target_errno_table[] in syscall_init(). */
563static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
564};
565
ths637947f2007-06-01 12:09:19 +0000566/*
thsfe8f0962007-07-12 10:59:21 +0000567 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000568 * minus the errnos that are not actually generic to all archs.
569 */
thsb92c47c2007-11-01 00:07:38 +0000570static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000571 [EIDRM] = TARGET_EIDRM,
572 [ECHRNG] = TARGET_ECHRNG,
573 [EL2NSYNC] = TARGET_EL2NSYNC,
574 [EL3HLT] = TARGET_EL3HLT,
575 [EL3RST] = TARGET_EL3RST,
576 [ELNRNG] = TARGET_ELNRNG,
577 [EUNATCH] = TARGET_EUNATCH,
578 [ENOCSI] = TARGET_ENOCSI,
579 [EL2HLT] = TARGET_EL2HLT,
580 [EDEADLK] = TARGET_EDEADLK,
581 [ENOLCK] = TARGET_ENOLCK,
582 [EBADE] = TARGET_EBADE,
583 [EBADR] = TARGET_EBADR,
584 [EXFULL] = TARGET_EXFULL,
585 [ENOANO] = TARGET_ENOANO,
586 [EBADRQC] = TARGET_EBADRQC,
587 [EBADSLT] = TARGET_EBADSLT,
588 [EBFONT] = TARGET_EBFONT,
589 [ENOSTR] = TARGET_ENOSTR,
590 [ENODATA] = TARGET_ENODATA,
591 [ETIME] = TARGET_ETIME,
592 [ENOSR] = TARGET_ENOSR,
593 [ENONET] = TARGET_ENONET,
594 [ENOPKG] = TARGET_ENOPKG,
595 [EREMOTE] = TARGET_EREMOTE,
596 [ENOLINK] = TARGET_ENOLINK,
597 [EADV] = TARGET_EADV,
598 [ESRMNT] = TARGET_ESRMNT,
599 [ECOMM] = TARGET_ECOMM,
600 [EPROTO] = TARGET_EPROTO,
601 [EDOTDOT] = TARGET_EDOTDOT,
602 [EMULTIHOP] = TARGET_EMULTIHOP,
603 [EBADMSG] = TARGET_EBADMSG,
604 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
605 [EOVERFLOW] = TARGET_EOVERFLOW,
606 [ENOTUNIQ] = TARGET_ENOTUNIQ,
607 [EBADFD] = TARGET_EBADFD,
608 [EREMCHG] = TARGET_EREMCHG,
609 [ELIBACC] = TARGET_ELIBACC,
610 [ELIBBAD] = TARGET_ELIBBAD,
611 [ELIBSCN] = TARGET_ELIBSCN,
612 [ELIBMAX] = TARGET_ELIBMAX,
613 [ELIBEXEC] = TARGET_ELIBEXEC,
614 [EILSEQ] = TARGET_EILSEQ,
615 [ENOSYS] = TARGET_ENOSYS,
616 [ELOOP] = TARGET_ELOOP,
617 [ERESTART] = TARGET_ERESTART,
618 [ESTRPIPE] = TARGET_ESTRPIPE,
619 [ENOTEMPTY] = TARGET_ENOTEMPTY,
620 [EUSERS] = TARGET_EUSERS,
621 [ENOTSOCK] = TARGET_ENOTSOCK,
622 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
623 [EMSGSIZE] = TARGET_EMSGSIZE,
624 [EPROTOTYPE] = TARGET_EPROTOTYPE,
625 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
626 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
627 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
628 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
629 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
630 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
631 [EADDRINUSE] = TARGET_EADDRINUSE,
632 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
633 [ENETDOWN] = TARGET_ENETDOWN,
634 [ENETUNREACH] = TARGET_ENETUNREACH,
635 [ENETRESET] = TARGET_ENETRESET,
636 [ECONNABORTED] = TARGET_ECONNABORTED,
637 [ECONNRESET] = TARGET_ECONNRESET,
638 [ENOBUFS] = TARGET_ENOBUFS,
639 [EISCONN] = TARGET_EISCONN,
640 [ENOTCONN] = TARGET_ENOTCONN,
641 [EUCLEAN] = TARGET_EUCLEAN,
642 [ENOTNAM] = TARGET_ENOTNAM,
643 [ENAVAIL] = TARGET_ENAVAIL,
644 [EISNAM] = TARGET_EISNAM,
645 [EREMOTEIO] = TARGET_EREMOTEIO,
646 [ESHUTDOWN] = TARGET_ESHUTDOWN,
647 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
648 [ETIMEDOUT] = TARGET_ETIMEDOUT,
649 [ECONNREFUSED] = TARGET_ECONNREFUSED,
650 [EHOSTDOWN] = TARGET_EHOSTDOWN,
651 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
652 [EALREADY] = TARGET_EALREADY,
653 [EINPROGRESS] = TARGET_EINPROGRESS,
654 [ESTALE] = TARGET_ESTALE,
655 [ECANCELED] = TARGET_ECANCELED,
656 [ENOMEDIUM] = TARGET_ENOMEDIUM,
657 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000658#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000659 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000660#endif
661#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000662 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000663#endif
664#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000665 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000666#endif
667#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000668 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000669#endif
670#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000671 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000672#endif
673#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000674 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000675#endif
thsb92c47c2007-11-01 00:07:38 +0000676};
ths637947f2007-06-01 12:09:19 +0000677
678static inline int host_to_target_errno(int err)
679{
680 if(host_to_target_errno_table[err])
681 return host_to_target_errno_table[err];
682 return err;
683}
684
thsb92c47c2007-11-01 00:07:38 +0000685static inline int target_to_host_errno(int err)
686{
687 if (target_to_host_errno_table[err])
688 return target_to_host_errno_table[err];
689 return err;
690}
691
blueswir1992f48a2007-10-14 16:27:31 +0000692static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000693{
694 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000695 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000696 else
697 return ret;
698}
699
blueswir1992f48a2007-10-14 16:27:31 +0000700static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000701{
blueswir1992f48a2007-10-14 16:27:31 +0000702 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000703}
704
thsb92c47c2007-11-01 00:07:38 +0000705char *target_strerror(int err)
706{
707 return strerror(target_to_host_errno(err));
708}
709
blueswir1992f48a2007-10-14 16:27:31 +0000710static abi_ulong target_brk;
711static abi_ulong target_original_brk;
bellard31e31b82003-02-18 22:55:36 +0000712
blueswir1992f48a2007-10-14 16:27:31 +0000713void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000714{
blueswir14c1de732007-07-07 20:45:44 +0000715 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
bellard31e31b82003-02-18 22:55:36 +0000716}
717
ths0da46a62007-10-20 20:23:07 +0000718/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000719abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000720{
blueswir1992f48a2007-10-14 16:27:31 +0000721 abi_ulong brk_page;
722 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000723 int new_alloc_size;
724
725 if (!new_brk)
pbrook53a59602006-03-25 19:31:22 +0000726 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000727 if (new_brk < target_original_brk)
balrog7ab240a2008-04-26 12:17:34 +0000728 return target_brk;
ths3b46e622007-09-17 08:09:54 +0000729
pbrook53a59602006-03-25 19:31:22 +0000730 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000731
732 /* If the new brk is less than this, set it and we're done... */
733 if (new_brk < brk_page) {
734 target_brk = new_brk;
pbrook53a59602006-03-25 19:31:22 +0000735 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000736 }
737
Peter Maydell00faf082011-04-18 16:34:24 +0100738 /* We need to allocate more memory after the brk... Note that
739 * we don't use MAP_FIXED because that will map over the top of
740 * any existing mapping (like the one with the host libc or qemu
741 * itself); instead we treat "mapped but at wrong address" as
742 * a failure and unmap again.
743 */
bellard54936002003-05-13 00:25:15 +0000744 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
ths5fafdf22007-09-16 21:08:06 +0000745 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000746 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100747 MAP_ANON|MAP_PRIVATE, 0, 0));
748
749 if (mapped_addr == brk_page) {
750 target_brk = new_brk;
751 return target_brk;
752 } else if (mapped_addr != -1) {
753 /* Mapped but at wrong address, meaning there wasn't actually
754 * enough space for this brk.
755 */
756 target_munmap(mapped_addr, new_alloc_size);
757 mapped_addr = -1;
758 }
balrog7ab240a2008-04-26 12:17:34 +0000759
Richard Henderson7dd46c02010-05-03 10:07:49 -0700760#if defined(TARGET_ALPHA)
761 /* We (partially) emulate OSF/1 on Alpha, which requires we
762 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100763 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700764#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100765 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000766 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000767}
768
ths26edcf42007-12-09 02:25:24 +0000769static inline abi_long copy_from_user_fdset(fd_set *fds,
770 abi_ulong target_fds_addr,
771 int n)
bellard31e31b82003-02-18 22:55:36 +0000772{
ths26edcf42007-12-09 02:25:24 +0000773 int i, nw, j, k;
774 abi_ulong b, *target_fds;
775
776 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
777 if (!(target_fds = lock_user(VERIFY_READ,
778 target_fds_addr,
779 sizeof(abi_ulong) * nw,
780 1)))
781 return -TARGET_EFAULT;
782
783 FD_ZERO(fds);
784 k = 0;
785 for (i = 0; i < nw; i++) {
786 /* grab the abi_ulong */
787 __get_user(b, &target_fds[i]);
788 for (j = 0; j < TARGET_ABI_BITS; j++) {
789 /* check the bit inside the abi_ulong */
790 if ((b >> j) & 1)
791 FD_SET(k, fds);
792 k++;
bellard31e31b82003-02-18 22:55:36 +0000793 }
bellard31e31b82003-02-18 22:55:36 +0000794 }
ths26edcf42007-12-09 02:25:24 +0000795
796 unlock_user(target_fds, target_fds_addr, 0);
797
798 return 0;
bellard31e31b82003-02-18 22:55:36 +0000799}
800
ths26edcf42007-12-09 02:25:24 +0000801static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
802 const fd_set *fds,
803 int n)
bellard31e31b82003-02-18 22:55:36 +0000804{
bellard31e31b82003-02-18 22:55:36 +0000805 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000806 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000807 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000808
ths26edcf42007-12-09 02:25:24 +0000809 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
810 if (!(target_fds = lock_user(VERIFY_WRITE,
811 target_fds_addr,
812 sizeof(abi_ulong) * nw,
813 0)))
814 return -TARGET_EFAULT;
815
816 k = 0;
817 for (i = 0; i < nw; i++) {
818 v = 0;
819 for (j = 0; j < TARGET_ABI_BITS; j++) {
820 v |= ((FD_ISSET(k, fds) != 0) << j);
821 k++;
bellard31e31b82003-02-18 22:55:36 +0000822 }
ths26edcf42007-12-09 02:25:24 +0000823 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000824 }
ths26edcf42007-12-09 02:25:24 +0000825
826 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
827
828 return 0;
bellard31e31b82003-02-18 22:55:36 +0000829}
830
bellardc596ed12003-07-13 17:32:31 +0000831#if defined(__alpha__)
832#define HOST_HZ 1024
833#else
834#define HOST_HZ 100
835#endif
836
blueswir1992f48a2007-10-14 16:27:31 +0000837static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000838{
839#if HOST_HZ == TARGET_HZ
840 return ticks;
841#else
842 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
843#endif
844}
845
bellard579a97f2007-11-11 14:26:47 +0000846static inline abi_long host_to_target_rusage(abi_ulong target_addr,
847 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000848{
pbrook53a59602006-03-25 19:31:22 +0000849 struct target_rusage *target_rusage;
850
bellard579a97f2007-11-11 14:26:47 +0000851 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
852 return -TARGET_EFAULT;
bellardb4091862003-05-16 15:39:34 +0000853 target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
854 target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
855 target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
856 target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
857 target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
858 target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
859 target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
860 target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
861 target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
862 target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
863 target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
864 target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
865 target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
866 target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
867 target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
868 target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
869 target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
870 target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000871 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000872
873 return 0;
bellardb4091862003-05-16 15:39:34 +0000874}
875
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900876static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
877{
878 if (target_rlim == TARGET_RLIM_INFINITY)
879 return RLIM_INFINITY;
880 else
881 return tswapl(target_rlim);
882}
883
884static inline target_ulong host_to_target_rlim(rlim_t rlim)
885{
886 if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
887 return TARGET_RLIM_INFINITY;
888 else
889 return tswapl(rlim);
890}
891
ths788f5ec2007-12-09 02:37:05 +0000892static inline abi_long copy_from_user_timeval(struct timeval *tv,
893 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000894{
pbrook53a59602006-03-25 19:31:22 +0000895 struct target_timeval *target_tv;
896
ths788f5ec2007-12-09 02:37:05 +0000897 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000898 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000899
900 __get_user(tv->tv_sec, &target_tv->tv_sec);
901 __get_user(tv->tv_usec, &target_tv->tv_usec);
902
903 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000904
905 return 0;
bellard31e31b82003-02-18 22:55:36 +0000906}
907
ths788f5ec2007-12-09 02:37:05 +0000908static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
909 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000910{
pbrook53a59602006-03-25 19:31:22 +0000911 struct target_timeval *target_tv;
912
ths788f5ec2007-12-09 02:37:05 +0000913 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000914 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000915
916 __put_user(tv->tv_sec, &target_tv->tv_sec);
917 __put_user(tv->tv_usec, &target_tv->tv_usec);
918
919 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000920
921 return 0;
bellard31e31b82003-02-18 22:55:36 +0000922}
923
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700924#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
925#include <mqueue.h>
926
aurel3224e10032009-04-15 16:11:43 +0000927static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
928 abi_ulong target_mq_attr_addr)
929{
930 struct target_mq_attr *target_mq_attr;
931
932 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
933 target_mq_attr_addr, 1))
934 return -TARGET_EFAULT;
935
936 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
937 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
938 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
939 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
940
941 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
942
943 return 0;
944}
945
946static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
947 const struct mq_attr *attr)
948{
949 struct target_mq_attr *target_mq_attr;
950
951 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
952 target_mq_attr_addr, 0))
953 return -TARGET_EFAULT;
954
955 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
956 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
957 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
958 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
959
960 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
961
962 return 0;
963}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700964#endif
bellard31e31b82003-02-18 22:55:36 +0000965
ths0da46a62007-10-20 20:23:07 +0000966/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000967static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000968 abi_ulong rfd_addr, abi_ulong wfd_addr,
969 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000970{
971 fd_set rfds, wfds, efds;
972 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
973 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000974 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000975
ths26edcf42007-12-09 02:25:24 +0000976 if (rfd_addr) {
977 if (copy_from_user_fdset(&rfds, rfd_addr, n))
978 return -TARGET_EFAULT;
979 rfds_ptr = &rfds;
pbrook53a59602006-03-25 19:31:22 +0000980 } else {
pbrook53a59602006-03-25 19:31:22 +0000981 rfds_ptr = NULL;
982 }
ths26edcf42007-12-09 02:25:24 +0000983 if (wfd_addr) {
984 if (copy_from_user_fdset(&wfds, wfd_addr, n))
985 return -TARGET_EFAULT;
986 wfds_ptr = &wfds;
pbrook53a59602006-03-25 19:31:22 +0000987 } else {
pbrook53a59602006-03-25 19:31:22 +0000988 wfds_ptr = NULL;
989 }
ths26edcf42007-12-09 02:25:24 +0000990 if (efd_addr) {
991 if (copy_from_user_fdset(&efds, efd_addr, n))
992 return -TARGET_EFAULT;
993 efds_ptr = &efds;
pbrook53a59602006-03-25 19:31:22 +0000994 } else {
pbrook53a59602006-03-25 19:31:22 +0000995 efds_ptr = NULL;
996 }
ths3b46e622007-09-17 08:09:54 +0000997
ths26edcf42007-12-09 02:25:24 +0000998 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +0000999 if (copy_from_user_timeval(&tv, target_tv_addr))
1000 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001001 tv_ptr = &tv;
1002 } else {
1003 tv_ptr = NULL;
1004 }
ths26edcf42007-12-09 02:25:24 +00001005
bellard31e31b82003-02-18 22:55:36 +00001006 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001007
ths26edcf42007-12-09 02:25:24 +00001008 if (!is_error(ret)) {
1009 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1010 return -TARGET_EFAULT;
1011 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1012 return -TARGET_EFAULT;
1013 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1014 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001015
ths788f5ec2007-12-09 02:37:05 +00001016 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1017 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001018 }
bellard579a97f2007-11-11 14:26:47 +00001019
bellard31e31b82003-02-18 22:55:36 +00001020 return ret;
1021}
1022
Riku Voipio099d6b02009-05-05 12:10:04 +03001023static abi_long do_pipe2(int host_pipe[], int flags)
1024{
1025#ifdef CONFIG_PIPE2
1026 return pipe2(host_pipe, flags);
1027#else
1028 return -ENOSYS;
1029#endif
1030}
1031
Richard Hendersonfb41a662010-05-03 10:07:52 -07001032static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1033 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001034{
1035 int host_pipe[2];
1036 abi_long ret;
1037 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1038
1039 if (is_error(ret))
1040 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001041
1042 /* Several targets have special calling conventions for the original
1043 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1044 if (!is_pipe2) {
1045#if defined(TARGET_ALPHA)
1046 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1047 return host_pipe[0];
1048#elif defined(TARGET_MIPS)
1049 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1050 return host_pipe[0];
1051#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001052 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001053 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001054#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001055 }
1056
Riku Voipio099d6b02009-05-05 12:10:04 +03001057 if (put_user_s32(host_pipe[0], pipedes)
1058 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1059 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001060 return get_errno(ret);
1061}
1062
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001063static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1064 abi_ulong target_addr,
1065 socklen_t len)
1066{
1067 struct target_ip_mreqn *target_smreqn;
1068
1069 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1070 if (!target_smreqn)
1071 return -TARGET_EFAULT;
1072 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1073 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1074 if (len == sizeof(struct target_ip_mreqn))
1075 mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
1076 unlock_user(target_smreqn, target_addr, 0);
1077
1078 return 0;
1079}
1080
bellard579a97f2007-11-11 14:26:47 +00001081static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1082 abi_ulong target_addr,
1083 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001084{
aurel32607175e2009-04-15 16:11:59 +00001085 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1086 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001087 struct target_sockaddr *target_saddr;
1088
bellard579a97f2007-11-11 14:26:47 +00001089 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1090 if (!target_saddr)
1091 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001092
1093 sa_family = tswap16(target_saddr->sa_family);
1094
1095 /* Oops. The caller might send a incomplete sun_path; sun_path
1096 * must be terminated by \0 (see the manual page), but
1097 * unfortunately it is quite common to specify sockaddr_un
1098 * length as "strlen(x->sun_path)" while it should be
1099 * "strlen(...) + 1". We'll fix that here if needed.
1100 * Linux kernel has a similar feature.
1101 */
1102
1103 if (sa_family == AF_UNIX) {
1104 if (len < unix_maxlen && len > 0) {
1105 char *cp = (char*)target_saddr;
1106
1107 if ( cp[len-1] && !cp[len] )
1108 len++;
1109 }
1110 if (len > unix_maxlen)
1111 len = unix_maxlen;
1112 }
1113
pbrook53a59602006-03-25 19:31:22 +00001114 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001115 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001116 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001117
1118 return 0;
bellard7854b052003-03-29 17:22:23 +00001119}
1120
bellard579a97f2007-11-11 14:26:47 +00001121static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1122 struct sockaddr *addr,
1123 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001124{
pbrook53a59602006-03-25 19:31:22 +00001125 struct target_sockaddr *target_saddr;
1126
bellard579a97f2007-11-11 14:26:47 +00001127 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1128 if (!target_saddr)
1129 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001130 memcpy(target_saddr, addr, len);
1131 target_saddr->sa_family = tswap16(addr->sa_family);
1132 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001133
1134 return 0;
bellard7854b052003-03-29 17:22:23 +00001135}
1136
pbrook53a59602006-03-25 19:31:22 +00001137/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001138static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1139 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001140{
1141 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001142 abi_long msg_controllen;
1143 abi_ulong target_cmsg_addr;
1144 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001145 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001146
1147 msg_controllen = tswapl(target_msgh->msg_controllen);
1148 if (msg_controllen < sizeof (struct target_cmsghdr))
1149 goto the_end;
1150 target_cmsg_addr = tswapl(target_msgh->msg_control);
1151 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1152 if (!target_cmsg)
1153 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001154
1155 while (cmsg && target_cmsg) {
1156 void *data = CMSG_DATA(cmsg);
1157 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1158
ths5fafdf22007-09-16 21:08:06 +00001159 int len = tswapl(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001160 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1161
1162 space += CMSG_SPACE(len);
1163 if (space > msgh->msg_controllen) {
1164 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001165 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001166 break;
1167 }
1168
1169 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1170 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1171 cmsg->cmsg_len = CMSG_LEN(len);
1172
bellard3532fa72006-06-24 15:06:03 +00001173 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001174 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1175 memcpy(data, target_data, len);
1176 } else {
1177 int *fd = (int *)data;
1178 int *target_fd = (int *)target_data;
1179 int i, numfds = len / sizeof(int);
1180
1181 for (i = 0; i < numfds; i++)
1182 fd[i] = tswap32(target_fd[i]);
1183 }
1184
1185 cmsg = CMSG_NXTHDR(msgh, cmsg);
1186 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1187 }
bellard5a4a8982007-11-11 17:39:18 +00001188 unlock_user(target_cmsg, target_cmsg_addr, 0);
1189 the_end:
bellard7854b052003-03-29 17:22:23 +00001190 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001191 return 0;
bellard7854b052003-03-29 17:22:23 +00001192}
1193
pbrook53a59602006-03-25 19:31:22 +00001194/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001195static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1196 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001197{
1198 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001199 abi_long msg_controllen;
1200 abi_ulong target_cmsg_addr;
1201 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001202 socklen_t space = 0;
1203
bellard5a4a8982007-11-11 17:39:18 +00001204 msg_controllen = tswapl(target_msgh->msg_controllen);
1205 if (msg_controllen < sizeof (struct target_cmsghdr))
1206 goto the_end;
1207 target_cmsg_addr = tswapl(target_msgh->msg_control);
1208 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1209 if (!target_cmsg)
1210 return -TARGET_EFAULT;
1211
bellard7854b052003-03-29 17:22:23 +00001212 while (cmsg && target_cmsg) {
1213 void *data = CMSG_DATA(cmsg);
1214 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1215
1216 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1217
1218 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001219 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001220 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001221 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001222 break;
1223 }
1224
1225 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1226 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
1227 target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
1228
bellard3532fa72006-06-24 15:06:03 +00001229 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001230 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1231 memcpy(target_data, data, len);
1232 } else {
1233 int *fd = (int *)data;
1234 int *target_fd = (int *)target_data;
1235 int i, numfds = len / sizeof(int);
1236
1237 for (i = 0; i < numfds; i++)
1238 target_fd[i] = tswap32(fd[i]);
1239 }
1240
1241 cmsg = CMSG_NXTHDR(msgh, cmsg);
1242 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1243 }
bellard5a4a8982007-11-11 17:39:18 +00001244 unlock_user(target_cmsg, target_cmsg_addr, space);
1245 the_end:
1246 target_msgh->msg_controllen = tswapl(space);
1247 return 0;
bellard7854b052003-03-29 17:22:23 +00001248}
1249
ths0da46a62007-10-20 20:23:07 +00001250/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001251static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001252 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001253{
blueswir1992f48a2007-10-14 16:27:31 +00001254 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001255 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001256 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001257 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001258
bellard8853f862004-02-22 14:57:26 +00001259 switch(level) {
1260 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001261 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001262 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001263 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001264
bellard2f619692007-11-16 10:46:05 +00001265 if (get_user_u32(val, optval_addr))
1266 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001267 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1268 break;
1269 case SOL_IP:
1270 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001271 case IP_TOS:
1272 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001273 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001274 case IP_ROUTER_ALERT:
1275 case IP_RECVOPTS:
1276 case IP_RETOPTS:
1277 case IP_PKTINFO:
1278 case IP_MTU_DISCOVER:
1279 case IP_RECVERR:
1280 case IP_RECVTOS:
1281#ifdef IP_FREEBIND
1282 case IP_FREEBIND:
1283#endif
1284 case IP_MULTICAST_TTL:
1285 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001286 val = 0;
1287 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001288 if (get_user_u32(val, optval_addr))
1289 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001290 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001291 if (get_user_u8(val, optval_addr))
1292 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001293 }
1294 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1295 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001296 case IP_ADD_MEMBERSHIP:
1297 case IP_DROP_MEMBERSHIP:
1298 if (optlen < sizeof (struct target_ip_mreq) ||
1299 optlen > sizeof (struct target_ip_mreqn))
1300 return -TARGET_EINVAL;
1301
1302 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1303 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1304 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1305 break;
1306
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001307 case IP_BLOCK_SOURCE:
1308 case IP_UNBLOCK_SOURCE:
1309 case IP_ADD_SOURCE_MEMBERSHIP:
1310 case IP_DROP_SOURCE_MEMBERSHIP:
1311 if (optlen != sizeof (struct target_ip_mreq_source))
1312 return -TARGET_EINVAL;
1313
1314 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1315 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1316 unlock_user (ip_mreq_source, optval_addr, 0);
1317 break;
1318
bellard8853f862004-02-22 14:57:26 +00001319 default:
1320 goto unimplemented;
1321 }
1322 break;
bellard3532fa72006-06-24 15:06:03 +00001323 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001324 switch (optname) {
1325 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001326 case TARGET_SO_DEBUG:
1327 optname = SO_DEBUG;
1328 break;
1329 case TARGET_SO_REUSEADDR:
1330 optname = SO_REUSEADDR;
1331 break;
1332 case TARGET_SO_TYPE:
1333 optname = SO_TYPE;
1334 break;
1335 case TARGET_SO_ERROR:
1336 optname = SO_ERROR;
1337 break;
1338 case TARGET_SO_DONTROUTE:
1339 optname = SO_DONTROUTE;
1340 break;
1341 case TARGET_SO_BROADCAST:
1342 optname = SO_BROADCAST;
1343 break;
1344 case TARGET_SO_SNDBUF:
1345 optname = SO_SNDBUF;
1346 break;
1347 case TARGET_SO_RCVBUF:
1348 optname = SO_RCVBUF;
1349 break;
1350 case TARGET_SO_KEEPALIVE:
1351 optname = SO_KEEPALIVE;
1352 break;
1353 case TARGET_SO_OOBINLINE:
1354 optname = SO_OOBINLINE;
1355 break;
1356 case TARGET_SO_NO_CHECK:
1357 optname = SO_NO_CHECK;
1358 break;
1359 case TARGET_SO_PRIORITY:
1360 optname = SO_PRIORITY;
1361 break;
bellard5e83e8e2005-03-01 22:32:06 +00001362#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001363 case TARGET_SO_BSDCOMPAT:
1364 optname = SO_BSDCOMPAT;
1365 break;
bellard5e83e8e2005-03-01 22:32:06 +00001366#endif
bellard3532fa72006-06-24 15:06:03 +00001367 case TARGET_SO_PASSCRED:
1368 optname = SO_PASSCRED;
1369 break;
1370 case TARGET_SO_TIMESTAMP:
1371 optname = SO_TIMESTAMP;
1372 break;
1373 case TARGET_SO_RCVLOWAT:
1374 optname = SO_RCVLOWAT;
1375 break;
1376 case TARGET_SO_RCVTIMEO:
1377 optname = SO_RCVTIMEO;
1378 break;
1379 case TARGET_SO_SNDTIMEO:
1380 optname = SO_SNDTIMEO;
1381 break;
bellard8853f862004-02-22 14:57:26 +00001382 break;
1383 default:
1384 goto unimplemented;
1385 }
bellard3532fa72006-06-24 15:06:03 +00001386 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001387 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001388
bellard2f619692007-11-16 10:46:05 +00001389 if (get_user_u32(val, optval_addr))
1390 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001391 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001392 break;
bellard7854b052003-03-29 17:22:23 +00001393 default:
bellard8853f862004-02-22 14:57:26 +00001394 unimplemented:
1395 gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001396 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001397 }
bellard8853f862004-02-22 14:57:26 +00001398 return ret;
bellard7854b052003-03-29 17:22:23 +00001399}
1400
ths0da46a62007-10-20 20:23:07 +00001401/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001402static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001403 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001404{
blueswir1992f48a2007-10-14 16:27:31 +00001405 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001406 int len, val;
1407 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001408
1409 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001410 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001411 level = SOL_SOCKET;
1412 switch (optname) {
1413 /* These don't just return a single integer */
1414 case TARGET_SO_LINGER:
1415 case TARGET_SO_RCVTIMEO:
1416 case TARGET_SO_SNDTIMEO:
1417 case TARGET_SO_PEERCRED:
1418 case TARGET_SO_PEERNAME:
1419 goto unimplemented;
1420 /* Options with 'int' argument. */
1421 case TARGET_SO_DEBUG:
1422 optname = SO_DEBUG;
1423 goto int_case;
1424 case TARGET_SO_REUSEADDR:
1425 optname = SO_REUSEADDR;
1426 goto int_case;
1427 case TARGET_SO_TYPE:
1428 optname = SO_TYPE;
1429 goto int_case;
1430 case TARGET_SO_ERROR:
1431 optname = SO_ERROR;
1432 goto int_case;
1433 case TARGET_SO_DONTROUTE:
1434 optname = SO_DONTROUTE;
1435 goto int_case;
1436 case TARGET_SO_BROADCAST:
1437 optname = SO_BROADCAST;
1438 goto int_case;
1439 case TARGET_SO_SNDBUF:
1440 optname = SO_SNDBUF;
1441 goto int_case;
1442 case TARGET_SO_RCVBUF:
1443 optname = SO_RCVBUF;
1444 goto int_case;
1445 case TARGET_SO_KEEPALIVE:
1446 optname = SO_KEEPALIVE;
1447 goto int_case;
1448 case TARGET_SO_OOBINLINE:
1449 optname = SO_OOBINLINE;
1450 goto int_case;
1451 case TARGET_SO_NO_CHECK:
1452 optname = SO_NO_CHECK;
1453 goto int_case;
1454 case TARGET_SO_PRIORITY:
1455 optname = SO_PRIORITY;
1456 goto int_case;
1457#ifdef SO_BSDCOMPAT
1458 case TARGET_SO_BSDCOMPAT:
1459 optname = SO_BSDCOMPAT;
1460 goto int_case;
1461#endif
1462 case TARGET_SO_PASSCRED:
1463 optname = SO_PASSCRED;
1464 goto int_case;
1465 case TARGET_SO_TIMESTAMP:
1466 optname = SO_TIMESTAMP;
1467 goto int_case;
1468 case TARGET_SO_RCVLOWAT:
1469 optname = SO_RCVLOWAT;
1470 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001471 default:
bellard2efbe912005-07-23 15:10:20 +00001472 goto int_case;
1473 }
1474 break;
1475 case SOL_TCP:
1476 /* TCP options all take an 'int' value. */
1477 int_case:
bellard2f619692007-11-16 10:46:05 +00001478 if (get_user_u32(len, optlen))
1479 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001480 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001481 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001482 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001483 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1484 if (ret < 0)
1485 return ret;
bellard2efbe912005-07-23 15:10:20 +00001486 if (len > lv)
1487 len = lv;
bellard2f619692007-11-16 10:46:05 +00001488 if (len == 4) {
1489 if (put_user_u32(val, optval_addr))
1490 return -TARGET_EFAULT;
1491 } else {
1492 if (put_user_u8(val, optval_addr))
1493 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001494 }
bellard2f619692007-11-16 10:46:05 +00001495 if (put_user_u32(len, optlen))
1496 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001497 break;
1498 case SOL_IP:
1499 switch(optname) {
1500 case IP_TOS:
1501 case IP_TTL:
1502 case IP_HDRINCL:
1503 case IP_ROUTER_ALERT:
1504 case IP_RECVOPTS:
1505 case IP_RETOPTS:
1506 case IP_PKTINFO:
1507 case IP_MTU_DISCOVER:
1508 case IP_RECVERR:
1509 case IP_RECVTOS:
1510#ifdef IP_FREEBIND
1511 case IP_FREEBIND:
1512#endif
1513 case IP_MULTICAST_TTL:
1514 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001515 if (get_user_u32(len, optlen))
1516 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001517 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001518 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001519 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001520 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1521 if (ret < 0)
1522 return ret;
bellard2efbe912005-07-23 15:10:20 +00001523 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001524 len = 1;
bellard2f619692007-11-16 10:46:05 +00001525 if (put_user_u32(len, optlen)
1526 || put_user_u8(val, optval_addr))
1527 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001528 } else {
bellard2efbe912005-07-23 15:10:20 +00001529 if (len > sizeof(int))
1530 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001531 if (put_user_u32(len, optlen)
1532 || put_user_u32(val, optval_addr))
1533 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001534 }
bellard8853f862004-02-22 14:57:26 +00001535 break;
bellard2efbe912005-07-23 15:10:20 +00001536 default:
thsc02f4992007-12-18 02:39:59 +00001537 ret = -TARGET_ENOPROTOOPT;
1538 break;
bellard8853f862004-02-22 14:57:26 +00001539 }
1540 break;
1541 default:
1542 unimplemented:
1543 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1544 level, optname);
thsc02f4992007-12-18 02:39:59 +00001545 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001546 break;
1547 }
1548 return ret;
bellard7854b052003-03-29 17:22:23 +00001549}
1550
bellard579a97f2007-11-11 14:26:47 +00001551/* FIXME
1552 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1553 * other lock functions have a return code of 0 for failure.
1554 */
1555static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1556 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001557{
1558 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001559 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001560 int i;
pbrook53a59602006-03-25 19:31:22 +00001561
bellard579a97f2007-11-11 14:26:47 +00001562 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1563 if (!target_vec)
1564 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001565 for(i = 0;i < count; i++) {
1566 base = tswapl(target_vec[i].iov_base);
1567 vec[i].iov_len = tswapl(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001568 if (vec[i].iov_len != 0) {
1569 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001570 /* Don't check lock_user return value. We must call writev even
1571 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001572 } else {
1573 /* zero length pointer is ignored */
1574 vec[i].iov_base = NULL;
1575 }
pbrook53a59602006-03-25 19:31:22 +00001576 }
1577 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001578 return 0;
pbrook53a59602006-03-25 19:31:22 +00001579}
1580
bellard579a97f2007-11-11 14:26:47 +00001581static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1582 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001583{
1584 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001585 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001586 int i;
1587
bellard579a97f2007-11-11 14:26:47 +00001588 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1589 if (!target_vec)
1590 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001591 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001592 if (target_vec[i].iov_base) {
1593 base = tswapl(target_vec[i].iov_base);
1594 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1595 }
pbrook53a59602006-03-25 19:31:22 +00001596 }
1597 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001598
1599 return 0;
pbrook53a59602006-03-25 19:31:22 +00001600}
1601
ths0da46a62007-10-20 20:23:07 +00001602/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001603static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001604{
1605#if defined(TARGET_MIPS)
1606 switch(type) {
1607 case TARGET_SOCK_DGRAM:
1608 type = SOCK_DGRAM;
1609 break;
1610 case TARGET_SOCK_STREAM:
1611 type = SOCK_STREAM;
1612 break;
1613 case TARGET_SOCK_RAW:
1614 type = SOCK_RAW;
1615 break;
1616 case TARGET_SOCK_RDM:
1617 type = SOCK_RDM;
1618 break;
1619 case TARGET_SOCK_SEQPACKET:
1620 type = SOCK_SEQPACKET;
1621 break;
1622 case TARGET_SOCK_PACKET:
1623 type = SOCK_PACKET;
1624 break;
1625 }
1626#endif
balrog12bc92a2007-10-30 21:06:14 +00001627 if (domain == PF_NETLINK)
1628 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001629 return get_errno(socket(domain, type, protocol));
1630}
1631
ths0da46a62007-10-20 20:23:07 +00001632/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001633static abi_long do_bind(int sockfd, abi_ulong target_addr,
1634 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001635{
aurel328f7aeaf2009-01-30 19:47:57 +00001636 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001637 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001638
Blue Swirl38724252010-09-18 05:53:14 +00001639 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001640 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001641 }
aurel328f7aeaf2009-01-30 19:47:57 +00001642
aurel32607175e2009-04-15 16:11:59 +00001643 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001644
Arnaud Patard917507b2009-06-19 10:44:45 +03001645 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1646 if (ret)
1647 return ret;
1648
bellard3532fa72006-06-24 15:06:03 +00001649 return get_errno(bind(sockfd, addr, addrlen));
1650}
1651
ths0da46a62007-10-20 20:23:07 +00001652/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001653static abi_long do_connect(int sockfd, abi_ulong target_addr,
1654 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001655{
aurel328f7aeaf2009-01-30 19:47:57 +00001656 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001657 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001658
Blue Swirl38724252010-09-18 05:53:14 +00001659 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001660 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001661 }
aurel328f7aeaf2009-01-30 19:47:57 +00001662
1663 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001664
Arnaud Patard917507b2009-06-19 10:44:45 +03001665 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1666 if (ret)
1667 return ret;
1668
bellard3532fa72006-06-24 15:06:03 +00001669 return get_errno(connect(sockfd, addr, addrlen));
1670}
1671
ths0da46a62007-10-20 20:23:07 +00001672/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001673static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1674 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001675{
balrog6de645c2008-10-28 10:26:29 +00001676 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001677 struct target_msghdr *msgp;
1678 struct msghdr msg;
1679 int count;
1680 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001681 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001682
bellard579a97f2007-11-11 14:26:47 +00001683 /* FIXME */
1684 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1685 msgp,
1686 target_msg,
1687 send ? 1 : 0))
1688 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001689 if (msgp->msg_name) {
1690 msg.msg_namelen = tswap32(msgp->msg_namelen);
1691 msg.msg_name = alloca(msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001692 ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001693 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001694 if (ret) {
1695 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1696 return ret;
1697 }
bellard3532fa72006-06-24 15:06:03 +00001698 } else {
1699 msg.msg_name = NULL;
1700 msg.msg_namelen = 0;
1701 }
1702 msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
1703 msg.msg_control = alloca(msg.msg_controllen);
1704 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001705
bellard3532fa72006-06-24 15:06:03 +00001706 count = tswapl(msgp->msg_iovlen);
1707 vec = alloca(count * sizeof(struct iovec));
1708 target_vec = tswapl(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001709 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001710 msg.msg_iovlen = count;
1711 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001712
bellard3532fa72006-06-24 15:06:03 +00001713 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001714 ret = target_to_host_cmsg(&msg, msgp);
1715 if (ret == 0)
1716 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001717 } else {
1718 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001719 if (!is_error(ret)) {
1720 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001721 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001722 if (!is_error(ret))
1723 ret = len;
1724 }
bellard3532fa72006-06-24 15:06:03 +00001725 }
1726 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001727 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001728 return ret;
1729}
1730
ths0da46a62007-10-20 20:23:07 +00001731/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001732static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001733 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001734{
bellard2f619692007-11-16 10:46:05 +00001735 socklen_t addrlen;
1736 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001737 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001738
Arnaud Patard917507b2009-06-19 10:44:45 +03001739 if (target_addr == 0)
1740 return get_errno(accept(fd, NULL, NULL));
1741
1742 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001743 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001744 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001745
Blue Swirl38724252010-09-18 05:53:14 +00001746 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001747 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001748 }
aurel328f7aeaf2009-01-30 19:47:57 +00001749
Arnaud Patard917507b2009-06-19 10:44:45 +03001750 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1751 return -TARGET_EINVAL;
1752
bellard2f619692007-11-16 10:46:05 +00001753 addr = alloca(addrlen);
1754
pbrook1be9e1d2006-11-19 15:26:04 +00001755 ret = get_errno(accept(fd, addr, &addrlen));
1756 if (!is_error(ret)) {
1757 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001758 if (put_user_u32(addrlen, target_addrlen_addr))
1759 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001760 }
1761 return ret;
1762}
1763
ths0da46a62007-10-20 20:23:07 +00001764/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001765static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001766 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001767{
bellard2f619692007-11-16 10:46:05 +00001768 socklen_t addrlen;
1769 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001770 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001771
bellard2f619692007-11-16 10:46:05 +00001772 if (get_user_u32(addrlen, target_addrlen_addr))
1773 return -TARGET_EFAULT;
1774
Blue Swirl38724252010-09-18 05:53:14 +00001775 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001776 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001777 }
aurel328f7aeaf2009-01-30 19:47:57 +00001778
Arnaud Patard917507b2009-06-19 10:44:45 +03001779 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1780 return -TARGET_EFAULT;
1781
bellard2f619692007-11-16 10:46:05 +00001782 addr = alloca(addrlen);
1783
pbrook1be9e1d2006-11-19 15:26:04 +00001784 ret = get_errno(getpeername(fd, addr, &addrlen));
1785 if (!is_error(ret)) {
1786 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001787 if (put_user_u32(addrlen, target_addrlen_addr))
1788 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001789 }
1790 return ret;
1791}
1792
ths0da46a62007-10-20 20:23:07 +00001793/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001794static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001795 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001796{
bellard2f619692007-11-16 10:46:05 +00001797 socklen_t addrlen;
1798 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001799 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001800
bellard2f619692007-11-16 10:46:05 +00001801 if (get_user_u32(addrlen, target_addrlen_addr))
1802 return -TARGET_EFAULT;
1803
Blue Swirl38724252010-09-18 05:53:14 +00001804 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001805 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001806 }
aurel328f7aeaf2009-01-30 19:47:57 +00001807
Arnaud Patard917507b2009-06-19 10:44:45 +03001808 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1809 return -TARGET_EFAULT;
1810
bellard2f619692007-11-16 10:46:05 +00001811 addr = alloca(addrlen);
1812
pbrook1be9e1d2006-11-19 15:26:04 +00001813 ret = get_errno(getsockname(fd, addr, &addrlen));
1814 if (!is_error(ret)) {
1815 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001816 if (put_user_u32(addrlen, target_addrlen_addr))
1817 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001818 }
1819 return ret;
1820}
1821
ths0da46a62007-10-20 20:23:07 +00001822/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001823static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001824 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001825{
1826 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001827 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001828
1829 ret = get_errno(socketpair(domain, type, protocol, tab));
1830 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001831 if (put_user_s32(tab[0], target_tab_addr)
1832 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1833 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001834 }
1835 return ret;
1836}
1837
ths0da46a62007-10-20 20:23:07 +00001838/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001839static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1840 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001841{
1842 void *addr;
1843 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001844 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001845
Blue Swirl38724252010-09-18 05:53:14 +00001846 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001847 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001848 }
aurel328f7aeaf2009-01-30 19:47:57 +00001849
bellard579a97f2007-11-11 14:26:47 +00001850 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1851 if (!host_msg)
1852 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001853 if (target_addr) {
1854 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001855 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1856 if (ret) {
1857 unlock_user(host_msg, msg, 0);
1858 return ret;
1859 }
pbrook1be9e1d2006-11-19 15:26:04 +00001860 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1861 } else {
1862 ret = get_errno(send(fd, host_msg, len, flags));
1863 }
1864 unlock_user(host_msg, msg, 0);
1865 return ret;
1866}
1867
ths0da46a62007-10-20 20:23:07 +00001868/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001869static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1870 abi_ulong target_addr,
1871 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001872{
1873 socklen_t addrlen;
1874 void *addr;
1875 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001876 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001877
bellard579a97f2007-11-11 14:26:47 +00001878 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
1879 if (!host_msg)
1880 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001881 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00001882 if (get_user_u32(addrlen, target_addrlen)) {
1883 ret = -TARGET_EFAULT;
1884 goto fail;
1885 }
Blue Swirl38724252010-09-18 05:53:14 +00001886 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001887 ret = -TARGET_EINVAL;
1888 goto fail;
1889 }
pbrook1be9e1d2006-11-19 15:26:04 +00001890 addr = alloca(addrlen);
1891 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
1892 } else {
1893 addr = NULL; /* To keep compiler quiet. */
1894 ret = get_errno(recv(fd, host_msg, len, flags));
1895 }
1896 if (!is_error(ret)) {
1897 if (target_addr) {
1898 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001899 if (put_user_u32(addrlen, target_addrlen)) {
1900 ret = -TARGET_EFAULT;
1901 goto fail;
1902 }
pbrook1be9e1d2006-11-19 15:26:04 +00001903 }
1904 unlock_user(host_msg, msg, len);
1905 } else {
bellard2f619692007-11-16 10:46:05 +00001906fail:
pbrook1be9e1d2006-11-19 15:26:04 +00001907 unlock_user(host_msg, msg, 0);
1908 }
1909 return ret;
1910}
1911
j_mayer32407102007-09-26 23:01:49 +00001912#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00001913/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001914static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00001915{
blueswir1992f48a2007-10-14 16:27:31 +00001916 abi_long ret;
1917 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00001918
1919 switch(num) {
1920 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00001921 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001922 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00001923
Ulrich Hecht98818182009-07-03 17:09:28 +02001924 if (get_user_ual(domain, vptr)
1925 || get_user_ual(type, vptr + n)
1926 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001927 return -TARGET_EFAULT;
1928
bellard3532fa72006-06-24 15:06:03 +00001929 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00001930 }
bellard31e31b82003-02-18 22:55:36 +00001931 break;
1932 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00001933 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001934 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001935 abi_ulong target_addr;
1936 socklen_t addrlen;
1937
Ulrich Hecht98818182009-07-03 17:09:28 +02001938 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001939 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001940 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001941 return -TARGET_EFAULT;
1942
bellard3532fa72006-06-24 15:06:03 +00001943 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00001944 }
bellard31e31b82003-02-18 22:55:36 +00001945 break;
1946 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00001947 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001948 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001949 abi_ulong target_addr;
1950 socklen_t addrlen;
1951
Ulrich Hecht98818182009-07-03 17:09:28 +02001952 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001953 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001954 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001955 return -TARGET_EFAULT;
1956
bellard3532fa72006-06-24 15:06:03 +00001957 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00001958 }
bellard31e31b82003-02-18 22:55:36 +00001959 break;
1960 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00001961 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001962 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00001963
Ulrich Hecht98818182009-07-03 17:09:28 +02001964 if (get_user_ual(sockfd, vptr)
1965 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00001966 return -TARGET_EFAULT;
1967
bellard7854b052003-03-29 17:22:23 +00001968 ret = get_errno(listen(sockfd, backlog));
1969 }
bellard31e31b82003-02-18 22:55:36 +00001970 break;
1971 case SOCKOP_accept:
1972 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001973 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001974 abi_ulong target_addr, target_addrlen;
1975
Ulrich Hecht98818182009-07-03 17:09:28 +02001976 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001977 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001978 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001979 return -TARGET_EFAULT;
1980
pbrook1be9e1d2006-11-19 15:26:04 +00001981 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00001982 }
1983 break;
1984 case SOCKOP_getsockname:
1985 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001986 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001987 abi_ulong target_addr, target_addrlen;
1988
Ulrich Hecht98818182009-07-03 17:09:28 +02001989 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001990 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001991 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001992 return -TARGET_EFAULT;
1993
pbrook1be9e1d2006-11-19 15:26:04 +00001994 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00001995 }
1996 break;
1997 case SOCKOP_getpeername:
1998 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001999 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002000 abi_ulong target_addr, target_addrlen;
2001
Ulrich Hecht98818182009-07-03 17:09:28 +02002002 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002003 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002004 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002005 return -TARGET_EFAULT;
2006
pbrook1be9e1d2006-11-19 15:26:04 +00002007 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002008 }
2009 break;
2010 case SOCKOP_socketpair:
2011 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002012 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002013 abi_ulong tab;
2014
Ulrich Hecht98818182009-07-03 17:09:28 +02002015 if (get_user_ual(domain, vptr)
2016 || get_user_ual(type, vptr + n)
2017 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002018 || get_user_ual(tab, vptr + 3 * n))
2019 return -TARGET_EFAULT;
2020
pbrook1be9e1d2006-11-19 15:26:04 +00002021 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002022 }
2023 break;
2024 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002025 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002026 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002027 abi_ulong msg;
2028 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002029 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002030
Ulrich Hecht98818182009-07-03 17:09:28 +02002031 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002032 || get_user_ual(msg, vptr + n)
2033 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002034 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002035 return -TARGET_EFAULT;
2036
pbrook1be9e1d2006-11-19 15:26:04 +00002037 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002038 }
bellard31e31b82003-02-18 22:55:36 +00002039 break;
2040 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002041 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002042 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002043 abi_ulong msg;
2044 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002045 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002046
Ulrich Hecht98818182009-07-03 17:09:28 +02002047 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002048 || get_user_ual(msg, vptr + n)
2049 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002050 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002051 return -TARGET_EFAULT;
2052
pbrook1be9e1d2006-11-19 15:26:04 +00002053 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002054 }
bellard31e31b82003-02-18 22:55:36 +00002055 break;
2056 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002057 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002058 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002059 abi_ulong msg;
2060 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002061 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002062 abi_ulong addr;
2063 socklen_t addrlen;
2064
Ulrich Hecht98818182009-07-03 17:09:28 +02002065 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002066 || get_user_ual(msg, vptr + n)
2067 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002068 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002069 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002070 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002071 return -TARGET_EFAULT;
2072
pbrook1be9e1d2006-11-19 15:26:04 +00002073 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002074 }
bellard31e31b82003-02-18 22:55:36 +00002075 break;
2076 case SOCKOP_recvfrom:
2077 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002078 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002079 abi_ulong msg;
2080 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002081 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002082 abi_ulong addr;
2083 socklen_t addrlen;
2084
Ulrich Hecht98818182009-07-03 17:09:28 +02002085 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002086 || get_user_ual(msg, vptr + n)
2087 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002088 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002089 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002090 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002091 return -TARGET_EFAULT;
2092
pbrook1be9e1d2006-11-19 15:26:04 +00002093 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002094 }
2095 break;
2096 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002097 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002098 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002099
Ulrich Hecht98818182009-07-03 17:09:28 +02002100 if (get_user_ual(sockfd, vptr)
2101 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002102 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002103
2104 ret = get_errno(shutdown(sockfd, how));
2105 }
bellard31e31b82003-02-18 22:55:36 +00002106 break;
2107 case SOCKOP_sendmsg:
2108 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002109 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002110 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002111 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002112 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002113
Ulrich Hecht98818182009-07-03 17:09:28 +02002114 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002115 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002116 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002117 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002118
ths5fafdf22007-09-16 21:08:06 +00002119 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002120 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002121 }
2122 break;
bellard31e31b82003-02-18 22:55:36 +00002123 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002124 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002125 abi_ulong sockfd;
2126 abi_ulong level;
2127 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002128 abi_ulong optval;
2129 socklen_t optlen;
2130
Ulrich Hecht98818182009-07-03 17:09:28 +02002131 if (get_user_ual(sockfd, vptr)
2132 || get_user_ual(level, vptr + n)
2133 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002134 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002135 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002136 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002137
2138 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2139 }
2140 break;
bellard31e31b82003-02-18 22:55:36 +00002141 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002142 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002143 abi_ulong sockfd;
2144 abi_ulong level;
2145 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002146 abi_ulong optval;
2147 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002148
Ulrich Hecht98818182009-07-03 17:09:28 +02002149 if (get_user_ual(sockfd, vptr)
2150 || get_user_ual(level, vptr + n)
2151 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002152 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002153 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002154 return -TARGET_EFAULT;
2155
2156 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002157 }
2158 break;
bellard31e31b82003-02-18 22:55:36 +00002159 default:
2160 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002161 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002162 break;
2163 }
2164 return ret;
2165}
j_mayer32407102007-09-26 23:01:49 +00002166#endif
bellard31e31b82003-02-18 22:55:36 +00002167
bellard8853f862004-02-22 14:57:26 +00002168#define N_SHM_REGIONS 32
2169
2170static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002171 abi_ulong start;
2172 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002173} shm_regions[N_SHM_REGIONS];
2174
ths3eb6b042007-06-03 14:26:27 +00002175struct target_ipc_perm
2176{
blueswir1992f48a2007-10-14 16:27:31 +00002177 abi_long __key;
2178 abi_ulong uid;
2179 abi_ulong gid;
2180 abi_ulong cuid;
2181 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002182 unsigned short int mode;
2183 unsigned short int __pad1;
2184 unsigned short int __seq;
2185 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002186 abi_ulong __unused1;
2187 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002188};
2189
2190struct target_semid_ds
2191{
2192 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002193 abi_ulong sem_otime;
2194 abi_ulong __unused1;
2195 abi_ulong sem_ctime;
2196 abi_ulong __unused2;
2197 abi_ulong sem_nsems;
2198 abi_ulong __unused3;
2199 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002200};
2201
bellard579a97f2007-11-11 14:26:47 +00002202static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2203 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002204{
2205 struct target_ipc_perm *target_ip;
2206 struct target_semid_ds *target_sd;
2207
bellard579a97f2007-11-11 14:26:47 +00002208 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2209 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002210 target_ip = &(target_sd->sem_perm);
ths3eb6b042007-06-03 14:26:27 +00002211 host_ip->__key = tswapl(target_ip->__key);
2212 host_ip->uid = tswapl(target_ip->uid);
2213 host_ip->gid = tswapl(target_ip->gid);
2214 host_ip->cuid = tswapl(target_ip->cuid);
2215 host_ip->cgid = tswapl(target_ip->cgid);
2216 host_ip->mode = tswapl(target_ip->mode);
2217 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002218 return 0;
ths3eb6b042007-06-03 14:26:27 +00002219}
2220
bellard579a97f2007-11-11 14:26:47 +00002221static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2222 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002223{
2224 struct target_ipc_perm *target_ip;
2225 struct target_semid_ds *target_sd;
2226
bellard579a97f2007-11-11 14:26:47 +00002227 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2228 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002229 target_ip = &(target_sd->sem_perm);
2230 target_ip->__key = tswapl(host_ip->__key);
2231 target_ip->uid = tswapl(host_ip->uid);
2232 target_ip->gid = tswapl(host_ip->gid);
2233 target_ip->cuid = tswapl(host_ip->cuid);
2234 target_ip->cgid = tswapl(host_ip->cgid);
2235 target_ip->mode = tswapl(host_ip->mode);
2236 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002237 return 0;
ths3eb6b042007-06-03 14:26:27 +00002238}
2239
bellard579a97f2007-11-11 14:26:47 +00002240static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2241 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002242{
2243 struct target_semid_ds *target_sd;
2244
bellard579a97f2007-11-11 14:26:47 +00002245 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2246 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002247 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2248 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002249 host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
2250 host_sd->sem_otime = tswapl(target_sd->sem_otime);
2251 host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
2252 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002253 return 0;
ths3eb6b042007-06-03 14:26:27 +00002254}
2255
bellard579a97f2007-11-11 14:26:47 +00002256static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2257 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002258{
2259 struct target_semid_ds *target_sd;
2260
bellard579a97f2007-11-11 14:26:47 +00002261 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2262 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002263 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2264 return -TARGET_EFAULT;;
ths3eb6b042007-06-03 14:26:27 +00002265 target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
2266 target_sd->sem_otime = tswapl(host_sd->sem_otime);
2267 target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
2268 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002269 return 0;
ths3eb6b042007-06-03 14:26:27 +00002270}
2271
aurel32e5289082009-04-18 16:16:12 +00002272struct target_seminfo {
2273 int semmap;
2274 int semmni;
2275 int semmns;
2276 int semmnu;
2277 int semmsl;
2278 int semopm;
2279 int semume;
2280 int semusz;
2281 int semvmx;
2282 int semaem;
2283};
2284
2285static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2286 struct seminfo *host_seminfo)
2287{
2288 struct target_seminfo *target_seminfo;
2289 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2290 return -TARGET_EFAULT;
2291 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2292 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2293 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2294 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2295 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2296 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2297 __put_user(host_seminfo->semume, &target_seminfo->semume);
2298 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2299 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2300 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2301 unlock_user_struct(target_seminfo, target_addr, 1);
2302 return 0;
2303}
2304
thsfa294812007-02-02 22:05:00 +00002305union semun {
2306 int val;
ths3eb6b042007-06-03 14:26:27 +00002307 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002308 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002309 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002310};
2311
ths3eb6b042007-06-03 14:26:27 +00002312union target_semun {
2313 int val;
aurel32e5289082009-04-18 16:16:12 +00002314 abi_ulong buf;
2315 abi_ulong array;
2316 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002317};
2318
aurel32e5289082009-04-18 16:16:12 +00002319static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2320 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002321{
aurel32e5289082009-04-18 16:16:12 +00002322 int nsems;
2323 unsigned short *array;
2324 union semun semun;
2325 struct semid_ds semid_ds;
2326 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002327
aurel32e5289082009-04-18 16:16:12 +00002328 semun.buf = &semid_ds;
2329
2330 ret = semctl(semid, 0, IPC_STAT, semun);
2331 if (ret == -1)
2332 return get_errno(ret);
2333
2334 nsems = semid_ds.sem_nsems;
2335
2336 *host_array = malloc(nsems*sizeof(unsigned short));
2337 array = lock_user(VERIFY_READ, target_addr,
2338 nsems*sizeof(unsigned short), 1);
2339 if (!array)
2340 return -TARGET_EFAULT;
2341
2342 for(i=0; i<nsems; i++) {
2343 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002344 }
aurel32e5289082009-04-18 16:16:12 +00002345 unlock_user(array, target_addr, 0);
2346
bellard579a97f2007-11-11 14:26:47 +00002347 return 0;
ths3eb6b042007-06-03 14:26:27 +00002348}
2349
aurel32e5289082009-04-18 16:16:12 +00002350static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2351 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002352{
aurel32e5289082009-04-18 16:16:12 +00002353 int nsems;
2354 unsigned short *array;
2355 union semun semun;
2356 struct semid_ds semid_ds;
2357 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002358
aurel32e5289082009-04-18 16:16:12 +00002359 semun.buf = &semid_ds;
2360
2361 ret = semctl(semid, 0, IPC_STAT, semun);
2362 if (ret == -1)
2363 return get_errno(ret);
2364
2365 nsems = semid_ds.sem_nsems;
2366
2367 array = lock_user(VERIFY_WRITE, target_addr,
2368 nsems*sizeof(unsigned short), 0);
2369 if (!array)
2370 return -TARGET_EFAULT;
2371
2372 for(i=0; i<nsems; i++) {
2373 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002374 }
aurel32e5289082009-04-18 16:16:12 +00002375 free(*host_array);
2376 unlock_user(array, target_addr, 1);
2377
bellard579a97f2007-11-11 14:26:47 +00002378 return 0;
ths3eb6b042007-06-03 14:26:27 +00002379}
2380
aurel32e5289082009-04-18 16:16:12 +00002381static inline abi_long do_semctl(int semid, int semnum, int cmd,
2382 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002383{
2384 union semun arg;
2385 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302386 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002387 struct seminfo seminfo;
2388 abi_long ret = -TARGET_EINVAL;
2389 abi_long err;
2390 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002391
2392 switch( cmd ) {
2393 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002394 case SETVAL:
aurel32e5289082009-04-18 16:16:12 +00002395 arg.val = tswapl(target_su.val);
2396 ret = get_errno(semctl(semid, semnum, cmd, arg));
2397 target_su.val = tswapl(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002398 break;
2399 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002400 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002401 err = target_to_host_semarray(semid, &array, target_su.array);
2402 if (err)
2403 return err;
2404 arg.array = array;
2405 ret = get_errno(semctl(semid, semnum, cmd, arg));
2406 err = host_to_target_semarray(semid, target_su.array, &array);
2407 if (err)
2408 return err;
ths3eb6b042007-06-03 14:26:27 +00002409 break;
2410 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002411 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002412 case SEM_STAT:
2413 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2414 if (err)
2415 return err;
2416 arg.buf = &dsarg;
2417 ret = get_errno(semctl(semid, semnum, cmd, arg));
2418 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2419 if (err)
2420 return err;
ths3eb6b042007-06-03 14:26:27 +00002421 break;
aurel32e5289082009-04-18 16:16:12 +00002422 case IPC_INFO:
2423 case SEM_INFO:
2424 arg.__buf = &seminfo;
2425 ret = get_errno(semctl(semid, semnum, cmd, arg));
2426 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2427 if (err)
2428 return err;
2429 break;
2430 case IPC_RMID:
2431 case GETPID:
2432 case GETNCNT:
2433 case GETZCNT:
2434 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2435 break;
ths3eb6b042007-06-03 14:26:27 +00002436 }
2437
2438 return ret;
2439}
2440
aurel32e5289082009-04-18 16:16:12 +00002441struct target_sembuf {
2442 unsigned short sem_num;
2443 short sem_op;
2444 short sem_flg;
2445};
2446
2447static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2448 abi_ulong target_addr,
2449 unsigned nsops)
2450{
2451 struct target_sembuf *target_sembuf;
2452 int i;
2453
2454 target_sembuf = lock_user(VERIFY_READ, target_addr,
2455 nsops*sizeof(struct target_sembuf), 1);
2456 if (!target_sembuf)
2457 return -TARGET_EFAULT;
2458
2459 for(i=0; i<nsops; i++) {
2460 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2461 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2462 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2463 }
2464
2465 unlock_user(target_sembuf, target_addr, 0);
2466
2467 return 0;
2468}
2469
2470static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2471{
2472 struct sembuf sops[nsops];
2473
2474 if (target_to_host_sembuf(sops, ptr, nsops))
2475 return -TARGET_EFAULT;
2476
2477 return semop(semid, sops, nsops);
2478}
2479
ths1bc012f2007-06-03 14:27:49 +00002480struct target_msqid_ds
2481{
aurel321c54ff92008-10-13 21:08:44 +00002482 struct target_ipc_perm msg_perm;
2483 abi_ulong msg_stime;
2484#if TARGET_ABI_BITS == 32
2485 abi_ulong __unused1;
2486#endif
2487 abi_ulong msg_rtime;
2488#if TARGET_ABI_BITS == 32
2489 abi_ulong __unused2;
2490#endif
2491 abi_ulong msg_ctime;
2492#if TARGET_ABI_BITS == 32
2493 abi_ulong __unused3;
2494#endif
2495 abi_ulong __msg_cbytes;
2496 abi_ulong msg_qnum;
2497 abi_ulong msg_qbytes;
2498 abi_ulong msg_lspid;
2499 abi_ulong msg_lrpid;
2500 abi_ulong __unused4;
2501 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002502};
2503
bellard579a97f2007-11-11 14:26:47 +00002504static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2505 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002506{
2507 struct target_msqid_ds *target_md;
2508
bellard579a97f2007-11-11 14:26:47 +00002509 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2510 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002511 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2512 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002513 host_md->msg_stime = tswapl(target_md->msg_stime);
2514 host_md->msg_rtime = tswapl(target_md->msg_rtime);
2515 host_md->msg_ctime = tswapl(target_md->msg_ctime);
2516 host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
2517 host_md->msg_qnum = tswapl(target_md->msg_qnum);
2518 host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
2519 host_md->msg_lspid = tswapl(target_md->msg_lspid);
2520 host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
2521 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002522 return 0;
ths1bc012f2007-06-03 14:27:49 +00002523}
2524
bellard579a97f2007-11-11 14:26:47 +00002525static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2526 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002527{
2528 struct target_msqid_ds *target_md;
2529
bellard579a97f2007-11-11 14:26:47 +00002530 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2531 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002532 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2533 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002534 target_md->msg_stime = tswapl(host_md->msg_stime);
2535 target_md->msg_rtime = tswapl(host_md->msg_rtime);
2536 target_md->msg_ctime = tswapl(host_md->msg_ctime);
2537 target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
2538 target_md->msg_qnum = tswapl(host_md->msg_qnum);
2539 target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
2540 target_md->msg_lspid = tswapl(host_md->msg_lspid);
2541 target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
2542 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002543 return 0;
ths1bc012f2007-06-03 14:27:49 +00002544}
2545
aurel321c54ff92008-10-13 21:08:44 +00002546struct target_msginfo {
2547 int msgpool;
2548 int msgmap;
2549 int msgmax;
2550 int msgmnb;
2551 int msgmni;
2552 int msgssz;
2553 int msgtql;
2554 unsigned short int msgseg;
2555};
2556
2557static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2558 struct msginfo *host_msginfo)
2559{
2560 struct target_msginfo *target_msginfo;
2561 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2562 return -TARGET_EFAULT;
2563 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2564 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2565 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2566 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2567 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2568 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2569 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2570 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2571 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002572 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002573}
2574
2575static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002576{
2577 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002578 struct msginfo msginfo;
2579 abi_long ret = -TARGET_EINVAL;
2580
2581 cmd &= 0xff;
2582
2583 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002584 case IPC_STAT:
2585 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002586 case MSG_STAT:
2587 if (target_to_host_msqid_ds(&dsarg,ptr))
2588 return -TARGET_EFAULT;
2589 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2590 if (host_to_target_msqid_ds(ptr,&dsarg))
2591 return -TARGET_EFAULT;
2592 break;
2593 case IPC_RMID:
2594 ret = get_errno(msgctl(msgid, cmd, NULL));
2595 break;
2596 case IPC_INFO:
2597 case MSG_INFO:
2598 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2599 if (host_to_target_msginfo(ptr, &msginfo))
2600 return -TARGET_EFAULT;
2601 break;
ths1bc012f2007-06-03 14:27:49 +00002602 }
aurel321c54ff92008-10-13 21:08:44 +00002603
ths1bc012f2007-06-03 14:27:49 +00002604 return ret;
2605}
2606
2607struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002608 abi_long mtype;
2609 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002610};
2611
blueswir1992f48a2007-10-14 16:27:31 +00002612static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2613 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002614{
2615 struct target_msgbuf *target_mb;
2616 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002617 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002618
bellard579a97f2007-11-11 14:26:47 +00002619 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2620 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002621 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002622 host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
2623 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002624 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2625 free(host_mb);
2626 unlock_user_struct(target_mb, msgp, 0);
2627
2628 return ret;
2629}
2630
blueswir1992f48a2007-10-14 16:27:31 +00002631static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002632 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002633 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002634{
2635 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002636 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002637 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002638 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002639
bellard579a97f2007-11-11 14:26:47 +00002640 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2641 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002642
ths1bc012f2007-06-03 14:27:49 +00002643 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002644 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
2645
bellard579a97f2007-11-11 14:26:47 +00002646 if (ret > 0) {
2647 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2648 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2649 if (!target_mtext) {
2650 ret = -TARGET_EFAULT;
2651 goto end;
2652 }
aurel321c54ff92008-10-13 21:08:44 +00002653 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002654 unlock_user(target_mtext, target_mtext_addr, ret);
2655 }
aurel321c54ff92008-10-13 21:08:44 +00002656
ths1bc012f2007-06-03 14:27:49 +00002657 target_mb->mtype = tswapl(host_mb->mtype);
2658 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002659
bellard579a97f2007-11-11 14:26:47 +00002660end:
2661 if (target_mb)
2662 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002663 return ret;
2664}
2665
Riku Voipio88a8c982009-04-03 10:42:00 +03002666struct target_shmid_ds
2667{
2668 struct target_ipc_perm shm_perm;
2669 abi_ulong shm_segsz;
2670 abi_ulong shm_atime;
2671#if TARGET_ABI_BITS == 32
2672 abi_ulong __unused1;
2673#endif
2674 abi_ulong shm_dtime;
2675#if TARGET_ABI_BITS == 32
2676 abi_ulong __unused2;
2677#endif
2678 abi_ulong shm_ctime;
2679#if TARGET_ABI_BITS == 32
2680 abi_ulong __unused3;
2681#endif
2682 int shm_cpid;
2683 int shm_lpid;
2684 abi_ulong shm_nattch;
2685 unsigned long int __unused4;
2686 unsigned long int __unused5;
2687};
2688
2689static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2690 abi_ulong target_addr)
2691{
2692 struct target_shmid_ds *target_sd;
2693
2694 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2695 return -TARGET_EFAULT;
2696 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2697 return -TARGET_EFAULT;
2698 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2699 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2700 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2701 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2702 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2703 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2704 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2705 unlock_user_struct(target_sd, target_addr, 0);
2706 return 0;
2707}
2708
2709static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2710 struct shmid_ds *host_sd)
2711{
2712 struct target_shmid_ds *target_sd;
2713
2714 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2715 return -TARGET_EFAULT;
2716 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2717 return -TARGET_EFAULT;
2718 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2719 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2720 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2721 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2722 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2723 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2724 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2725 unlock_user_struct(target_sd, target_addr, 1);
2726 return 0;
2727}
2728
2729struct target_shminfo {
2730 abi_ulong shmmax;
2731 abi_ulong shmmin;
2732 abi_ulong shmmni;
2733 abi_ulong shmseg;
2734 abi_ulong shmall;
2735};
2736
2737static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2738 struct shminfo *host_shminfo)
2739{
2740 struct target_shminfo *target_shminfo;
2741 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2742 return -TARGET_EFAULT;
2743 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2744 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2745 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2746 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2747 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2748 unlock_user_struct(target_shminfo, target_addr, 1);
2749 return 0;
2750}
2751
2752struct target_shm_info {
2753 int used_ids;
2754 abi_ulong shm_tot;
2755 abi_ulong shm_rss;
2756 abi_ulong shm_swp;
2757 abi_ulong swap_attempts;
2758 abi_ulong swap_successes;
2759};
2760
2761static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2762 struct shm_info *host_shm_info)
2763{
2764 struct target_shm_info *target_shm_info;
2765 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2766 return -TARGET_EFAULT;
2767 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2768 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2769 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2770 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2771 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2772 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2773 unlock_user_struct(target_shm_info, target_addr, 1);
2774 return 0;
2775}
2776
2777static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2778{
2779 struct shmid_ds dsarg;
2780 struct shminfo shminfo;
2781 struct shm_info shm_info;
2782 abi_long ret = -TARGET_EINVAL;
2783
2784 cmd &= 0xff;
2785
2786 switch(cmd) {
2787 case IPC_STAT:
2788 case IPC_SET:
2789 case SHM_STAT:
2790 if (target_to_host_shmid_ds(&dsarg, buf))
2791 return -TARGET_EFAULT;
2792 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2793 if (host_to_target_shmid_ds(buf, &dsarg))
2794 return -TARGET_EFAULT;
2795 break;
2796 case IPC_INFO:
2797 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2798 if (host_to_target_shminfo(buf, &shminfo))
2799 return -TARGET_EFAULT;
2800 break;
2801 case SHM_INFO:
2802 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2803 if (host_to_target_shm_info(buf, &shm_info))
2804 return -TARGET_EFAULT;
2805 break;
2806 case IPC_RMID:
2807 case SHM_LOCK:
2808 case SHM_UNLOCK:
2809 ret = get_errno(shmctl(shmid, cmd, NULL));
2810 break;
2811 }
2812
2813 return ret;
2814}
2815
2816static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2817{
2818 abi_long raddr;
2819 void *host_raddr;
2820 struct shmid_ds shm_info;
2821 int i,ret;
2822
2823 /* find out the length of the shared memory segment */
2824 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2825 if (is_error(ret)) {
2826 /* can't get length, bail out */
2827 return ret;
2828 }
2829
2830 mmap_lock();
2831
2832 if (shmaddr)
2833 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2834 else {
2835 abi_ulong mmap_start;
2836
2837 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2838
2839 if (mmap_start == -1) {
2840 errno = ENOMEM;
2841 host_raddr = (void *)-1;
2842 } else
2843 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2844 }
2845
2846 if (host_raddr == (void *)-1) {
2847 mmap_unlock();
2848 return get_errno((long)host_raddr);
2849 }
2850 raddr=h2g((unsigned long)host_raddr);
2851
2852 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2853 PAGE_VALID | PAGE_READ |
2854 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2855
2856 for (i = 0; i < N_SHM_REGIONS; i++) {
2857 if (shm_regions[i].start == 0) {
2858 shm_regions[i].start = raddr;
2859 shm_regions[i].size = shm_info.shm_segsz;
2860 break;
2861 }
2862 }
2863
2864 mmap_unlock();
2865 return raddr;
2866
2867}
2868
2869static inline abi_long do_shmdt(abi_ulong shmaddr)
2870{
2871 int i;
2872
2873 for (i = 0; i < N_SHM_REGIONS; ++i) {
2874 if (shm_regions[i].start == shmaddr) {
2875 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09002876 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03002877 break;
2878 }
2879 }
2880
2881 return get_errno(shmdt(g2h(shmaddr)));
2882}
2883
aurel321c54ff92008-10-13 21:08:44 +00002884#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00002885/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00002886/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002887static abi_long do_ipc(unsigned int call, int first,
2888 int second, int third,
2889 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00002890{
2891 int version;
blueswir1992f48a2007-10-14 16:27:31 +00002892 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00002893
2894 version = call >> 16;
2895 call &= 0xffff;
2896
2897 switch (call) {
thsfa294812007-02-02 22:05:00 +00002898 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00002899 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00002900 break;
2901
2902 case IPCOP_semget:
2903 ret = get_errno(semget(first, second, third));
2904 break;
2905
2906 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00002907 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00002908 break;
thsd96372e2007-02-02 22:05:44 +00002909
aurel321c54ff92008-10-13 21:08:44 +00002910 case IPCOP_msgget:
2911 ret = get_errno(msgget(first, second));
2912 break;
thsd96372e2007-02-02 22:05:44 +00002913
aurel321c54ff92008-10-13 21:08:44 +00002914 case IPCOP_msgsnd:
2915 ret = do_msgsnd(first, ptr, second, third);
2916 break;
thsd96372e2007-02-02 22:05:44 +00002917
aurel321c54ff92008-10-13 21:08:44 +00002918 case IPCOP_msgctl:
2919 ret = do_msgctl(first, second, ptr);
2920 break;
thsd96372e2007-02-02 22:05:44 +00002921
aurel321c54ff92008-10-13 21:08:44 +00002922 case IPCOP_msgrcv:
2923 switch (version) {
2924 case 0:
2925 {
2926 struct target_ipc_kludge {
2927 abi_long msgp;
2928 abi_long msgtyp;
2929 } *tmp;
thsd96372e2007-02-02 22:05:44 +00002930
aurel321c54ff92008-10-13 21:08:44 +00002931 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
2932 ret = -TARGET_EFAULT;
2933 break;
ths1bc012f2007-06-03 14:27:49 +00002934 }
aurel321c54ff92008-10-13 21:08:44 +00002935
2936 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
2937
2938 unlock_user_struct(tmp, ptr, 0);
2939 break;
2940 }
2941 default:
2942 ret = do_msgrcv(first, ptr, second, fifth, third);
2943 }
2944 break;
thsd96372e2007-02-02 22:05:44 +00002945
bellard8853f862004-02-22 14:57:26 +00002946 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03002947 switch (version) {
2948 default:
bellard5a4a8982007-11-11 17:39:18 +00002949 {
2950 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03002951 raddr = do_shmat(first, ptr, second);
2952 if (is_error(raddr))
2953 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00002954 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00002955 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03002956 break;
2957 }
2958 case 1:
2959 ret = -TARGET_EINVAL;
2960 break;
bellard5a4a8982007-11-11 17:39:18 +00002961 }
bellard8853f862004-02-22 14:57:26 +00002962 break;
2963 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03002964 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00002965 break;
2966
2967 case IPCOP_shmget:
2968 /* IPC_* flag values are the same on all linux platforms */
2969 ret = get_errno(shmget(first, second, third));
2970 break;
2971
2972 /* IPC_* and SHM_* command values are the same on all linux platforms */
2973 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03002974 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00002975 break;
2976 default:
j_mayer32407102007-09-26 23:01:49 +00002977 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00002978 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00002979 break;
2980 }
2981 return ret;
2982}
j_mayer32407102007-09-26 23:01:49 +00002983#endif
bellard8853f862004-02-22 14:57:26 +00002984
bellard31e31b82003-02-18 22:55:36 +00002985/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00002986
Blue Swirl001faf32009-05-13 17:53:17 +00002987#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00002988#define STRUCT_SPECIAL(name) STRUCT_ ## name,
2989enum {
2990#include "syscall_types.h"
2991};
2992#undef STRUCT
2993#undef STRUCT_SPECIAL
2994
Blue Swirl001faf32009-05-13 17:53:17 +00002995#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00002996#define STRUCT_SPECIAL(name)
2997#include "syscall_types.h"
2998#undef STRUCT
2999#undef STRUCT_SPECIAL
3000
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003001typedef struct IOCTLEntry IOCTLEntry;
3002
3003typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3004 int fd, abi_long cmd, abi_long arg);
3005
3006struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003007 unsigned int target_cmd;
3008 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003009 const char *name;
3010 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003011 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003012 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003013};
bellard31e31b82003-02-18 22:55:36 +00003014
3015#define IOC_R 0x0001
3016#define IOC_W 0x0002
3017#define IOC_RW (IOC_R | IOC_W)
3018
3019#define MAX_STRUCT_SIZE 4096
3020
Peter Maydelldace20d2011-01-10 13:11:24 +00003021#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003022/* So fiemap access checks don't overflow on 32 bit systems.
3023 * This is very slightly smaller than the limit imposed by
3024 * the underlying kernel.
3025 */
3026#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3027 / sizeof(struct fiemap_extent))
3028
3029static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3030 int fd, abi_long cmd, abi_long arg)
3031{
3032 /* The parameter for this ioctl is a struct fiemap followed
3033 * by an array of struct fiemap_extent whose size is set
3034 * in fiemap->fm_extent_count. The array is filled in by the
3035 * ioctl.
3036 */
3037 int target_size_in, target_size_out;
3038 struct fiemap *fm;
3039 const argtype *arg_type = ie->arg_type;
3040 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3041 void *argptr, *p;
3042 abi_long ret;
3043 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3044 uint32_t outbufsz;
3045 int free_fm = 0;
3046
3047 assert(arg_type[0] == TYPE_PTR);
3048 assert(ie->access == IOC_RW);
3049 arg_type++;
3050 target_size_in = thunk_type_size(arg_type, 0);
3051 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3052 if (!argptr) {
3053 return -TARGET_EFAULT;
3054 }
3055 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3056 unlock_user(argptr, arg, 0);
3057 fm = (struct fiemap *)buf_temp;
3058 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3059 return -TARGET_EINVAL;
3060 }
3061
3062 outbufsz = sizeof (*fm) +
3063 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3064
3065 if (outbufsz > MAX_STRUCT_SIZE) {
3066 /* We can't fit all the extents into the fixed size buffer.
3067 * Allocate one that is large enough and use it instead.
3068 */
3069 fm = malloc(outbufsz);
3070 if (!fm) {
3071 return -TARGET_ENOMEM;
3072 }
3073 memcpy(fm, buf_temp, sizeof(struct fiemap));
3074 free_fm = 1;
3075 }
3076 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3077 if (!is_error(ret)) {
3078 target_size_out = target_size_in;
3079 /* An extent_count of 0 means we were only counting the extents
3080 * so there are no structs to copy
3081 */
3082 if (fm->fm_extent_count != 0) {
3083 target_size_out += fm->fm_mapped_extents * extent_size;
3084 }
3085 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3086 if (!argptr) {
3087 ret = -TARGET_EFAULT;
3088 } else {
3089 /* Convert the struct fiemap */
3090 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3091 if (fm->fm_extent_count != 0) {
3092 p = argptr + target_size_in;
3093 /* ...and then all the struct fiemap_extents */
3094 for (i = 0; i < fm->fm_mapped_extents; i++) {
3095 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3096 THUNK_TARGET);
3097 p += extent_size;
3098 }
3099 }
3100 unlock_user(argptr, arg, target_size_out);
3101 }
3102 }
3103 if (free_fm) {
3104 free(fm);
3105 }
3106 return ret;
3107}
Peter Maydelldace20d2011-01-10 13:11:24 +00003108#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003109
Laurent Vivier059c2f22011-03-30 00:12:12 +02003110static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3111 int fd, abi_long cmd, abi_long arg)
3112{
3113 const argtype *arg_type = ie->arg_type;
3114 int target_size;
3115 void *argptr;
3116 int ret;
3117 struct ifconf *host_ifconf;
3118 uint32_t outbufsz;
3119 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3120 int target_ifreq_size;
3121 int nb_ifreq;
3122 int free_buf = 0;
3123 int i;
3124 int target_ifc_len;
3125 abi_long target_ifc_buf;
3126 int host_ifc_len;
3127 char *host_ifc_buf;
3128
3129 assert(arg_type[0] == TYPE_PTR);
3130 assert(ie->access == IOC_RW);
3131
3132 arg_type++;
3133 target_size = thunk_type_size(arg_type, 0);
3134
3135 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3136 if (!argptr)
3137 return -TARGET_EFAULT;
3138 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3139 unlock_user(argptr, arg, 0);
3140
3141 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3142 target_ifc_len = host_ifconf->ifc_len;
3143 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3144
3145 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3146 nb_ifreq = target_ifc_len / target_ifreq_size;
3147 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3148
3149 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3150 if (outbufsz > MAX_STRUCT_SIZE) {
3151 /* We can't fit all the extents into the fixed size buffer.
3152 * Allocate one that is large enough and use it instead.
3153 */
3154 host_ifconf = malloc(outbufsz);
3155 if (!host_ifconf) {
3156 return -TARGET_ENOMEM;
3157 }
3158 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3159 free_buf = 1;
3160 }
3161 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3162
3163 host_ifconf->ifc_len = host_ifc_len;
3164 host_ifconf->ifc_buf = host_ifc_buf;
3165
3166 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3167 if (!is_error(ret)) {
3168 /* convert host ifc_len to target ifc_len */
3169
3170 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3171 target_ifc_len = nb_ifreq * target_ifreq_size;
3172 host_ifconf->ifc_len = target_ifc_len;
3173
3174 /* restore target ifc_buf */
3175
3176 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3177
3178 /* copy struct ifconf to target user */
3179
3180 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3181 if (!argptr)
3182 return -TARGET_EFAULT;
3183 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3184 unlock_user(argptr, arg, target_size);
3185
3186 /* copy ifreq[] to target user */
3187
3188 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3189 for (i = 0; i < nb_ifreq ; i++) {
3190 thunk_convert(argptr + i * target_ifreq_size,
3191 host_ifc_buf + i * sizeof(struct ifreq),
3192 ifreq_arg_type, THUNK_TARGET);
3193 }
3194 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3195 }
3196
3197 if (free_buf) {
3198 free(host_ifconf);
3199 }
3200
3201 return ret;
3202}
3203
blueswir19f106a72008-10-05 10:52:52 +00003204static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003205#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003206 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3207#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3208 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003209#include "ioctls.h"
3210 { 0, 0, },
3211};
3212
pbrook53a59602006-03-25 19:31:22 +00003213/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003214/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003215static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003216{
3217 const IOCTLEntry *ie;
3218 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003219 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003220 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003221 int target_size;
3222 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003223
3224 ie = ioctl_entries;
3225 for(;;) {
3226 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003227 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003228 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003229 }
3230 if (ie->target_cmd == cmd)
3231 break;
3232 ie++;
3233 }
3234 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003235#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003236 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003237#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003238 if (ie->do_ioctl) {
3239 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3240 }
3241
bellard31e31b82003-02-18 22:55:36 +00003242 switch(arg_type[0]) {
3243 case TYPE_NULL:
3244 /* no argument */
3245 ret = get_errno(ioctl(fd, ie->host_cmd));
3246 break;
3247 case TYPE_PTRVOID:
3248 case TYPE_INT:
3249 /* int argment */
3250 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3251 break;
3252 case TYPE_PTR:
3253 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003254 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003255 switch(ie->access) {
3256 case IOC_R:
3257 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3258 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003259 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3260 if (!argptr)
3261 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003262 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3263 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003264 }
3265 break;
3266 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003267 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3268 if (!argptr)
3269 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003270 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3271 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003272 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3273 break;
3274 default:
3275 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003276 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3277 if (!argptr)
3278 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003279 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3280 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003281 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3282 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003283 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3284 if (!argptr)
3285 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003286 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3287 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003288 }
3289 break;
3290 }
3291 break;
3292 default:
j_mayer32407102007-09-26 23:01:49 +00003293 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3294 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003295 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003296 break;
3297 }
3298 return ret;
3299}
3300
blueswir1b39bc502008-10-05 10:51:10 +00003301static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003302 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3303 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3304 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3305 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3306 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3307 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3308 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3309 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3310 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3311 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3312 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3313 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3314 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3315 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3316 { 0, 0, 0, 0 }
3317};
3318
blueswir1b39bc502008-10-05 10:51:10 +00003319static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003320 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3321 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3322 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3323 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3324 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3325 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3326 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3327 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3328 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3329 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3330 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3331 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3332 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3333 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3334 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3335 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3336 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3337 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3338 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3339 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3340 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3341 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3342 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3343 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3344 { 0, 0, 0, 0 }
3345};
3346
blueswir1b39bc502008-10-05 10:51:10 +00003347static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003348 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3349 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3350 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3351 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3352 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3353 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3354 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3355 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3356 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3357 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3358 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3359 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3360 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3361 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3362 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3363 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3364 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3365 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3366 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3367 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3368 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3369 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3370 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3371 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3372 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3373 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3374 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3375 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3376 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3377 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3378 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3379 { 0, 0, 0, 0 }
3380};
3381
blueswir1b39bc502008-10-05 10:51:10 +00003382static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003383 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3384 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3385 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3386 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3387 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3388 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3389 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3390 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3391 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3392 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3393 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3394 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3395 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3396 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3397 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3398 { 0, 0, 0, 0 }
3399};
3400
3401static void target_to_host_termios (void *dst, const void *src)
3402{
3403 struct host_termios *host = dst;
3404 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003405
ths5fafdf22007-09-16 21:08:06 +00003406 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003407 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003408 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003409 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003410 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003411 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003412 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003413 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3414 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003415
Arnaud Patard44607122009-04-21 17:39:08 +03003416 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003417 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3418 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003419 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003420 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003421 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003422 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003423 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003424 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003425 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003426 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3427 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003428 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3429 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3430 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3431 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3432 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003433 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003434}
ths3b46e622007-09-17 08:09:54 +00003435
bellard31e31b82003-02-18 22:55:36 +00003436static void host_to_target_termios (void *dst, const void *src)
3437{
3438 struct target_termios *target = dst;
3439 const struct host_termios *host = src;
3440
ths5fafdf22007-09-16 21:08:06 +00003441 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003442 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003443 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003444 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003445 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003446 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003447 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003448 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3449 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003450
Arnaud Patard44607122009-04-21 17:39:08 +03003451 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003452 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3453 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3454 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3455 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3456 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3457 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3458 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3459 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3460 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3461 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3462 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3463 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3464 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3465 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3466 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3467 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3468 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3469}
3470
blueswir18e853dc2008-10-05 10:49:32 +00003471static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003472 .convert = { host_to_target_termios, target_to_host_termios },
3473 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3474 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3475};
3476
bellard5286db72003-06-05 00:57:30 +00003477static bitmask_transtbl mmap_flags_tbl[] = {
3478 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3479 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3480 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3481 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3482 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3483 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3484 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3485 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3486 { 0, 0, 0, 0 }
3487};
3488
bellard2ab83ea2003-06-15 19:56:46 +00003489#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003490
3491/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003492static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003493
bellard03acab62007-11-11 14:57:14 +00003494static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003495{
3496 int size;
pbrook53a59602006-03-25 19:31:22 +00003497 void *p;
bellard6dbad632003-03-16 18:05:05 +00003498
3499 if (!ldt_table)
3500 return 0;
3501 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3502 if (size > bytecount)
3503 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003504 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3505 if (!p)
bellard03acab62007-11-11 14:57:14 +00003506 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003507 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003508 memcpy(p, ldt_table, size);
3509 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003510 return size;
3511}
3512
3513/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003514static abi_long write_ldt(CPUX86State *env,
3515 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003516{
3517 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003518 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003519 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003520 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003521 uint32_t *lp, entry_1, entry_2;
3522
3523 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003524 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003525 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003526 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003527 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3528 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3529 ldt_info.limit = tswap32(target_ldt_info->limit);
3530 ldt_info.flags = tswap32(target_ldt_info->flags);
3531 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003532
bellard6dbad632003-03-16 18:05:05 +00003533 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003534 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003535 seg_32bit = ldt_info.flags & 1;
3536 contents = (ldt_info.flags >> 1) & 3;
3537 read_exec_only = (ldt_info.flags >> 3) & 1;
3538 limit_in_pages = (ldt_info.flags >> 4) & 1;
3539 seg_not_present = (ldt_info.flags >> 5) & 1;
3540 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003541#ifdef TARGET_ABI32
3542 lm = 0;
3543#else
3544 lm = (ldt_info.flags >> 7) & 1;
3545#endif
bellard6dbad632003-03-16 18:05:05 +00003546 if (contents == 3) {
3547 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003548 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003549 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003550 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003551 }
3552 /* allocate the LDT */
3553 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003554 env->ldt.base = target_mmap(0,
3555 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3556 PROT_READ|PROT_WRITE,
3557 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3558 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003559 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003560 memset(g2h(env->ldt.base), 0,
3561 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003562 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003563 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003564 }
3565
3566 /* NOTE: same code as Linux kernel */
3567 /* Allow LDTs to be cleared by the user. */
3568 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3569 if (oldmode ||
3570 (contents == 0 &&
3571 read_exec_only == 1 &&
3572 seg_32bit == 0 &&
3573 limit_in_pages == 0 &&
3574 seg_not_present == 1 &&
3575 useable == 0 )) {
3576 entry_1 = 0;
3577 entry_2 = 0;
3578 goto install;
3579 }
3580 }
ths3b46e622007-09-17 08:09:54 +00003581
bellard6dbad632003-03-16 18:05:05 +00003582 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3583 (ldt_info.limit & 0x0ffff);
3584 entry_2 = (ldt_info.base_addr & 0xff000000) |
3585 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3586 (ldt_info.limit & 0xf0000) |
3587 ((read_exec_only ^ 1) << 9) |
3588 (contents << 10) |
3589 ((seg_not_present ^ 1) << 15) |
3590 (seg_32bit << 22) |
3591 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003592 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003593 0x7000;
3594 if (!oldmode)
3595 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003596
bellard6dbad632003-03-16 18:05:05 +00003597 /* Install the new entry ... */
3598install:
3599 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3600 lp[0] = tswap32(entry_1);
3601 lp[1] = tswap32(entry_2);
3602 return 0;
3603}
3604
3605/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003606static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3607 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003608{
bellard03acab62007-11-11 14:57:14 +00003609 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003610
bellard6dbad632003-03-16 18:05:05 +00003611 switch (func) {
3612 case 0:
3613 ret = read_ldt(ptr, bytecount);
3614 break;
3615 case 1:
3616 ret = write_ldt(env, ptr, bytecount, 1);
3617 break;
3618 case 0x11:
3619 ret = write_ldt(env, ptr, bytecount, 0);
3620 break;
bellard03acab62007-11-11 14:57:14 +00003621 default:
3622 ret = -TARGET_ENOSYS;
3623 break;
bellard6dbad632003-03-16 18:05:05 +00003624 }
3625 return ret;
3626}
bellard1b6b0292003-03-22 17:31:38 +00003627
blueswir14583f582008-08-24 10:35:55 +00003628#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003629static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003630{
3631 uint64_t *gdt_table = g2h(env->gdt.base);
3632 struct target_modify_ldt_ldt_s ldt_info;
3633 struct target_modify_ldt_ldt_s *target_ldt_info;
3634 int seg_32bit, contents, read_exec_only, limit_in_pages;
3635 int seg_not_present, useable, lm;
3636 uint32_t *lp, entry_1, entry_2;
3637 int i;
3638
3639 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3640 if (!target_ldt_info)
3641 return -TARGET_EFAULT;
3642 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3643 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3644 ldt_info.limit = tswap32(target_ldt_info->limit);
3645 ldt_info.flags = tswap32(target_ldt_info->flags);
3646 if (ldt_info.entry_number == -1) {
3647 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3648 if (gdt_table[i] == 0) {
3649 ldt_info.entry_number = i;
3650 target_ldt_info->entry_number = tswap32(i);
3651 break;
3652 }
3653 }
3654 }
3655 unlock_user_struct(target_ldt_info, ptr, 1);
3656
3657 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
3658 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
3659 return -TARGET_EINVAL;
3660 seg_32bit = ldt_info.flags & 1;
3661 contents = (ldt_info.flags >> 1) & 3;
3662 read_exec_only = (ldt_info.flags >> 3) & 1;
3663 limit_in_pages = (ldt_info.flags >> 4) & 1;
3664 seg_not_present = (ldt_info.flags >> 5) & 1;
3665 useable = (ldt_info.flags >> 6) & 1;
3666#ifdef TARGET_ABI32
3667 lm = 0;
3668#else
3669 lm = (ldt_info.flags >> 7) & 1;
3670#endif
3671
3672 if (contents == 3) {
3673 if (seg_not_present == 0)
3674 return -TARGET_EINVAL;
3675 }
3676
3677 /* NOTE: same code as Linux kernel */
3678 /* Allow LDTs to be cleared by the user. */
3679 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3680 if ((contents == 0 &&
3681 read_exec_only == 1 &&
3682 seg_32bit == 0 &&
3683 limit_in_pages == 0 &&
3684 seg_not_present == 1 &&
3685 useable == 0 )) {
3686 entry_1 = 0;
3687 entry_2 = 0;
3688 goto install;
3689 }
3690 }
3691
3692 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3693 (ldt_info.limit & 0x0ffff);
3694 entry_2 = (ldt_info.base_addr & 0xff000000) |
3695 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3696 (ldt_info.limit & 0xf0000) |
3697 ((read_exec_only ^ 1) << 9) |
3698 (contents << 10) |
3699 ((seg_not_present ^ 1) << 15) |
3700 (seg_32bit << 22) |
3701 (limit_in_pages << 23) |
3702 (useable << 20) |
3703 (lm << 21) |
3704 0x7000;
3705
3706 /* Install the new entry ... */
3707install:
3708 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
3709 lp[0] = tswap32(entry_1);
3710 lp[1] = tswap32(entry_2);
3711 return 0;
3712}
3713
blueswir18fcd3692008-08-17 20:26:25 +00003714static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003715{
3716 struct target_modify_ldt_ldt_s *target_ldt_info;
3717 uint64_t *gdt_table = g2h(env->gdt.base);
3718 uint32_t base_addr, limit, flags;
3719 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
3720 int seg_not_present, useable, lm;
3721 uint32_t *lp, entry_1, entry_2;
3722
3723 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3724 if (!target_ldt_info)
3725 return -TARGET_EFAULT;
3726 idx = tswap32(target_ldt_info->entry_number);
3727 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
3728 idx > TARGET_GDT_ENTRY_TLS_MAX) {
3729 unlock_user_struct(target_ldt_info, ptr, 1);
3730 return -TARGET_EINVAL;
3731 }
3732 lp = (uint32_t *)(gdt_table + idx);
3733 entry_1 = tswap32(lp[0]);
3734 entry_2 = tswap32(lp[1]);
3735
3736 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
3737 contents = (entry_2 >> 10) & 3;
3738 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
3739 seg_32bit = (entry_2 >> 22) & 1;
3740 limit_in_pages = (entry_2 >> 23) & 1;
3741 useable = (entry_2 >> 20) & 1;
3742#ifdef TARGET_ABI32
3743 lm = 0;
3744#else
3745 lm = (entry_2 >> 21) & 1;
3746#endif
3747 flags = (seg_32bit << 0) | (contents << 1) |
3748 (read_exec_only << 3) | (limit_in_pages << 4) |
3749 (seg_not_present << 5) | (useable << 6) | (lm << 7);
3750 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
3751 base_addr = (entry_1 >> 16) |
3752 (entry_2 & 0xff000000) |
3753 ((entry_2 & 0xff) << 16);
3754 target_ldt_info->base_addr = tswapl(base_addr);
3755 target_ldt_info->limit = tswap32(limit);
3756 target_ldt_info->flags = tswap32(flags);
3757 unlock_user_struct(target_ldt_info, ptr, 1);
3758 return 0;
3759}
blueswir14583f582008-08-24 10:35:55 +00003760#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00003761
bellardd2fd1af2007-11-14 18:08:56 +00003762#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00003763static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00003764{
3765 abi_long ret;
3766 abi_ulong val;
3767 int idx;
3768
3769 switch(code) {
3770 case TARGET_ARCH_SET_GS:
3771 case TARGET_ARCH_SET_FS:
3772 if (code == TARGET_ARCH_SET_GS)
3773 idx = R_GS;
3774 else
3775 idx = R_FS;
3776 cpu_x86_load_seg(env, idx, 0);
3777 env->segs[idx].base = addr;
3778 break;
3779 case TARGET_ARCH_GET_GS:
3780 case TARGET_ARCH_GET_FS:
3781 if (code == TARGET_ARCH_GET_GS)
3782 idx = R_GS;
3783 else
3784 idx = R_FS;
3785 val = env->segs[idx].base;
3786 if (put_user(val, addr, abi_ulong))
3787 return -TARGET_EFAULT;
3788 break;
3789 default:
3790 ret = -TARGET_EINVAL;
3791 break;
3792 }
3793 return 0;
3794}
3795#endif
3796
bellard2ab83ea2003-06-15 19:56:46 +00003797#endif /* defined(TARGET_I386) */
3798
Riku Voipio05098a92011-03-04 15:27:29 +02003799#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00003800
Riku Voipio05098a92011-03-04 15:27:29 +02003801#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003802
3803static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
3804typedef struct {
3805 CPUState *env;
3806 pthread_mutex_t mutex;
3807 pthread_cond_t cond;
3808 pthread_t thread;
3809 uint32_t tid;
3810 abi_ulong child_tidptr;
3811 abi_ulong parent_tidptr;
3812 sigset_t sigmask;
3813} new_thread_info;
3814
3815static void *clone_func(void *arg)
3816{
3817 new_thread_info *info = arg;
3818 CPUState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003819 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00003820
3821 env = info->env;
3822 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003823 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00003824 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07003825 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003826 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00003827 if (info->child_tidptr)
3828 put_user_u32(info->tid, info->child_tidptr);
3829 if (info->parent_tidptr)
3830 put_user_u32(info->tid, info->parent_tidptr);
3831 /* Enable signals. */
3832 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
3833 /* Signal to the parent that we're ready. */
3834 pthread_mutex_lock(&info->mutex);
3835 pthread_cond_broadcast(&info->cond);
3836 pthread_mutex_unlock(&info->mutex);
3837 /* Wait until the parent has finshed initializing the tls state. */
3838 pthread_mutex_lock(&clone_lock);
3839 pthread_mutex_unlock(&clone_lock);
3840 cpu_loop(env);
3841 /* never exits */
3842 return NULL;
3843}
3844#else
bellard1b6b0292003-03-22 17:31:38 +00003845
3846static int clone_func(void *arg)
3847{
bellard2ab83ea2003-06-15 19:56:46 +00003848 CPUState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00003849 cpu_loop(env);
3850 /* never exits */
3851 return 0;
3852}
pbrookd865bab2008-06-07 22:12:17 +00003853#endif
bellard1b6b0292003-03-22 17:31:38 +00003854
ths0da46a62007-10-20 20:23:07 +00003855/* do_fork() Must return host values and target errnos (unlike most
3856 do_*() functions). */
pbrookd865bab2008-06-07 22:12:17 +00003857static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3858 abi_ulong parent_tidptr, target_ulong newtls,
3859 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00003860{
3861 int ret;
bellard5cd43932003-03-29 16:54:36 +00003862 TaskState *ts;
bellard2ab83ea2003-06-15 19:56:46 +00003863 CPUState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003864#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003865 unsigned int nptl_flags;
3866 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02003867#else
3868 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00003869#endif
ths3b46e622007-09-17 08:09:54 +00003870
balrog436d1242008-09-21 02:39:45 +00003871 /* Emulate vfork() with fork() */
3872 if (flags & CLONE_VFORK)
3873 flags &= ~(CLONE_VFORK | CLONE_VM);
3874
bellard1b6b0292003-03-22 17:31:38 +00003875 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003876 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003877#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003878 new_thread_info info;
3879 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00003880#endif
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003881 ts = qemu_mallocz(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00003882 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00003883 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00003884 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00003885#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3886 cpu_reset(new_env);
3887#endif
pbrook6e68e072008-05-30 17:22:15 +00003888 /* Init regs that differ from the parent. */
3889 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00003890 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003891 ts->bprm = parent_ts->bprm;
3892 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003893#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003894 nptl_flags = flags;
3895 flags &= ~CLONE_NPTL_FLAGS2;
3896
pbrookc2764712009-03-07 15:24:59 +00003897 if (nptl_flags & CLONE_CHILD_CLEARTID) {
3898 ts->child_tidptr = child_tidptr;
3899 }
3900
pbrookd865bab2008-06-07 22:12:17 +00003901 if (nptl_flags & CLONE_SETTLS)
3902 cpu_set_tls (new_env, newtls);
3903
3904 /* Grab a mutex so that thread setup appears atomic. */
3905 pthread_mutex_lock(&clone_lock);
3906
3907 memset(&info, 0, sizeof(info));
3908 pthread_mutex_init(&info.mutex, NULL);
3909 pthread_mutex_lock(&info.mutex);
3910 pthread_cond_init(&info.cond, NULL);
3911 info.env = new_env;
3912 if (nptl_flags & CLONE_CHILD_SETTID)
3913 info.child_tidptr = child_tidptr;
3914 if (nptl_flags & CLONE_PARENT_SETTID)
3915 info.parent_tidptr = parent_tidptr;
3916
3917 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003918 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
3919 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00003920 /* It is not safe to deliver signals until the child has finished
3921 initializing, so temporarily block all signals. */
3922 sigfillset(&sigmask);
3923 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
3924
3925 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00003926 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00003927
3928 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
3929 pthread_attr_destroy(&attr);
3930 if (ret == 0) {
3931 /* Wait for the child to initialize. */
3932 pthread_cond_wait(&info.cond, &info.mutex);
3933 ret = info.tid;
3934 if (flags & CLONE_PARENT_SETTID)
3935 put_user_u32(ret, parent_tidptr);
3936 } else {
3937 ret = -1;
3938 }
3939 pthread_mutex_unlock(&info.mutex);
3940 pthread_cond_destroy(&info.cond);
3941 pthread_mutex_destroy(&info.mutex);
3942 pthread_mutex_unlock(&clone_lock);
3943#else
3944 if (flags & CLONE_NPTL_FLAGS2)
3945 return -EINVAL;
3946 /* This is probably going to die very quickly, but do it anyway. */
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003947 new_stack = qemu_mallocz (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00003948#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02003949 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00003950#else
3951 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
3952#endif
pbrookd865bab2008-06-07 22:12:17 +00003953#endif
bellard1b6b0292003-03-22 17:31:38 +00003954 } else {
3955 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00003956 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00003957 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00003958 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00003959 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00003960 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00003961 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00003962 cpu_clone_regs(env, newsp);
3963 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02003964#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00003965 /* There is a race condition here. The parent process could
3966 theoretically read the TID in the child process before the child
3967 tid is set. This would require using either ptrace
3968 (not implemented) or having *_tidptr to point at a shared memory
3969 mapping. We can't repeat the spinlock hack used above because
3970 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00003971 if (flags & CLONE_CHILD_SETTID)
3972 put_user_u32(gettid(), child_tidptr);
3973 if (flags & CLONE_PARENT_SETTID)
3974 put_user_u32(gettid(), parent_tidptr);
3975 ts = (TaskState *)env->opaque;
3976 if (flags & CLONE_SETTLS)
3977 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00003978 if (flags & CLONE_CHILD_CLEARTID)
3979 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00003980#endif
pbrookd865bab2008-06-07 22:12:17 +00003981 } else {
3982 fork_end(0);
3983 }
bellard1b6b0292003-03-22 17:31:38 +00003984 }
3985 return ret;
3986}
3987
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02003988/* warning : doesn't handle linux specific flags... */
3989static int target_to_host_fcntl_cmd(int cmd)
3990{
3991 switch(cmd) {
3992 case TARGET_F_DUPFD:
3993 case TARGET_F_GETFD:
3994 case TARGET_F_SETFD:
3995 case TARGET_F_GETFL:
3996 case TARGET_F_SETFL:
3997 return cmd;
3998 case TARGET_F_GETLK:
3999 return F_GETLK;
4000 case TARGET_F_SETLK:
4001 return F_SETLK;
4002 case TARGET_F_SETLKW:
4003 return F_SETLKW;
4004 case TARGET_F_GETOWN:
4005 return F_GETOWN;
4006 case TARGET_F_SETOWN:
4007 return F_SETOWN;
4008 case TARGET_F_GETSIG:
4009 return F_GETSIG;
4010 case TARGET_F_SETSIG:
4011 return F_SETSIG;
4012#if TARGET_ABI_BITS == 32
4013 case TARGET_F_GETLK64:
4014 return F_GETLK64;
4015 case TARGET_F_SETLK64:
4016 return F_SETLK64;
4017 case TARGET_F_SETLKW64:
4018 return F_SETLKW64;
4019#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004020 case TARGET_F_SETLEASE:
4021 return F_SETLEASE;
4022 case TARGET_F_GETLEASE:
4023 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004024#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004025 case TARGET_F_DUPFD_CLOEXEC:
4026 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004027#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004028 case TARGET_F_NOTIFY:
4029 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004030 default:
4031 return -TARGET_EINVAL;
4032 }
4033 return -TARGET_EINVAL;
4034}
4035
blueswir1992f48a2007-10-14 16:27:31 +00004036static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004037{
4038 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004039 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004040 struct flock64 fl64;
4041 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004042 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004043 int host_cmd = target_to_host_fcntl_cmd(cmd);
4044
4045 if (host_cmd == -TARGET_EINVAL)
4046 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004047
bellard7775e9e2003-05-14 22:46:48 +00004048 switch(cmd) {
4049 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004050 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4051 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004052 fl.l_type = tswap16(target_fl->l_type);
4053 fl.l_whence = tswap16(target_fl->l_whence);
4054 fl.l_start = tswapl(target_fl->l_start);
4055 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004056 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004057 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004058 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004059 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004060 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4061 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004062 target_fl->l_type = tswap16(fl.l_type);
4063 target_fl->l_whence = tswap16(fl.l_whence);
4064 target_fl->l_start = tswapl(fl.l_start);
4065 target_fl->l_len = tswapl(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004066 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004067 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004068 }
4069 break;
ths3b46e622007-09-17 08:09:54 +00004070
bellard7775e9e2003-05-14 22:46:48 +00004071 case TARGET_F_SETLK:
4072 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004073 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4074 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004075 fl.l_type = tswap16(target_fl->l_type);
4076 fl.l_whence = tswap16(target_fl->l_whence);
4077 fl.l_start = tswapl(target_fl->l_start);
4078 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004079 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004080 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004081 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004082 break;
ths3b46e622007-09-17 08:09:54 +00004083
bellard7775e9e2003-05-14 22:46:48 +00004084 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004085 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4086 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004087 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4088 fl64.l_whence = tswap16(target_fl64->l_whence);
4089 fl64.l_start = tswapl(target_fl64->l_start);
4090 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004091 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004092 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004093 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004094 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004095 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4096 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004097 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4098 target_fl64->l_whence = tswap16(fl64.l_whence);
4099 target_fl64->l_start = tswapl(fl64.l_start);
4100 target_fl64->l_len = tswapl(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004101 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004102 unlock_user_struct(target_fl64, arg, 1);
4103 }
bellard9ee1fa22007-11-11 15:11:19 +00004104 break;
bellard7775e9e2003-05-14 22:46:48 +00004105 case TARGET_F_SETLK64:
4106 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004107 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4108 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004109 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4110 fl64.l_whence = tswap16(target_fl64->l_whence);
4111 fl64.l_start = tswapl(target_fl64->l_start);
4112 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004113 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004114 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004115 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004116 break;
4117
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004118 case TARGET_F_GETFL:
4119 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004120 if (ret >= 0) {
4121 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4122 }
bellardffa65c32004-01-04 23:57:22 +00004123 break;
4124
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004125 case TARGET_F_SETFL:
4126 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4127 break;
4128
4129 case TARGET_F_SETOWN:
4130 case TARGET_F_GETOWN:
4131 case TARGET_F_SETSIG:
4132 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004133 case TARGET_F_SETLEASE:
4134 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004135 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004136 break;
4137
bellard7775e9e2003-05-14 22:46:48 +00004138 default:
bellard9ee1fa22007-11-11 15:11:19 +00004139 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004140 break;
4141 }
4142 return ret;
4143}
4144
bellard67867302003-11-23 17:05:30 +00004145#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004146
bellard67867302003-11-23 17:05:30 +00004147static inline int high2lowuid(int uid)
4148{
4149 if (uid > 65535)
4150 return 65534;
4151 else
4152 return uid;
4153}
4154
4155static inline int high2lowgid(int gid)
4156{
4157 if (gid > 65535)
4158 return 65534;
4159 else
4160 return gid;
4161}
4162
4163static inline int low2highuid(int uid)
4164{
4165 if ((int16_t)uid == -1)
4166 return -1;
4167 else
4168 return uid;
4169}
4170
4171static inline int low2highgid(int gid)
4172{
4173 if ((int16_t)gid == -1)
4174 return -1;
4175 else
4176 return gid;
4177}
Riku Voipio0c866a72011-04-18 15:23:06 +03004178static inline int tswapid(int id)
4179{
4180 return tswap16(id);
4181}
4182#else /* !USE_UID16 */
4183static inline int high2lowuid(int uid)
4184{
4185 return uid;
4186}
4187static inline int high2lowgid(int gid)
4188{
4189 return gid;
4190}
4191static inline int low2highuid(int uid)
4192{
4193 return uid;
4194}
4195static inline int low2highgid(int gid)
4196{
4197 return gid;
4198}
4199static inline int tswapid(int id)
4200{
4201 return tswap32(id);
4202}
bellard67867302003-11-23 17:05:30 +00004203#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004204
bellard31e31b82003-02-18 22:55:36 +00004205void syscall_init(void)
4206{
bellard2ab83ea2003-06-15 19:56:46 +00004207 IOCTLEntry *ie;
4208 const argtype *arg_type;
4209 int size;
thsb92c47c2007-11-01 00:07:38 +00004210 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004211
Blue Swirl001faf32009-05-13 17:53:17 +00004212#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004213#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004214#include "syscall_types.h"
4215#undef STRUCT
4216#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004217
4218 /* we patch the ioctl size if necessary. We rely on the fact that
4219 no ioctl has all the bits at '1' in the size field */
4220 ie = ioctl_entries;
4221 while (ie->target_cmd != 0) {
4222 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4223 TARGET_IOC_SIZEMASK) {
4224 arg_type = ie->arg_type;
4225 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004226 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004227 ie->target_cmd);
4228 exit(1);
4229 }
4230 arg_type++;
4231 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004232 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004233 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4234 (size << TARGET_IOC_SIZESHIFT);
4235 }
thsb92c47c2007-11-01 00:07:38 +00004236
4237 /* Build target_to_host_errno_table[] table from
4238 * host_to_target_errno_table[]. */
4239 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4240 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4241
bellard2ab83ea2003-06-15 19:56:46 +00004242 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004243#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4244 (defined(__x86_64__) && defined(TARGET_X86_64))
4245 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4246 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4247 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004248 }
4249#endif
4250 ie++;
4251 }
bellard31e31b82003-02-18 22:55:36 +00004252}
bellardc573ff62004-01-04 15:51:36 +00004253
blueswir1992f48a2007-10-14 16:27:31 +00004254#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004255static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4256{
thsaf325d32008-06-10 15:29:15 +00004257#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004258 return ((uint64_t)word0 << 32) | word1;
4259#else
4260 return ((uint64_t)word1 << 32) | word0;
4261#endif
4262}
blueswir1992f48a2007-10-14 16:27:31 +00004263#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004264static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4265{
4266 return word0;
4267}
blueswir1992f48a2007-10-14 16:27:31 +00004268#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004269
4270#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004271static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4272 abi_long arg2,
4273 abi_long arg3,
4274 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004275{
4276#ifdef TARGET_ARM
4277 if (((CPUARMState *)cpu_env)->eabi)
4278 {
4279 arg2 = arg3;
4280 arg3 = arg4;
4281 }
4282#endif
4283 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4284}
4285#endif
4286
4287#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004288static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4289 abi_long arg2,
4290 abi_long arg3,
4291 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004292{
4293#ifdef TARGET_ARM
4294 if (((CPUARMState *)cpu_env)->eabi)
4295 {
4296 arg2 = arg3;
4297 arg3 = arg4;
4298 }
4299#endif
4300 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4301}
4302#endif
4303
bellard579a97f2007-11-11 14:26:47 +00004304static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4305 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004306{
4307 struct target_timespec *target_ts;
4308
bellard579a97f2007-11-11 14:26:47 +00004309 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4310 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004311 host_ts->tv_sec = tswapl(target_ts->tv_sec);
4312 host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
4313 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004314 return 0;
pbrook53a59602006-03-25 19:31:22 +00004315}
4316
bellard579a97f2007-11-11 14:26:47 +00004317static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4318 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004319{
4320 struct target_timespec *target_ts;
4321
bellard579a97f2007-11-11 14:26:47 +00004322 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4323 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004324 target_ts->tv_sec = tswapl(host_ts->tv_sec);
4325 target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
4326 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004327 return 0;
pbrook53a59602006-03-25 19:31:22 +00004328}
4329
aurel329d33b762009-04-08 23:07:05 +00004330#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004331static inline abi_long host_to_target_stat64(void *cpu_env,
4332 abi_ulong target_addr,
4333 struct stat *host_st)
4334{
4335#ifdef TARGET_ARM
4336 if (((CPUARMState *)cpu_env)->eabi) {
4337 struct target_eabi_stat64 *target_st;
4338
4339 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4340 return -TARGET_EFAULT;
4341 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4342 __put_user(host_st->st_dev, &target_st->st_dev);
4343 __put_user(host_st->st_ino, &target_st->st_ino);
4344#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4345 __put_user(host_st->st_ino, &target_st->__st_ino);
4346#endif
4347 __put_user(host_st->st_mode, &target_st->st_mode);
4348 __put_user(host_st->st_nlink, &target_st->st_nlink);
4349 __put_user(host_st->st_uid, &target_st->st_uid);
4350 __put_user(host_st->st_gid, &target_st->st_gid);
4351 __put_user(host_st->st_rdev, &target_st->st_rdev);
4352 __put_user(host_st->st_size, &target_st->st_size);
4353 __put_user(host_st->st_blksize, &target_st->st_blksize);
4354 __put_user(host_st->st_blocks, &target_st->st_blocks);
4355 __put_user(host_st->st_atime, &target_st->target_st_atime);
4356 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4357 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4358 unlock_user_struct(target_st, target_addr, 1);
4359 } else
4360#endif
4361 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004362#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004363 struct target_stat *target_st;
4364#else
balrog6a24a772008-09-20 02:23:36 +00004365 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004366#endif
balrog6a24a772008-09-20 02:23:36 +00004367
4368 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4369 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004370 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004371 __put_user(host_st->st_dev, &target_st->st_dev);
4372 __put_user(host_st->st_ino, &target_st->st_ino);
4373#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4374 __put_user(host_st->st_ino, &target_st->__st_ino);
4375#endif
4376 __put_user(host_st->st_mode, &target_st->st_mode);
4377 __put_user(host_st->st_nlink, &target_st->st_nlink);
4378 __put_user(host_st->st_uid, &target_st->st_uid);
4379 __put_user(host_st->st_gid, &target_st->st_gid);
4380 __put_user(host_st->st_rdev, &target_st->st_rdev);
4381 /* XXX: better use of kernel struct */
4382 __put_user(host_st->st_size, &target_st->st_size);
4383 __put_user(host_st->st_blksize, &target_st->st_blksize);
4384 __put_user(host_st->st_blocks, &target_st->st_blocks);
4385 __put_user(host_st->st_atime, &target_st->target_st_atime);
4386 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4387 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4388 unlock_user_struct(target_st, target_addr, 1);
4389 }
4390
4391 return 0;
4392}
4393#endif
4394
Juan Quintela2f7bb872009-07-27 16:13:24 +02004395#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004396/* ??? Using host futex calls even when target atomic operations
4397 are not really atomic probably breaks things. However implementing
4398 futexes locally would make futexes shared between multiple processes
4399 tricky. However they're probably useless because guest atomic
4400 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004401static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4402 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004403{
4404 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004405 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004406
4407 /* ??? We assume FUTEX_* constants are the same on both host
4408 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004409#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004410 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004411#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004412 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004413#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004414 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004415 case FUTEX_WAIT:
4416 if (timeout) {
4417 pts = &ts;
4418 target_to_host_timespec(pts, timeout);
4419 } else {
4420 pts = NULL;
4421 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004422 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004423 pts, NULL, 0));
4424 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004425 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004426 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004427 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004428 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004429 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004430 case FUTEX_WAKE_OP:
4431 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4432 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4433 But the prototype takes a `struct timespec *'; insert casts
4434 to satisfy the compiler. We do not need to tswap TIMEOUT
4435 since it's not compared to guest memory. */
4436 pts = (struct timespec *)(uintptr_t) timeout;
4437 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4438 g2h(uaddr2),
4439 (base_op == FUTEX_CMP_REQUEUE
4440 ? tswap32(val3)
4441 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004442 default:
4443 return -TARGET_ENOSYS;
4444 }
4445}
4446#endif
4447
pbrook1d9d8b52009-04-16 15:17:02 +00004448/* Map host to target signal numbers for the wait family of syscalls.
4449 Assume all other status bits are the same. */
4450static int host_to_target_waitstatus(int status)
4451{
4452 if (WIFSIGNALED(status)) {
4453 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4454 }
4455 if (WIFSTOPPED(status)) {
4456 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4457 | (status & 0xff);
4458 }
4459 return status;
4460}
4461
pbrooka745ec62008-05-06 15:36:17 +00004462int get_osversion(void)
4463{
4464 static int osversion;
4465 struct new_utsname buf;
4466 const char *s;
4467 int i, n, tmp;
4468 if (osversion)
4469 return osversion;
4470 if (qemu_uname_release && *qemu_uname_release) {
4471 s = qemu_uname_release;
4472 } else {
4473 if (sys_uname(&buf))
4474 return 0;
4475 s = buf.release;
4476 }
4477 tmp = 0;
4478 for (i = 0; i < 3; i++) {
4479 n = 0;
4480 while (*s >= '0' && *s <= '9') {
4481 n *= 10;
4482 n += *s - '0';
4483 s++;
4484 }
4485 tmp = (tmp << 8) + n;
4486 if (*s == '.')
4487 s++;
4488 }
4489 osversion = tmp;
4490 return osversion;
4491}
4492
ths0da46a62007-10-20 20:23:07 +00004493/* do_syscall() should always have a single exit point at the end so
4494 that actions, such as logging of syscall results, can be performed.
4495 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004496abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4497 abi_long arg2, abi_long arg3, abi_long arg4,
4498 abi_long arg5, abi_long arg6)
bellard31e31b82003-02-18 22:55:36 +00004499{
blueswir1992f48a2007-10-14 16:27:31 +00004500 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004501 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004502 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004503 void *p;
ths3b46e622007-09-17 08:09:54 +00004504
bellard72f03902003-02-18 23:33:18 +00004505#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00004506 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00004507#endif
thsb92c47c2007-11-01 00:07:38 +00004508 if(do_strace)
4509 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
4510
bellard31e31b82003-02-18 22:55:36 +00004511 switch(num) {
4512 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02004513#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00004514 /* In old applications this may be used to implement _exit(2).
4515 However in threaded applictions it is used for thread termination,
4516 and _exit_group is used for application termination.
4517 Do thread termination if we have more then one thread. */
4518 /* FIXME: This probably breaks if a signal arrives. We should probably
4519 be disabling signals. */
4520 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004521 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00004522 CPUState **lastp;
4523 CPUState *p;
4524
4525 cpu_list_lock();
4526 lastp = &first_cpu;
4527 p = first_cpu;
4528 while (p && p != (CPUState *)cpu_env) {
4529 lastp = &p->next_cpu;
4530 p = p->next_cpu;
4531 }
4532 /* If we didn't find the CPU for this thread then something is
4533 horribly wrong. */
4534 if (!p)
4535 abort();
4536 /* Remove the CPU from the list. */
4537 *lastp = p->next_cpu;
4538 cpu_list_unlock();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004539 ts = ((CPUState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00004540 if (ts->child_tidptr) {
4541 put_user_u32(0, ts->child_tidptr);
4542 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
4543 NULL, NULL, 0);
4544 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004545 thread_env = NULL;
4546 qemu_free(cpu_env);
4547 qemu_free(ts);
pbrookc2764712009-03-07 15:24:59 +00004548 pthread_exit(NULL);
4549 }
4550#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02004551#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00004552 _mcleanup();
4553#endif
bellarde9009672005-04-26 20:42:36 +00004554 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00004555 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00004556 ret = 0; /* avoid warning */
4557 break;
4558 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00004559 if (arg3 == 0)
4560 ret = 0;
4561 else {
4562 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
4563 goto efault;
4564 ret = get_errno(read(arg1, p, arg3));
4565 unlock_user(p, arg2, ret);
4566 }
bellard31e31b82003-02-18 22:55:36 +00004567 break;
4568 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00004569 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
4570 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004571 ret = get_errno(write(arg1, p, arg3));
4572 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00004573 break;
4574 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00004575 if (!(p = lock_user_string(arg1)))
4576 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004577 ret = get_errno(open(path(p),
bellardffa65c32004-01-04 23:57:22 +00004578 target_to_host_bitmask(arg2, fcntl_flags_tbl),
4579 arg3));
pbrook53a59602006-03-25 19:31:22 +00004580 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004581 break;
ths82424832007-09-24 09:21:55 +00004582#if defined(TARGET_NR_openat) && defined(__NR_openat)
4583 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00004584 if (!(p = lock_user_string(arg2)))
4585 goto efault;
4586 ret = get_errno(sys_openat(arg1,
4587 path(p),
4588 target_to_host_bitmask(arg3, fcntl_flags_tbl),
4589 arg4));
4590 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00004591 break;
4592#endif
bellard31e31b82003-02-18 22:55:36 +00004593 case TARGET_NR_close:
4594 ret = get_errno(close(arg1));
4595 break;
4596 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00004597 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00004598 break;
4599 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00004600 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00004601 break;
thse5febef2007-04-01 18:31:35 +00004602#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00004603 case TARGET_NR_waitpid:
4604 {
pbrook53a59602006-03-25 19:31:22 +00004605 int status;
4606 ret = get_errno(waitpid(arg1, &status, arg3));
bellard2f619692007-11-16 10:46:05 +00004607 if (!is_error(ret) && arg2
pbrook1d9d8b52009-04-16 15:17:02 +00004608 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00004609 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004610 }
4611 break;
thse5febef2007-04-01 18:31:35 +00004612#endif
pbrookf0cbb612008-05-30 18:20:05 +00004613#ifdef TARGET_NR_waitid
4614 case TARGET_NR_waitid:
4615 {
4616 siginfo_t info;
4617 info.si_pid = 0;
4618 ret = get_errno(waitid(arg1, arg2, &info, arg4));
4619 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004620 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00004621 goto efault;
4622 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05004623 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00004624 }
4625 }
4626 break;
4627#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004628#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004629 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00004630 if (!(p = lock_user_string(arg1)))
4631 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004632 ret = get_errno(creat(p, arg2));
4633 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004634 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004635#endif
bellard31e31b82003-02-18 22:55:36 +00004636 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00004637 {
4638 void * p2;
4639 p = lock_user_string(arg1);
4640 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004641 if (!p || !p2)
4642 ret = -TARGET_EFAULT;
4643 else
4644 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004645 unlock_user(p2, arg2, 0);
4646 unlock_user(p, arg1, 0);
4647 }
bellard31e31b82003-02-18 22:55:36 +00004648 break;
ths64f0ce42007-09-24 09:25:06 +00004649#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
4650 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00004651 {
4652 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00004653 if (!arg2 || !arg4)
4654 goto efault;
ths64f0ce42007-09-24 09:25:06 +00004655 p = lock_user_string(arg2);
4656 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004657 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004658 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00004659 else
4660 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00004661 unlock_user(p, arg2, 0);
4662 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00004663 }
4664 break;
4665#endif
bellard31e31b82003-02-18 22:55:36 +00004666 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00004667 if (!(p = lock_user_string(arg1)))
4668 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004669 ret = get_errno(unlink(p));
4670 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004671 break;
ths8170f562007-09-24 09:24:11 +00004672#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
4673 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00004674 if (!(p = lock_user_string(arg2)))
4675 goto efault;
4676 ret = get_errno(sys_unlinkat(arg1, p, arg3));
4677 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00004678 break;
balrogb7d35e62007-12-12 00:40:24 +00004679#endif
bellard31e31b82003-02-18 22:55:36 +00004680 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00004681 {
4682 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00004683 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00004684 abi_ulong gp;
4685 abi_ulong guest_argp;
4686 abi_ulong guest_envp;
4687 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00004688 char **q;
4689
bellardf7341ff2003-03-30 21:00:25 +00004690 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00004691 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00004692 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004693 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004694 goto efault;
ths03aa1972007-12-02 06:28:08 +00004695 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004696 break;
bellard7854b052003-03-29 17:22:23 +00004697 argc++;
bellard2f619692007-11-16 10:46:05 +00004698 }
bellardf7341ff2003-03-30 21:00:25 +00004699 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00004700 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00004701 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004702 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004703 goto efault;
ths03aa1972007-12-02 06:28:08 +00004704 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004705 break;
bellard7854b052003-03-29 17:22:23 +00004706 envc++;
bellard2f619692007-11-16 10:46:05 +00004707 }
bellard7854b052003-03-29 17:22:23 +00004708
bellardf7341ff2003-03-30 21:00:25 +00004709 argp = alloca((argc + 1) * sizeof(void *));
4710 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00004711
pbrookda94d262008-05-30 18:24:00 +00004712 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004713 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004714 if (get_user_ual(addr, gp))
4715 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004716 if (!addr)
4717 break;
bellard2f619692007-11-16 10:46:05 +00004718 if (!(*q = lock_user_string(addr)))
4719 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004720 }
bellardf7341ff2003-03-30 21:00:25 +00004721 *q = NULL;
4722
pbrookda94d262008-05-30 18:24:00 +00004723 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004724 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004725 if (get_user_ual(addr, gp))
4726 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004727 if (!addr)
4728 break;
bellard2f619692007-11-16 10:46:05 +00004729 if (!(*q = lock_user_string(addr)))
4730 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004731 }
bellardf7341ff2003-03-30 21:00:25 +00004732 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00004733
bellard2f619692007-11-16 10:46:05 +00004734 if (!(p = lock_user_string(arg1)))
4735 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004736 ret = get_errno(execve(p, argp, envp));
4737 unlock_user(p, arg1, 0);
4738
bellard2f619692007-11-16 10:46:05 +00004739 goto execve_end;
4740
4741 execve_efault:
4742 ret = -TARGET_EFAULT;
4743
4744 execve_end:
pbrook53a59602006-03-25 19:31:22 +00004745 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004746 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004747 if (get_user_ual(addr, gp)
4748 || !addr)
4749 break;
pbrook53a59602006-03-25 19:31:22 +00004750 unlock_user(*q, addr, 0);
4751 }
4752 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004753 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004754 if (get_user_ual(addr, gp)
4755 || !addr)
4756 break;
pbrook53a59602006-03-25 19:31:22 +00004757 unlock_user(*q, addr, 0);
4758 }
bellard7854b052003-03-29 17:22:23 +00004759 }
bellard31e31b82003-02-18 22:55:36 +00004760 break;
4761 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00004762 if (!(p = lock_user_string(arg1)))
4763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004764 ret = get_errno(chdir(p));
4765 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004766 break;
bellarda315a142005-01-30 22:59:18 +00004767#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00004768 case TARGET_NR_time:
4769 {
pbrook53a59602006-03-25 19:31:22 +00004770 time_t host_time;
4771 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00004772 if (!is_error(ret)
4773 && arg1
4774 && put_user_sal(host_time, arg1))
4775 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004776 }
4777 break;
bellarda315a142005-01-30 22:59:18 +00004778#endif
bellard31e31b82003-02-18 22:55:36 +00004779 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00004780 if (!(p = lock_user_string(arg1)))
4781 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004782 ret = get_errno(mknod(p, arg2, arg3));
4783 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004784 break;
ths75ac37a2007-09-24 09:23:05 +00004785#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
4786 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00004787 if (!(p = lock_user_string(arg2)))
4788 goto efault;
4789 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
4790 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00004791 break;
4792#endif
bellard31e31b82003-02-18 22:55:36 +00004793 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00004794 if (!(p = lock_user_string(arg1)))
4795 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004796 ret = get_errno(chmod(p, arg2));
4797 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004798 break;
bellardebc05482003-09-30 21:08:41 +00004799#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00004800 case TARGET_NR_break:
4801 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004802#endif
4803#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00004804 case TARGET_NR_oldstat:
4805 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004806#endif
bellard31e31b82003-02-18 22:55:36 +00004807 case TARGET_NR_lseek:
4808 ret = get_errno(lseek(arg1, arg2, arg3));
4809 break;
Richard Henderson92317332010-05-03 10:07:53 -07004810#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
4811 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00004812 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07004813 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00004814 ret = get_errno(getpid());
4815 break;
Richard Henderson92317332010-05-03 10:07:53 -07004816#endif
4817#ifdef TARGET_NR_getpid
4818 case TARGET_NR_getpid:
4819 ret = get_errno(getpid());
4820 break;
4821#endif
bellard31e31b82003-02-18 22:55:36 +00004822 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00004823 {
4824 /* need to look at the data field */
4825 void *p2, *p3;
4826 p = lock_user_string(arg1);
4827 p2 = lock_user_string(arg2);
4828 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00004829 if (!p || !p2 || !p3)
4830 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004831 else {
bellard579a97f2007-11-11 14:26:47 +00004832 /* FIXME - arg5 should be locked, but it isn't clear how to
4833 * do that since it's not guaranteed to be a NULL-terminated
4834 * string.
4835 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004836 if ( ! arg5 )
4837 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
4838 else
4839 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
4840 }
bellard579a97f2007-11-11 14:26:47 +00004841 unlock_user(p, arg1, 0);
4842 unlock_user(p2, arg2, 0);
4843 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00004844 break;
4845 }
thse5febef2007-04-01 18:31:35 +00004846#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00004847 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00004848 if (!(p = lock_user_string(arg1)))
4849 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004850 ret = get_errno(umount(p));
4851 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004852 break;
thse5febef2007-04-01 18:31:35 +00004853#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004854#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004855 case TARGET_NR_stime:
4856 {
pbrook53a59602006-03-25 19:31:22 +00004857 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00004858 if (get_user_sal(host_time, arg1))
4859 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004860 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00004861 }
4862 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004863#endif
bellard31e31b82003-02-18 22:55:36 +00004864 case TARGET_NR_ptrace:
4865 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00004866#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004867 case TARGET_NR_alarm:
4868 ret = alarm(arg1);
4869 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004870#endif
bellardebc05482003-09-30 21:08:41 +00004871#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00004872 case TARGET_NR_oldfstat:
4873 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004874#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004875#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004876 case TARGET_NR_pause:
4877 ret = get_errno(pause());
4878 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004879#endif
thse5febef2007-04-01 18:31:35 +00004880#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00004881 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00004882 {
pbrook53a59602006-03-25 19:31:22 +00004883 struct utimbuf tbuf, *host_tbuf;
4884 struct target_utimbuf *target_tbuf;
4885 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00004886 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
4887 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004888 tbuf.actime = tswapl(target_tbuf->actime);
4889 tbuf.modtime = tswapl(target_tbuf->modtime);
4890 unlock_user_struct(target_tbuf, arg2, 0);
4891 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00004892 } else {
pbrook53a59602006-03-25 19:31:22 +00004893 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00004894 }
bellard579a97f2007-11-11 14:26:47 +00004895 if (!(p = lock_user_string(arg1)))
4896 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004897 ret = get_errno(utime(p, host_tbuf));
4898 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00004899 }
4900 break;
thse5febef2007-04-01 18:31:35 +00004901#endif
bellard978a66f2004-12-06 22:58:05 +00004902 case TARGET_NR_utimes:
4903 {
bellard978a66f2004-12-06 22:58:05 +00004904 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00004905 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00004906 if (copy_from_user_timeval(&tv[0], arg2)
4907 || copy_from_user_timeval(&tv[1],
4908 arg2 + sizeof(struct target_timeval)))
4909 goto efault;
bellard978a66f2004-12-06 22:58:05 +00004910 tvp = tv;
4911 } else {
4912 tvp = NULL;
4913 }
bellard579a97f2007-11-11 14:26:47 +00004914 if (!(p = lock_user_string(arg1)))
4915 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004916 ret = get_errno(utimes(p, tvp));
4917 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00004918 }
4919 break;
balrogac8a6552008-09-20 02:25:39 +00004920#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
4921 case TARGET_NR_futimesat:
4922 {
4923 struct timeval *tvp, tv[2];
4924 if (arg3) {
4925 if (copy_from_user_timeval(&tv[0], arg3)
4926 || copy_from_user_timeval(&tv[1],
4927 arg3 + sizeof(struct target_timeval)))
4928 goto efault;
4929 tvp = tv;
4930 } else {
4931 tvp = NULL;
4932 }
4933 if (!(p = lock_user_string(arg2)))
4934 goto efault;
4935 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
4936 unlock_user(p, arg2, 0);
4937 }
4938 break;
4939#endif
bellardebc05482003-09-30 21:08:41 +00004940#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00004941 case TARGET_NR_stty:
4942 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004943#endif
4944#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00004945 case TARGET_NR_gtty:
4946 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004947#endif
bellard31e31b82003-02-18 22:55:36 +00004948 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00004949 if (!(p = lock_user_string(arg1)))
4950 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02004951 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00004952 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004953 break;
ths92a34c12007-09-24 09:27:49 +00004954#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
4955 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00004956 if (!(p = lock_user_string(arg2)))
4957 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00004958 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00004959 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00004960 break;
4961#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004962#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004963 case TARGET_NR_nice:
4964 ret = get_errno(nice(arg1));
4965 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004966#endif
bellardebc05482003-09-30 21:08:41 +00004967#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00004968 case TARGET_NR_ftime:
4969 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004970#endif
bellard31e31b82003-02-18 22:55:36 +00004971 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00004972 sync();
4973 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00004974 break;
4975 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00004976 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00004977 break;
4978 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00004979 {
4980 void *p2;
4981 p = lock_user_string(arg1);
4982 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004983 if (!p || !p2)
4984 ret = -TARGET_EFAULT;
4985 else
4986 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004987 unlock_user(p2, arg2, 0);
4988 unlock_user(p, arg1, 0);
4989 }
bellard31e31b82003-02-18 22:55:36 +00004990 break;
ths722183f2007-09-24 09:24:37 +00004991#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
4992 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00004993 {
bellard579a97f2007-11-11 14:26:47 +00004994 void *p2;
ths722183f2007-09-24 09:24:37 +00004995 p = lock_user_string(arg2);
4996 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004997 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004998 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00004999 else
5000 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005001 unlock_user(p2, arg4, 0);
5002 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005003 }
5004 break;
5005#endif
bellard31e31b82003-02-18 22:55:36 +00005006 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005007 if (!(p = lock_user_string(arg1)))
5008 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005009 ret = get_errno(mkdir(p, arg2));
5010 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005011 break;
ths4472ad02007-09-24 09:22:32 +00005012#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5013 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005014 if (!(p = lock_user_string(arg2)))
5015 goto efault;
5016 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5017 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005018 break;
5019#endif
bellard31e31b82003-02-18 22:55:36 +00005020 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005021 if (!(p = lock_user_string(arg1)))
5022 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005023 ret = get_errno(rmdir(p));
5024 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005025 break;
5026 case TARGET_NR_dup:
5027 ret = get_errno(dup(arg1));
5028 break;
5029 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005030 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005031 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005032#ifdef TARGET_NR_pipe2
5033 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005034 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005035 break;
5036#endif
bellard31e31b82003-02-18 22:55:36 +00005037 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005038 {
pbrook53a59602006-03-25 19:31:22 +00005039 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005040 struct tms tms;
5041 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005042 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005043 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5044 if (!tmsp)
5045 goto efault;
bellardc596ed12003-07-13 17:32:31 +00005046 tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
5047 tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
5048 tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
5049 tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005050 }
bellardc596ed12003-07-13 17:32:31 +00005051 if (!is_error(ret))
5052 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005053 }
5054 break;
bellardebc05482003-09-30 21:08:41 +00005055#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005056 case TARGET_NR_prof:
5057 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005058#endif
thse5febef2007-04-01 18:31:35 +00005059#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005060 case TARGET_NR_signal:
5061 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005062#endif
bellard31e31b82003-02-18 22:55:36 +00005063 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005064 if (arg1 == 0) {
5065 ret = get_errno(acct(NULL));
5066 } else {
5067 if (!(p = lock_user_string(arg1)))
5068 goto efault;
5069 ret = get_errno(acct(path(p)));
5070 unlock_user(p, arg1, 0);
5071 }
pbrook24836682006-04-16 14:14:53 +00005072 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005073#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005074 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005075 if (!(p = lock_user_string(arg1)))
5076 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005077 ret = get_errno(umount2(p, arg2));
5078 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005079 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005080#endif
bellardebc05482003-09-30 21:08:41 +00005081#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005082 case TARGET_NR_lock:
5083 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005084#endif
bellard31e31b82003-02-18 22:55:36 +00005085 case TARGET_NR_ioctl:
5086 ret = do_ioctl(arg1, arg2, arg3);
5087 break;
5088 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005089 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005090 break;
bellardebc05482003-09-30 21:08:41 +00005091#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005092 case TARGET_NR_mpx:
5093 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005094#endif
bellard31e31b82003-02-18 22:55:36 +00005095 case TARGET_NR_setpgid:
5096 ret = get_errno(setpgid(arg1, arg2));
5097 break;
bellardebc05482003-09-30 21:08:41 +00005098#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005099 case TARGET_NR_ulimit:
5100 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005101#endif
5102#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005103 case TARGET_NR_oldolduname:
5104 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005105#endif
bellard31e31b82003-02-18 22:55:36 +00005106 case TARGET_NR_umask:
5107 ret = get_errno(umask(arg1));
5108 break;
5109 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005110 if (!(p = lock_user_string(arg1)))
5111 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005112 ret = get_errno(chroot(p));
5113 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005114 break;
5115 case TARGET_NR_ustat:
5116 goto unimplemented;
5117 case TARGET_NR_dup2:
5118 ret = get_errno(dup2(arg1, arg2));
5119 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005120#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5121 case TARGET_NR_dup3:
5122 ret = get_errno(dup3(arg1, arg2, arg3));
5123 break;
5124#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005125#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005126 case TARGET_NR_getppid:
5127 ret = get_errno(getppid());
5128 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005129#endif
bellard31e31b82003-02-18 22:55:36 +00005130 case TARGET_NR_getpgrp:
5131 ret = get_errno(getpgrp());
5132 break;
5133 case TARGET_NR_setsid:
5134 ret = get_errno(setsid());
5135 break;
thse5febef2007-04-01 18:31:35 +00005136#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005137 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005138 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005139#if defined(TARGET_ALPHA)
5140 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005141 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005142 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005143 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5144 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005145 act._sa_handler = old_act->_sa_handler;
5146 target_siginitset(&act.sa_mask, old_act->sa_mask);
5147 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005148 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005149 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005150 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005151 }
5152 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005153 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005154 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5155 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005156 old_act->_sa_handler = oact._sa_handler;
5157 old_act->sa_mask = oact.sa_mask.sig[0];
5158 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005159 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005160 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005161#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005162 struct target_sigaction act, oact, *pact, *old_act;
5163
5164 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005165 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5166 goto efault;
bellard106ec872006-06-27 21:08:10 +00005167 act._sa_handler = old_act->_sa_handler;
5168 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5169 act.sa_flags = old_act->sa_flags;
5170 unlock_user_struct(old_act, arg2, 0);
5171 pact = &act;
5172 } else {
5173 pact = NULL;
5174 }
5175
5176 ret = get_errno(do_sigaction(arg1, pact, &oact));
5177
5178 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005179 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5180 goto efault;
bellard106ec872006-06-27 21:08:10 +00005181 old_act->_sa_handler = oact._sa_handler;
5182 old_act->sa_flags = oact.sa_flags;
5183 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5184 old_act->sa_mask.sig[1] = 0;
5185 old_act->sa_mask.sig[2] = 0;
5186 old_act->sa_mask.sig[3] = 0;
5187 unlock_user_struct(old_act, arg3, 1);
5188 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005189#else
5190 struct target_old_sigaction *old_act;
5191 struct target_sigaction act, oact, *pact;
5192 if (arg2) {
5193 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5194 goto efault;
5195 act._sa_handler = old_act->_sa_handler;
5196 target_siginitset(&act.sa_mask, old_act->sa_mask);
5197 act.sa_flags = old_act->sa_flags;
5198 act.sa_restorer = old_act->sa_restorer;
5199 unlock_user_struct(old_act, arg2, 0);
5200 pact = &act;
5201 } else {
5202 pact = NULL;
5203 }
5204 ret = get_errno(do_sigaction(arg1, pact, &oact));
5205 if (!is_error(ret) && arg3) {
5206 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5207 goto efault;
5208 old_act->_sa_handler = oact._sa_handler;
5209 old_act->sa_mask = oact.sa_mask.sig[0];
5210 old_act->sa_flags = oact.sa_flags;
5211 old_act->sa_restorer = oact.sa_restorer;
5212 unlock_user_struct(old_act, arg3, 1);
5213 }
ths388bb212007-05-13 13:58:00 +00005214#endif
bellard31e31b82003-02-18 22:55:36 +00005215 }
5216 break;
thse5febef2007-04-01 18:31:35 +00005217#endif
bellard66fb9762003-03-23 01:06:05 +00005218 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005219 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005220#if defined(TARGET_ALPHA)
5221 struct target_sigaction act, oact, *pact = 0;
5222 struct target_rt_sigaction *rt_act;
5223 /* ??? arg4 == sizeof(sigset_t). */
5224 if (arg2) {
5225 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5226 goto efault;
5227 act._sa_handler = rt_act->_sa_handler;
5228 act.sa_mask = rt_act->sa_mask;
5229 act.sa_flags = rt_act->sa_flags;
5230 act.sa_restorer = arg5;
5231 unlock_user_struct(rt_act, arg2, 0);
5232 pact = &act;
5233 }
5234 ret = get_errno(do_sigaction(arg1, pact, &oact));
5235 if (!is_error(ret) && arg3) {
5236 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5237 goto efault;
5238 rt_act->_sa_handler = oact._sa_handler;
5239 rt_act->sa_mask = oact.sa_mask;
5240 rt_act->sa_flags = oact.sa_flags;
5241 unlock_user_struct(rt_act, arg3, 1);
5242 }
5243#else
pbrook53a59602006-03-25 19:31:22 +00005244 struct target_sigaction *act;
5245 struct target_sigaction *oact;
5246
bellard579a97f2007-11-11 14:26:47 +00005247 if (arg2) {
5248 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5249 goto efault;
5250 } else
pbrook53a59602006-03-25 19:31:22 +00005251 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005252 if (arg3) {
5253 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5254 ret = -TARGET_EFAULT;
5255 goto rt_sigaction_fail;
5256 }
5257 } else
pbrook53a59602006-03-25 19:31:22 +00005258 oact = NULL;
5259 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005260 rt_sigaction_fail:
5261 if (act)
pbrook53a59602006-03-25 19:31:22 +00005262 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005263 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005264 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005265#endif
pbrook53a59602006-03-25 19:31:22 +00005266 }
bellard66fb9762003-03-23 01:06:05 +00005267 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005268#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005269 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005270 {
5271 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005272 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005273 sigprocmask(0, NULL, &cur_set);
5274 host_to_target_old_sigset(&target_set, &cur_set);
5275 ret = target_set;
5276 }
5277 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005278#endif
5279#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005280 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005281 {
5282 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005283 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005284 sigprocmask(0, NULL, &cur_set);
5285 target_to_host_old_sigset(&set, &target_set);
5286 sigorset(&set, &set, &cur_set);
5287 sigprocmask(SIG_SETMASK, &set, &oset);
5288 host_to_target_old_sigset(&target_set, &oset);
5289 ret = target_set;
5290 }
5291 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005292#endif
thse5febef2007-04-01 18:31:35 +00005293#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005294 case TARGET_NR_sigprocmask:
5295 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005296#if defined(TARGET_ALPHA)
5297 sigset_t set, oldset;
5298 abi_ulong mask;
5299 int how;
5300
5301 switch (arg1) {
5302 case TARGET_SIG_BLOCK:
5303 how = SIG_BLOCK;
5304 break;
5305 case TARGET_SIG_UNBLOCK:
5306 how = SIG_UNBLOCK;
5307 break;
5308 case TARGET_SIG_SETMASK:
5309 how = SIG_SETMASK;
5310 break;
5311 default:
5312 ret = -TARGET_EINVAL;
5313 goto fail;
5314 }
5315 mask = arg2;
5316 target_to_host_old_sigset(&set, &mask);
5317
5318 ret = get_errno(sigprocmask(how, &set, &oldset));
5319
5320 if (!is_error(ret)) {
5321 host_to_target_old_sigset(&mask, &oldset);
5322 ret = mask;
5323 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5324 }
5325#else
bellard66fb9762003-03-23 01:06:05 +00005326 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005327 int how;
ths3b46e622007-09-17 08:09:54 +00005328
pbrook53a59602006-03-25 19:31:22 +00005329 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005330 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005331 case TARGET_SIG_BLOCK:
5332 how = SIG_BLOCK;
5333 break;
5334 case TARGET_SIG_UNBLOCK:
5335 how = SIG_UNBLOCK;
5336 break;
5337 case TARGET_SIG_SETMASK:
5338 how = SIG_SETMASK;
5339 break;
5340 default:
ths0da46a62007-10-20 20:23:07 +00005341 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005342 goto fail;
5343 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005344 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005345 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005346 target_to_host_old_sigset(&set, p);
5347 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005348 set_ptr = &set;
5349 } else {
5350 how = 0;
5351 set_ptr = NULL;
5352 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005353 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005354 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005355 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005356 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005357 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005358 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005359 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005360#endif
bellard66fb9762003-03-23 01:06:05 +00005361 }
5362 break;
thse5febef2007-04-01 18:31:35 +00005363#endif
bellard66fb9762003-03-23 01:06:05 +00005364 case TARGET_NR_rt_sigprocmask:
5365 {
5366 int how = arg1;
5367 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005368
pbrook53a59602006-03-25 19:31:22 +00005369 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005370 switch(how) {
5371 case TARGET_SIG_BLOCK:
5372 how = SIG_BLOCK;
5373 break;
5374 case TARGET_SIG_UNBLOCK:
5375 how = SIG_UNBLOCK;
5376 break;
5377 case TARGET_SIG_SETMASK:
5378 how = SIG_SETMASK;
5379 break;
5380 default:
ths0da46a62007-10-20 20:23:07 +00005381 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005382 goto fail;
5383 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005384 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005385 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005386 target_to_host_sigset(&set, p);
5387 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005388 set_ptr = &set;
5389 } else {
5390 how = 0;
5391 set_ptr = NULL;
5392 }
5393 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005394 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005395 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005396 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005397 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005398 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005399 }
5400 }
5401 break;
thse5febef2007-04-01 18:31:35 +00005402#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005403 case TARGET_NR_sigpending:
5404 {
5405 sigset_t set;
5406 ret = get_errno(sigpending(&set));
5407 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005408 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005409 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005410 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005411 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005412 }
5413 }
5414 break;
thse5febef2007-04-01 18:31:35 +00005415#endif
bellard66fb9762003-03-23 01:06:05 +00005416 case TARGET_NR_rt_sigpending:
5417 {
5418 sigset_t set;
5419 ret = get_errno(sigpending(&set));
5420 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005421 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005422 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005423 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005424 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005425 }
5426 }
5427 break;
thse5febef2007-04-01 18:31:35 +00005428#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005429 case TARGET_NR_sigsuspend:
5430 {
5431 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005432#if defined(TARGET_ALPHA)
5433 abi_ulong mask = arg1;
5434 target_to_host_old_sigset(&set, &mask);
5435#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005436 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005437 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005438 target_to_host_old_sigset(&set, p);
5439 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005440#endif
bellard66fb9762003-03-23 01:06:05 +00005441 ret = get_errno(sigsuspend(&set));
5442 }
5443 break;
thse5febef2007-04-01 18:31:35 +00005444#endif
bellard66fb9762003-03-23 01:06:05 +00005445 case TARGET_NR_rt_sigsuspend:
5446 {
5447 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005448 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005449 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005450 target_to_host_sigset(&set, p);
5451 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005452 ret = get_errno(sigsuspend(&set));
5453 }
5454 break;
5455 case TARGET_NR_rt_sigtimedwait:
5456 {
bellard66fb9762003-03-23 01:06:05 +00005457 sigset_t set;
5458 struct timespec uts, *puts;
5459 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005460
Anthony Liguoric227f092009-10-01 16:12:16 -05005461 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005462 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005463 target_to_host_sigset(&set, p);
5464 unlock_user(p, arg1, 0);
5465 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005466 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005467 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005468 } else {
5469 puts = NULL;
5470 }
5471 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005472 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005473 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005474 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005475 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005476 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005477 }
5478 }
5479 break;
5480 case TARGET_NR_rt_sigqueueinfo:
5481 {
5482 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005483 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005484 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005485 target_to_host_siginfo(&uinfo, p);
5486 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005487 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5488 }
5489 break;
thse5febef2007-04-01 18:31:35 +00005490#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005491 case TARGET_NR_sigreturn:
5492 /* NOTE: ret is eax, so not transcoding must be done */
5493 ret = do_sigreturn(cpu_env);
5494 break;
thse5febef2007-04-01 18:31:35 +00005495#endif
bellard66fb9762003-03-23 01:06:05 +00005496 case TARGET_NR_rt_sigreturn:
5497 /* NOTE: ret is eax, so not transcoding must be done */
5498 ret = do_rt_sigreturn(cpu_env);
5499 break;
bellard31e31b82003-02-18 22:55:36 +00005500 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00005501 if (!(p = lock_user_string(arg1)))
5502 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005503 ret = get_errno(sethostname(p, arg2));
5504 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005505 break;
5506 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00005507 {
bellard9de5e442003-03-23 16:49:39 +00005508 int resource = arg1;
pbrook53a59602006-03-25 19:31:22 +00005509 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005510 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00005511 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
5512 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005513 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
5514 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005515 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00005516 ret = get_errno(setrlimit(resource, &rlim));
5517 }
5518 break;
bellard31e31b82003-02-18 22:55:36 +00005519 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00005520 {
bellard9de5e442003-03-23 16:49:39 +00005521 int resource = arg1;
pbrook53a59602006-03-25 19:31:22 +00005522 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005523 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00005524
bellard9de5e442003-03-23 16:49:39 +00005525 ret = get_errno(getrlimit(resource, &rlim));
5526 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005527 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
5528 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005529 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
5530 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005531 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00005532 }
5533 }
5534 break;
bellard31e31b82003-02-18 22:55:36 +00005535 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00005536 {
5537 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00005538 ret = get_errno(getrusage(arg1, &rusage));
5539 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005540 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00005541 }
5542 }
5543 break;
bellard31e31b82003-02-18 22:55:36 +00005544 case TARGET_NR_gettimeofday:
5545 {
bellard31e31b82003-02-18 22:55:36 +00005546 struct timeval tv;
5547 ret = get_errno(gettimeofday(&tv, NULL));
5548 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00005549 if (copy_to_user_timeval(arg1, &tv))
5550 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005551 }
5552 }
5553 break;
5554 case TARGET_NR_settimeofday:
5555 {
bellard31e31b82003-02-18 22:55:36 +00005556 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00005557 if (copy_from_user_timeval(&tv, arg1))
5558 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005559 ret = get_errno(settimeofday(&tv, NULL));
5560 }
5561 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005562#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00005563 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00005564 {
pbrook53a59602006-03-25 19:31:22 +00005565 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00005566 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00005567 long nsel;
5568
bellard579a97f2007-11-11 14:26:47 +00005569 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
5570 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005571 nsel = tswapl(sel->n);
5572 inp = tswapl(sel->inp);
5573 outp = tswapl(sel->outp);
5574 exp = tswapl(sel->exp);
5575 tvp = tswapl(sel->tvp);
5576 unlock_user_struct(sel, arg1, 0);
5577 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00005578 }
5579 break;
bellard048f6b42005-11-26 18:47:20 +00005580#endif
Riku Voipio9e423822010-05-07 12:28:05 +00005581#ifdef TARGET_NR_pselect6
5582 case TARGET_NR_pselect6:
5583 goto unimplemented_nowarn;
5584#endif
bellard31e31b82003-02-18 22:55:36 +00005585 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00005586 {
5587 void *p2;
5588 p = lock_user_string(arg1);
5589 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005590 if (!p || !p2)
5591 ret = -TARGET_EFAULT;
5592 else
5593 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005594 unlock_user(p2, arg2, 0);
5595 unlock_user(p, arg1, 0);
5596 }
bellard31e31b82003-02-18 22:55:36 +00005597 break;
thsf0b62432007-09-24 09:25:40 +00005598#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
5599 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00005600 {
bellard579a97f2007-11-11 14:26:47 +00005601 void *p2;
thsf0b62432007-09-24 09:25:40 +00005602 p = lock_user_string(arg1);
5603 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005604 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005605 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00005606 else
5607 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00005608 unlock_user(p2, arg3, 0);
5609 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00005610 }
5611 break;
5612#endif
bellardebc05482003-09-30 21:08:41 +00005613#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00005614 case TARGET_NR_oldlstat:
5615 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005616#endif
bellard31e31b82003-02-18 22:55:36 +00005617 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00005618 {
aurel32d088d662009-01-30 20:09:01 +00005619 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00005620 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00005621 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
5622 if (!p || !p2)
5623 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00005624 else {
5625 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
5626 char real[PATH_MAX];
5627 temp = realpath(exec_path,real);
5628 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
5629 snprintf((char *)p2, arg3, "%s", real);
5630 }
5631 else
5632 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00005633 }
pbrook53a59602006-03-25 19:31:22 +00005634 unlock_user(p2, arg2, ret);
5635 unlock_user(p, arg1, 0);
5636 }
bellard31e31b82003-02-18 22:55:36 +00005637 break;
ths5e0ccb12007-09-24 09:26:10 +00005638#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
5639 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00005640 {
bellard579a97f2007-11-11 14:26:47 +00005641 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00005642 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005643 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
5644 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005645 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00005646 else
5647 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00005648 unlock_user(p2, arg3, ret);
5649 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00005650 }
5651 break;
5652#endif
thse5febef2007-04-01 18:31:35 +00005653#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00005654 case TARGET_NR_uselib:
5655 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005656#endif
5657#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00005658 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00005659 if (!(p = lock_user_string(arg1)))
5660 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005661 ret = get_errno(swapon(p, arg2));
5662 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005663 break;
thse5febef2007-04-01 18:31:35 +00005664#endif
bellard31e31b82003-02-18 22:55:36 +00005665 case TARGET_NR_reboot:
5666 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005667#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00005668 case TARGET_NR_readdir:
5669 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005670#endif
5671#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00005672 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005673#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
5674 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
5675 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00005676 {
blueswir1992f48a2007-10-14 16:27:31 +00005677 abi_ulong *v;
5678 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00005679 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
5680 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005681 v1 = tswapl(v[0]);
5682 v2 = tswapl(v[1]);
5683 v3 = tswapl(v[2]);
5684 v4 = tswapl(v[3]);
5685 v5 = tswapl(v[4]);
5686 v6 = tswapl(v[5]);
5687 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00005688 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00005689 target_to_host_bitmask(v4, mmap_flags_tbl),
5690 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00005691 }
bellard31e31b82003-02-18 22:55:36 +00005692#else
ths5fafdf22007-09-16 21:08:06 +00005693 ret = get_errno(target_mmap(arg1, arg2, arg3,
5694 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00005695 arg5,
5696 arg6));
bellard31e31b82003-02-18 22:55:36 +00005697#endif
bellard6fb883e2003-07-09 17:12:39 +00005698 break;
thse5febef2007-04-01 18:31:35 +00005699#endif
bellarda315a142005-01-30 22:59:18 +00005700#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00005701 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00005702#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00005703#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00005704#endif
ths5fafdf22007-09-16 21:08:06 +00005705 ret = get_errno(target_mmap(arg1, arg2, arg3,
5706 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00005707 arg5,
bellardc573ff62004-01-04 15:51:36 +00005708 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00005709 break;
bellarda315a142005-01-30 22:59:18 +00005710#endif
bellard31e31b82003-02-18 22:55:36 +00005711 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00005712 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005713 break;
bellard9de5e442003-03-23 16:49:39 +00005714 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01005715 {
5716 TaskState *ts = ((CPUState *)cpu_env)->opaque;
5717 /* Special hack to detect libc making the stack executable. */
5718 if ((arg3 & PROT_GROWSDOWN)
5719 && arg1 >= ts->info->stack_limit
5720 && arg1 <= ts->info->start_stack) {
5721 arg3 &= ~PROT_GROWSDOWN;
5722 arg2 = arg2 + arg1 - ts->info->stack_limit;
5723 arg1 = ts->info->stack_limit;
5724 }
5725 }
bellard54936002003-05-13 00:25:15 +00005726 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005727 break;
thse5febef2007-04-01 18:31:35 +00005728#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00005729 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00005730 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00005731 break;
thse5febef2007-04-01 18:31:35 +00005732#endif
pbrook53a59602006-03-25 19:31:22 +00005733 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00005734#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00005735 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00005736 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005737 break;
thse5febef2007-04-01 18:31:35 +00005738#endif
5739#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00005740 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00005741 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005742 break;
thse5febef2007-04-01 18:31:35 +00005743#endif
5744#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00005745 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00005746 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005747 break;
thse5febef2007-04-01 18:31:35 +00005748#endif
5749#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00005750 case TARGET_NR_mlockall:
5751 ret = get_errno(mlockall(arg1));
5752 break;
thse5febef2007-04-01 18:31:35 +00005753#endif
5754#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00005755 case TARGET_NR_munlockall:
5756 ret = get_errno(munlockall());
5757 break;
thse5febef2007-04-01 18:31:35 +00005758#endif
bellard31e31b82003-02-18 22:55:36 +00005759 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00005760 if (!(p = lock_user_string(arg1)))
5761 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005762 ret = get_errno(truncate(p, arg2));
5763 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005764 break;
5765 case TARGET_NR_ftruncate:
5766 ret = get_errno(ftruncate(arg1, arg2));
5767 break;
5768 case TARGET_NR_fchmod:
5769 ret = get_errno(fchmod(arg1, arg2));
5770 break;
ths814d7972007-09-24 09:26:51 +00005771#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
5772 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00005773 if (!(p = lock_user_string(arg2)))
5774 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005775 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005776 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00005777 break;
5778#endif
bellard31e31b82003-02-18 22:55:36 +00005779 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00005780 /* libc does special remapping of the return value of
5781 * sys_getpriority() so it's just easiest to call
5782 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03005783 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005784 break;
5785 case TARGET_NR_setpriority:
5786 ret = get_errno(setpriority(arg1, arg2, arg3));
5787 break;
bellardebc05482003-09-30 21:08:41 +00005788#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00005789 case TARGET_NR_profil:
5790 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005791#endif
bellard31e31b82003-02-18 22:55:36 +00005792 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00005793 if (!(p = lock_user_string(arg1)))
5794 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005795 ret = get_errno(statfs(path(p), &stfs));
5796 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005797 convert_statfs:
5798 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005799 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00005800
bellard579a97f2007-11-11 14:26:47 +00005801 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
5802 goto efault;
5803 __put_user(stfs.f_type, &target_stfs->f_type);
5804 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
5805 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
5806 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
5807 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
5808 __put_user(stfs.f_files, &target_stfs->f_files);
5809 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
5810 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
5811 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
5812 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00005813 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00005814 }
5815 break;
5816 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00005817 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00005818 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00005819#ifdef TARGET_NR_statfs64
5820 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00005821 if (!(p = lock_user_string(arg1)))
5822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005823 ret = get_errno(statfs(path(p), &stfs));
5824 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00005825 convert_statfs64:
5826 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005827 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00005828
bellard579a97f2007-11-11 14:26:47 +00005829 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
5830 goto efault;
5831 __put_user(stfs.f_type, &target_stfs->f_type);
5832 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
5833 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
5834 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
5835 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
5836 __put_user(stfs.f_files, &target_stfs->f_files);
5837 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
5838 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
5839 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
5840 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
5841 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00005842 }
5843 break;
5844 case TARGET_NR_fstatfs64:
5845 ret = get_errno(fstatfs(arg1, &stfs));
5846 goto convert_statfs64;
5847#endif
bellardebc05482003-09-30 21:08:41 +00005848#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00005849 case TARGET_NR_ioperm:
5850 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005851#endif
thse5febef2007-04-01 18:31:35 +00005852#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00005853 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00005854 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00005855 break;
thse5febef2007-04-01 18:31:35 +00005856#endif
bellard3532fa72006-06-24 15:06:03 +00005857#ifdef TARGET_NR_accept
5858 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00005859 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00005860 break;
5861#endif
5862#ifdef TARGET_NR_bind
5863 case TARGET_NR_bind:
5864 ret = do_bind(arg1, arg2, arg3);
5865 break;
5866#endif
5867#ifdef TARGET_NR_connect
5868 case TARGET_NR_connect:
5869 ret = do_connect(arg1, arg2, arg3);
5870 break;
5871#endif
5872#ifdef TARGET_NR_getpeername
5873 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00005874 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00005875 break;
5876#endif
5877#ifdef TARGET_NR_getsockname
5878 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00005879 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00005880 break;
5881#endif
5882#ifdef TARGET_NR_getsockopt
5883 case TARGET_NR_getsockopt:
5884 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
5885 break;
5886#endif
5887#ifdef TARGET_NR_listen
5888 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00005889 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00005890 break;
5891#endif
5892#ifdef TARGET_NR_recv
5893 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00005894 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00005895 break;
5896#endif
5897#ifdef TARGET_NR_recvfrom
5898 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00005899 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00005900 break;
5901#endif
5902#ifdef TARGET_NR_recvmsg
5903 case TARGET_NR_recvmsg:
5904 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
5905 break;
5906#endif
5907#ifdef TARGET_NR_send
5908 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00005909 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00005910 break;
5911#endif
5912#ifdef TARGET_NR_sendmsg
5913 case TARGET_NR_sendmsg:
5914 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
5915 break;
5916#endif
5917#ifdef TARGET_NR_sendto
5918 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00005919 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00005920 break;
5921#endif
5922#ifdef TARGET_NR_shutdown
5923 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00005924 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00005925 break;
5926#endif
5927#ifdef TARGET_NR_socket
5928 case TARGET_NR_socket:
5929 ret = do_socket(arg1, arg2, arg3);
5930 break;
5931#endif
5932#ifdef TARGET_NR_socketpair
5933 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00005934 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00005935 break;
5936#endif
5937#ifdef TARGET_NR_setsockopt
5938 case TARGET_NR_setsockopt:
5939 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
5940 break;
5941#endif
ths7494b0f2007-02-11 18:26:53 +00005942
bellard31e31b82003-02-18 22:55:36 +00005943 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00005944 if (!(p = lock_user_string(arg2)))
5945 goto efault;
thse5574482007-02-11 20:03:13 +00005946 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
5947 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00005948 break;
5949
bellard31e31b82003-02-18 22:55:36 +00005950 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00005951 {
bellard66fb9762003-03-23 01:06:05 +00005952 struct itimerval value, ovalue, *pvalue;
5953
pbrook53a59602006-03-25 19:31:22 +00005954 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005955 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00005956 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
5957 || copy_from_user_timeval(&pvalue->it_value,
5958 arg2 + sizeof(struct target_timeval)))
5959 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005960 } else {
5961 pvalue = NULL;
5962 }
5963 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00005964 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00005965 if (copy_to_user_timeval(arg3,
5966 &ovalue.it_interval)
5967 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
5968 &ovalue.it_value))
5969 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005970 }
5971 }
5972 break;
bellard31e31b82003-02-18 22:55:36 +00005973 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00005974 {
bellard66fb9762003-03-23 01:06:05 +00005975 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00005976
bellard66fb9762003-03-23 01:06:05 +00005977 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00005978 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00005979 if (copy_to_user_timeval(arg2,
5980 &value.it_interval)
5981 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
5982 &value.it_value))
5983 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005984 }
5985 }
5986 break;
bellard31e31b82003-02-18 22:55:36 +00005987 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00005988 if (!(p = lock_user_string(arg1)))
5989 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005990 ret = get_errno(stat(path(p), &st));
5991 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005992 goto do_stat;
5993 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00005994 if (!(p = lock_user_string(arg1)))
5995 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005996 ret = get_errno(lstat(path(p), &st));
5997 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005998 goto do_stat;
5999 case TARGET_NR_fstat:
6000 {
6001 ret = get_errno(fstat(arg1, &st));
6002 do_stat:
6003 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006004 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006005
bellard579a97f2007-11-11 14:26:47 +00006006 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6007 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006008 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006009 __put_user(st.st_dev, &target_st->st_dev);
6010 __put_user(st.st_ino, &target_st->st_ino);
6011 __put_user(st.st_mode, &target_st->st_mode);
6012 __put_user(st.st_uid, &target_st->st_uid);
6013 __put_user(st.st_gid, &target_st->st_gid);
6014 __put_user(st.st_nlink, &target_st->st_nlink);
6015 __put_user(st.st_rdev, &target_st->st_rdev);
6016 __put_user(st.st_size, &target_st->st_size);
6017 __put_user(st.st_blksize, &target_st->st_blksize);
6018 __put_user(st.st_blocks, &target_st->st_blocks);
6019 __put_user(st.st_atime, &target_st->target_st_atime);
6020 __put_user(st.st_mtime, &target_st->target_st_mtime);
6021 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006022 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006023 }
6024 }
6025 break;
bellardebc05482003-09-30 21:08:41 +00006026#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006027 case TARGET_NR_olduname:
6028 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006029#endif
6030#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006031 case TARGET_NR_iopl:
6032 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006033#endif
bellard31e31b82003-02-18 22:55:36 +00006034 case TARGET_NR_vhangup:
6035 ret = get_errno(vhangup());
6036 break;
bellardebc05482003-09-30 21:08:41 +00006037#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006038 case TARGET_NR_idle:
6039 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006040#endif
bellard42ad6ae2005-01-03 22:48:11 +00006041#ifdef TARGET_NR_syscall
6042 case TARGET_NR_syscall:
6043 ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
6044 break;
6045#endif
bellard31e31b82003-02-18 22:55:36 +00006046 case TARGET_NR_wait4:
6047 {
6048 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006049 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006050 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006051 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006052 if (target_rusage)
6053 rusage_ptr = &rusage;
6054 else
6055 rusage_ptr = NULL;
6056 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6057 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006058 if (status_ptr) {
pbrook1d9d8b52009-04-16 15:17:02 +00006059 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006060 if (put_user_s32(status, status_ptr))
6061 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006062 }
bellard2f619692007-11-16 10:46:05 +00006063 if (target_rusage)
6064 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006065 }
6066 }
6067 break;
thse5febef2007-04-01 18:31:35 +00006068#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006069 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006070 if (!(p = lock_user_string(arg1)))
6071 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006072 ret = get_errno(swapoff(p));
6073 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006074 break;
thse5febef2007-04-01 18:31:35 +00006075#endif
bellard31e31b82003-02-18 22:55:36 +00006076 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006077 {
pbrook53a59602006-03-25 19:31:22 +00006078 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006079 struct sysinfo value;
6080 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006081 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006082 {
bellard579a97f2007-11-11 14:26:47 +00006083 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6084 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006085 __put_user(value.uptime, &target_value->uptime);
6086 __put_user(value.loads[0], &target_value->loads[0]);
6087 __put_user(value.loads[1], &target_value->loads[1]);
6088 __put_user(value.loads[2], &target_value->loads[2]);
6089 __put_user(value.totalram, &target_value->totalram);
6090 __put_user(value.freeram, &target_value->freeram);
6091 __put_user(value.sharedram, &target_value->sharedram);
6092 __put_user(value.bufferram, &target_value->bufferram);
6093 __put_user(value.totalswap, &target_value->totalswap);
6094 __put_user(value.freeswap, &target_value->freeswap);
6095 __put_user(value.procs, &target_value->procs);
6096 __put_user(value.totalhigh, &target_value->totalhigh);
6097 __put_user(value.freehigh, &target_value->freehigh);
6098 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006099 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006100 }
6101 }
6102 break;
thse5febef2007-04-01 18:31:35 +00006103#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006104 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006105 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6106 break;
thse5febef2007-04-01 18:31:35 +00006107#endif
aurel32e5289082009-04-18 16:16:12 +00006108#ifdef TARGET_NR_semget
6109 case TARGET_NR_semget:
6110 ret = get_errno(semget(arg1, arg2, arg3));
6111 break;
6112#endif
6113#ifdef TARGET_NR_semop
6114 case TARGET_NR_semop:
6115 ret = get_errno(do_semop(arg1, arg2, arg3));
6116 break;
6117#endif
6118#ifdef TARGET_NR_semctl
6119 case TARGET_NR_semctl:
6120 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6121 break;
6122#endif
aurel32eeb438c2008-10-13 21:08:55 +00006123#ifdef TARGET_NR_msgctl
6124 case TARGET_NR_msgctl:
6125 ret = do_msgctl(arg1, arg2, arg3);
6126 break;
6127#endif
6128#ifdef TARGET_NR_msgget
6129 case TARGET_NR_msgget:
6130 ret = get_errno(msgget(arg1, arg2));
6131 break;
6132#endif
6133#ifdef TARGET_NR_msgrcv
6134 case TARGET_NR_msgrcv:
6135 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6136 break;
6137#endif
6138#ifdef TARGET_NR_msgsnd
6139 case TARGET_NR_msgsnd:
6140 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6141 break;
6142#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006143#ifdef TARGET_NR_shmget
6144 case TARGET_NR_shmget:
6145 ret = get_errno(shmget(arg1, arg2, arg3));
6146 break;
6147#endif
6148#ifdef TARGET_NR_shmctl
6149 case TARGET_NR_shmctl:
6150 ret = do_shmctl(arg1, arg2, arg3);
6151 break;
6152#endif
6153#ifdef TARGET_NR_shmat
6154 case TARGET_NR_shmat:
6155 ret = do_shmat(arg1, arg2, arg3);
6156 break;
6157#endif
6158#ifdef TARGET_NR_shmdt
6159 case TARGET_NR_shmdt:
6160 ret = do_shmdt(arg1);
6161 break;
6162#endif
bellard31e31b82003-02-18 22:55:36 +00006163 case TARGET_NR_fsync:
6164 ret = get_errno(fsync(arg1));
6165 break;
bellard31e31b82003-02-18 22:55:36 +00006166 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006167#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006168 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006169#elif defined(TARGET_CRIS)
6170 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006171#elif defined(TARGET_S390X)
6172 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006173#else
pbrookd865bab2008-06-07 22:12:17 +00006174 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006175#endif
bellard1b6b0292003-03-22 17:31:38 +00006176 break;
bellardec86b0f2003-04-11 00:15:04 +00006177#ifdef __NR_exit_group
6178 /* new thread calls */
6179 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006180#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006181 _mcleanup();
6182#endif
bellarde9009672005-04-26 20:42:36 +00006183 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006184 ret = get_errno(exit_group(arg1));
6185 break;
6186#endif
bellard31e31b82003-02-18 22:55:36 +00006187 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006188 if (!(p = lock_user_string(arg1)))
6189 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006190 ret = get_errno(setdomainname(p, arg2));
6191 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006192 break;
6193 case TARGET_NR_uname:
6194 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006195 {
6196 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006197
bellard579a97f2007-11-11 14:26:47 +00006198 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6199 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006200 ret = get_errno(sys_uname(buf));
6201 if (!is_error(ret)) {
6202 /* Overrite the native machine name with whatever is being
6203 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006204 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006205 /* Allow the user to override the reported release. */
6206 if (qemu_uname_release && *qemu_uname_release)
6207 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006208 }
pbrook53a59602006-03-25 19:31:22 +00006209 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006210 }
bellard31e31b82003-02-18 22:55:36 +00006211 break;
bellard6dbad632003-03-16 18:05:05 +00006212#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006213 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006214 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006215 break;
j_mayer84409dd2007-04-06 08:56:50 +00006216#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006217 case TARGET_NR_vm86old:
6218 goto unimplemented;
6219 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006220 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006221 break;
6222#endif
j_mayer84409dd2007-04-06 08:56:50 +00006223#endif
bellard31e31b82003-02-18 22:55:36 +00006224 case TARGET_NR_adjtimex:
6225 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006226#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006227 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006228#endif
bellard31e31b82003-02-18 22:55:36 +00006229 case TARGET_NR_init_module:
6230 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006231#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006232 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006233#endif
bellard31e31b82003-02-18 22:55:36 +00006234 goto unimplemented;
6235 case TARGET_NR_quotactl:
6236 goto unimplemented;
6237 case TARGET_NR_getpgid:
6238 ret = get_errno(getpgid(arg1));
6239 break;
6240 case TARGET_NR_fchdir:
6241 ret = get_errno(fchdir(arg1));
6242 break;
j_mayer84409dd2007-04-06 08:56:50 +00006243#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006244 case TARGET_NR_bdflush:
6245 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006246#endif
thse5febef2007-04-01 18:31:35 +00006247#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006248 case TARGET_NR_sysfs:
6249 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006250#endif
bellard31e31b82003-02-18 22:55:36 +00006251 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006252 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006253 break;
thse5febef2007-04-01 18:31:35 +00006254#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006255 case TARGET_NR_afs_syscall:
6256 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006257#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006258#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006259 case TARGET_NR__llseek:
6260 {
6261 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006262#if !defined(__NR_llseek)
6263 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6264 if (res == -1) {
6265 ret = get_errno(res);
6266 } else {
6267 ret = 0;
6268 }
6269#else
bellard31e31b82003-02-18 22:55:36 +00006270 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006271#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006272 if ((ret == 0) && put_user_s64(res, arg4)) {
6273 goto efault;
6274 }
bellard31e31b82003-02-18 22:55:36 +00006275 }
6276 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006277#endif
bellard31e31b82003-02-18 22:55:36 +00006278 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006279#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006280 {
pbrook53a59602006-03-25 19:31:22 +00006281 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006282 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006283 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006284
6285 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006286 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006287 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006288 goto fail;
6289 }
ths3b46e622007-09-17 08:09:54 +00006290
bellard4add45b2003-06-05 01:52:59 +00006291 ret = get_errno(sys_getdents(arg1, dirp, count));
6292 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006293 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006294 struct target_dirent *tde;
6295 int len = ret;
6296 int reclen, treclen;
6297 int count1, tnamelen;
6298
6299 count1 = 0;
6300 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006301 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6302 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006303 tde = target_dirp;
6304 while (len > 0) {
6305 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006306 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006307 tde->d_reclen = tswap16(treclen);
6308 tde->d_ino = tswapl(de->d_ino);
6309 tde->d_off = tswapl(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006310 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006311 if (tnamelen > 256)
6312 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006313 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006314 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006315 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006316 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006317 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006318 count1 += treclen;
6319 }
6320 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006321 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006322 }
6323 free(dirp);
6324 }
6325#else
bellard31e31b82003-02-18 22:55:36 +00006326 {
aurel326556a832008-10-13 21:08:17 +00006327 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006328 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006329
bellard579a97f2007-11-11 14:26:47 +00006330 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6331 goto efault;
bellard72f03902003-02-18 23:33:18 +00006332 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006333 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006334 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006335 int len = ret;
6336 int reclen;
6337 de = dirp;
6338 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006339 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006340 if (reclen > len)
6341 break;
bellard8083a3e2003-03-24 23:12:16 +00006342 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006343 tswapls(&de->d_ino);
6344 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006345 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006346 len -= reclen;
6347 }
6348 }
pbrook53a59602006-03-25 19:31:22 +00006349 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006350 }
bellard4add45b2003-06-05 01:52:59 +00006351#endif
bellard31e31b82003-02-18 22:55:36 +00006352 break;
ths3ae43202007-09-16 21:39:48 +00006353#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006354 case TARGET_NR_getdents64:
6355 {
aurel326556a832008-10-13 21:08:17 +00006356 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006357 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006358 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6359 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006360 ret = get_errno(sys_getdents64(arg1, dirp, count));
6361 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006362 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006363 int len = ret;
6364 int reclen;
6365 de = dirp;
6366 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006367 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006368 if (reclen > len)
6369 break;
bellard8083a3e2003-03-24 23:12:16 +00006370 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006371 tswap64s((uint64_t *)&de->d_ino);
6372 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006373 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006374 len -= reclen;
6375 }
6376 }
pbrook53a59602006-03-25 19:31:22 +00006377 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006378 }
6379 break;
bellarda541f292004-04-12 20:39:29 +00006380#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006381#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
6382#ifdef TARGET_S390X
6383 case TARGET_NR_select:
6384#else
bellard31e31b82003-02-18 22:55:36 +00006385 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006386#endif
pbrook53a59602006-03-25 19:31:22 +00006387 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00006388 break;
thse5febef2007-04-01 18:31:35 +00006389#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05006390#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
6391# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00006392 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05006393# endif
6394# ifdef TARGET_NR_ppoll
6395 case TARGET_NR_ppoll:
6396# endif
bellard9de5e442003-03-23 16:49:39 +00006397 {
pbrook53a59602006-03-25 19:31:22 +00006398 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00006399 unsigned int nfds = arg2;
6400 int timeout = arg3;
6401 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00006402 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00006403
bellard579a97f2007-11-11 14:26:47 +00006404 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
6405 if (!target_pfd)
6406 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05006407
bellard9de5e442003-03-23 16:49:39 +00006408 pfd = alloca(sizeof(struct pollfd) * nfds);
6409 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006410 pfd[i].fd = tswap32(target_pfd[i].fd);
6411 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00006412 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05006413
6414# ifdef TARGET_NR_ppoll
6415 if (num == TARGET_NR_ppoll) {
6416 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
6417 target_sigset_t *target_set;
6418 sigset_t _set, *set = &_set;
6419
6420 if (arg3) {
6421 if (target_to_host_timespec(timeout_ts, arg3)) {
6422 unlock_user(target_pfd, arg1, 0);
6423 goto efault;
6424 }
6425 } else {
6426 timeout_ts = NULL;
6427 }
6428
6429 if (arg4) {
6430 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
6431 if (!target_set) {
6432 unlock_user(target_pfd, arg1, 0);
6433 goto efault;
6434 }
6435 target_to_host_sigset(set, target_set);
6436 } else {
6437 set = NULL;
6438 }
6439
6440 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
6441
6442 if (!is_error(ret) && arg3) {
6443 host_to_target_timespec(arg3, timeout_ts);
6444 }
6445 if (arg4) {
6446 unlock_user(target_set, arg4, 0);
6447 }
6448 } else
6449# endif
6450 ret = get_errno(poll(pfd, nfds, timeout));
6451
bellard9de5e442003-03-23 16:49:39 +00006452 if (!is_error(ret)) {
6453 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006454 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00006455 }
6456 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00006457 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00006458 }
6459 break;
thse5febef2007-04-01 18:31:35 +00006460#endif
bellard31e31b82003-02-18 22:55:36 +00006461 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00006462 /* NOTE: the flock constant seems to be the same for every
6463 Linux platform */
6464 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006465 break;
6466 case TARGET_NR_readv:
6467 {
6468 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006469 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006470
6471 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006472 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
6473 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006474 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006475 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00006476 }
6477 break;
6478 case TARGET_NR_writev:
6479 {
6480 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006481 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006482
6483 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006484 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
6485 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006486 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006487 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00006488 }
6489 break;
6490 case TARGET_NR_getsid:
6491 ret = get_errno(getsid(arg1));
6492 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006493#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00006494 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00006495 ret = get_errno(fdatasync(arg1));
6496 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006497#endif
bellard31e31b82003-02-18 22:55:36 +00006498 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00006499 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00006500 return value. */
ths0da46a62007-10-20 20:23:07 +00006501 ret = -TARGET_ENOTDIR;
6502 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05006503 case TARGET_NR_sched_getaffinity:
6504 {
6505 unsigned int mask_size;
6506 unsigned long *mask;
6507
6508 /*
6509 * sched_getaffinity needs multiples of ulong, so need to take
6510 * care of mismatches between target ulong and host ulong sizes.
6511 */
6512 if (arg2 & (sizeof(abi_ulong) - 1)) {
6513 ret = -TARGET_EINVAL;
6514 break;
6515 }
6516 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6517
6518 mask = alloca(mask_size);
6519 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
6520
6521 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09006522 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05006523 goto efault;
6524 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05006525 }
6526 }
6527 break;
6528 case TARGET_NR_sched_setaffinity:
6529 {
6530 unsigned int mask_size;
6531 unsigned long *mask;
6532
6533 /*
6534 * sched_setaffinity needs multiples of ulong, so need to take
6535 * care of mismatches between target ulong and host ulong sizes.
6536 */
6537 if (arg2 & (sizeof(abi_ulong) - 1)) {
6538 ret = -TARGET_EINVAL;
6539 break;
6540 }
6541 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6542
6543 mask = alloca(mask_size);
6544 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
6545 goto efault;
6546 }
6547 memcpy(mask, p, arg2);
6548 unlock_user_struct(p, arg2, 0);
6549
6550 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
6551 }
6552 break;
bellard31e31b82003-02-18 22:55:36 +00006553 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00006554 {
pbrook53a59602006-03-25 19:31:22 +00006555 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006556 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00006557
bellard579a97f2007-11-11 14:26:47 +00006558 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
6559 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006560 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006561 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00006562 ret = get_errno(sched_setparam(arg1, &schp));
6563 }
6564 break;
bellard31e31b82003-02-18 22:55:36 +00006565 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00006566 {
pbrook53a59602006-03-25 19:31:22 +00006567 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006568 struct sched_param schp;
6569 ret = get_errno(sched_getparam(arg1, &schp));
6570 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006571 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
6572 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006573 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006574 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00006575 }
6576 }
6577 break;
bellard31e31b82003-02-18 22:55:36 +00006578 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00006579 {
pbrook53a59602006-03-25 19:31:22 +00006580 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006581 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00006582 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
6583 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006584 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006585 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00006586 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
6587 }
6588 break;
bellard31e31b82003-02-18 22:55:36 +00006589 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00006590 ret = get_errno(sched_getscheduler(arg1));
6591 break;
bellard31e31b82003-02-18 22:55:36 +00006592 case TARGET_NR_sched_yield:
6593 ret = get_errno(sched_yield());
6594 break;
6595 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00006596 ret = get_errno(sched_get_priority_max(arg1));
6597 break;
bellard31e31b82003-02-18 22:55:36 +00006598 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00006599 ret = get_errno(sched_get_priority_min(arg1));
6600 break;
bellard31e31b82003-02-18 22:55:36 +00006601 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00006602 {
bellard5cd43932003-03-29 16:54:36 +00006603 struct timespec ts;
6604 ret = get_errno(sched_rr_get_interval(arg1, &ts));
6605 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006606 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00006607 }
6608 }
6609 break;
bellard31e31b82003-02-18 22:55:36 +00006610 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00006611 {
bellard1b6b0292003-03-22 17:31:38 +00006612 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00006613 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00006614 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00006615 if (is_error(ret) && arg2) {
6616 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00006617 }
6618 }
6619 break;
thse5febef2007-04-01 18:31:35 +00006620#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00006621 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00006622 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006623#endif
6624#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00006625 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00006626 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006627#endif
bellard31e31b82003-02-18 22:55:36 +00006628 case TARGET_NR_prctl:
thse5574482007-02-11 20:03:13 +00006629 switch (arg1)
6630 {
6631 case PR_GET_PDEATHSIG:
6632 {
6633 int deathsig;
6634 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
bellard2f619692007-11-16 10:46:05 +00006635 if (!is_error(ret) && arg2
6636 && put_user_ual(deathsig, arg2))
6637 goto efault;
thse5574482007-02-11 20:03:13 +00006638 }
6639 break;
6640 default:
6641 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
6642 break;
6643 }
ths39b9aae2007-02-11 18:36:44 +00006644 break;
bellardd2fd1af2007-11-14 18:08:56 +00006645#ifdef TARGET_NR_arch_prctl
6646 case TARGET_NR_arch_prctl:
6647#if defined(TARGET_I386) && !defined(TARGET_ABI32)
6648 ret = do_arch_prctl(cpu_env, arg1, arg2);
6649 break;
6650#else
6651 goto unimplemented;
6652#endif
6653#endif
bellard67867302003-11-23 17:05:30 +00006654#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00006655 case TARGET_NR_pread:
balroga4ae00b2008-09-20 03:14:14 +00006656#ifdef TARGET_ARM
6657 if (((CPUARMState *)cpu_env)->eabi)
6658 arg4 = arg5;
6659#endif
bellard579a97f2007-11-11 14:26:47 +00006660 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6661 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006662 ret = get_errno(pread(arg1, p, arg3, arg4));
6663 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00006664 break;
bellard31e31b82003-02-18 22:55:36 +00006665 case TARGET_NR_pwrite:
balroga4ae00b2008-09-20 03:14:14 +00006666#ifdef TARGET_ARM
6667 if (((CPUARMState *)cpu_env)->eabi)
6668 arg4 = arg5;
6669#endif
bellard579a97f2007-11-11 14:26:47 +00006670 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6671 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006672 ret = get_errno(pwrite(arg1, p, arg3, arg4));
6673 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00006674 break;
bellard67867302003-11-23 17:05:30 +00006675#endif
aurel32f2c7ba12008-03-28 22:32:06 +00006676#ifdef TARGET_NR_pread64
6677 case TARGET_NR_pread64:
6678 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6679 goto efault;
6680 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
6681 unlock_user(p, arg2, ret);
6682 break;
6683 case TARGET_NR_pwrite64:
6684 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6685 goto efault;
6686 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
6687 unlock_user(p, arg2, 0);
6688 break;
6689#endif
bellard31e31b82003-02-18 22:55:36 +00006690 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00006691 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
6692 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006693 ret = get_errno(sys_getcwd1(p, arg2));
6694 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00006695 break;
6696 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00006697 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006698 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00006699 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006700 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00006701#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02006702 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006703 defined(TARGET_M68K) || defined(TARGET_S390X)
bellard579a97f2007-11-11 14:26:47 +00006704 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00006705 break;
6706#else
bellard5cd43932003-03-29 16:54:36 +00006707 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00006708#endif
bellard31e31b82003-02-18 22:55:36 +00006709 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00006710 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006711#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00006712 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00006713 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006714#endif
6715#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00006716 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00006717 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006718#endif
bellard048f6b42005-11-26 18:47:20 +00006719#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00006720 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00006721 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
6722 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006723 break;
bellard048f6b42005-11-26 18:47:20 +00006724#endif
bellardebc05482003-09-30 21:08:41 +00006725#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00006726 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00006727 {
6728 struct rlimit rlim;
6729 ret = get_errno(getrlimit(arg1, &rlim));
6730 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006731 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00006732 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6733 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006734 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6735 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006736 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00006737 }
6738 break;
6739 }
bellardebc05482003-09-30 21:08:41 +00006740#endif
bellarda315a142005-01-30 22:59:18 +00006741#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00006742 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00006743 if (!(p = lock_user_string(arg1)))
6744 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006745 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
6746 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00006747 break;
bellarda315a142005-01-30 22:59:18 +00006748#endif
6749#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00006750 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00006751 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00006752 break;
bellarda315a142005-01-30 22:59:18 +00006753#endif
6754#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00006755 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00006756 if (!(p = lock_user_string(arg1)))
6757 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006758 ret = get_errno(stat(path(p), &st));
6759 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006760 if (!is_error(ret))
6761 ret = host_to_target_stat64(cpu_env, arg2, &st);
6762 break;
bellarda315a142005-01-30 22:59:18 +00006763#endif
6764#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00006765 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00006766 if (!(p = lock_user_string(arg1)))
6767 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006768 ret = get_errno(lstat(path(p), &st));
6769 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006770 if (!is_error(ret))
6771 ret = host_to_target_stat64(cpu_env, arg2, &st);
6772 break;
bellarda315a142005-01-30 22:59:18 +00006773#endif
6774#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00006775 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00006776 ret = get_errno(fstat(arg1, &st));
6777 if (!is_error(ret))
6778 ret = host_to_target_stat64(cpu_env, arg2, &st);
6779 break;
bellardec86b0f2003-04-11 00:15:04 +00006780#endif
aurel329d33b762009-04-08 23:07:05 +00006781#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
6782 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
6783#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006784 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00006785#endif
6786#ifdef TARGET_NR_newfstatat
6787 case TARGET_NR_newfstatat:
6788#endif
balrog6a24a772008-09-20 02:23:36 +00006789 if (!(p = lock_user_string(arg2)))
6790 goto efault;
aurel329d33b762009-04-08 23:07:05 +00006791#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006792 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00006793#else
6794 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
6795#endif
balrog6a24a772008-09-20 02:23:36 +00006796 if (!is_error(ret))
6797 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00006798 break;
bellarda315a142005-01-30 22:59:18 +00006799#endif
bellard67867302003-11-23 17:05:30 +00006800 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00006801 if (!(p = lock_user_string(arg1)))
6802 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006803 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
6804 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00006805 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006806#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00006807 case TARGET_NR_getuid:
6808 ret = get_errno(high2lowuid(getuid()));
6809 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006810#endif
6811#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00006812 case TARGET_NR_getgid:
6813 ret = get_errno(high2lowgid(getgid()));
6814 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006815#endif
6816#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00006817 case TARGET_NR_geteuid:
6818 ret = get_errno(high2lowuid(geteuid()));
6819 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006820#endif
6821#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00006822 case TARGET_NR_getegid:
6823 ret = get_errno(high2lowgid(getegid()));
6824 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006825#endif
bellard67867302003-11-23 17:05:30 +00006826 case TARGET_NR_setreuid:
6827 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
6828 break;
6829 case TARGET_NR_setregid:
6830 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
6831 break;
6832 case TARGET_NR_getgroups:
6833 {
6834 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03006835 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00006836 gid_t *grouplist;
6837 int i;
6838
6839 grouplist = alloca(gidsetsize * sizeof(gid_t));
6840 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00006841 if (gidsetsize == 0)
6842 break;
bellard67867302003-11-23 17:05:30 +00006843 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006844 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
6845 if (!target_grouplist)
6846 goto efault;
balroga2155fc2008-09-20 02:12:08 +00006847 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03006848 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00006849 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00006850 }
6851 }
6852 break;
6853 case TARGET_NR_setgroups:
6854 {
6855 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03006856 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00006857 gid_t *grouplist;
6858 int i;
6859
6860 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00006861 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
6862 if (!target_grouplist) {
6863 ret = -TARGET_EFAULT;
6864 goto fail;
6865 }
bellard67867302003-11-23 17:05:30 +00006866 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03006867 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00006868 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00006869 ret = get_errno(setgroups(gidsetsize, grouplist));
6870 }
6871 break;
6872 case TARGET_NR_fchown:
6873 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
6874 break;
thsccfa72b2007-09-24 09:23:34 +00006875#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
6876 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00006877 if (!(p = lock_user_string(arg2)))
6878 goto efault;
6879 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
6880 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00006881 break;
6882#endif
bellard67867302003-11-23 17:05:30 +00006883#ifdef TARGET_NR_setresuid
6884 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00006885 ret = get_errno(setresuid(low2highuid(arg1),
6886 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00006887 low2highuid(arg3)));
6888 break;
6889#endif
6890#ifdef TARGET_NR_getresuid
6891 case TARGET_NR_getresuid:
6892 {
pbrook53a59602006-03-25 19:31:22 +00006893 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00006894 ret = get_errno(getresuid(&ruid, &euid, &suid));
6895 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006896 if (put_user_u16(high2lowuid(ruid), arg1)
6897 || put_user_u16(high2lowuid(euid), arg2)
6898 || put_user_u16(high2lowuid(suid), arg3))
6899 goto efault;
bellard67867302003-11-23 17:05:30 +00006900 }
6901 }
6902 break;
6903#endif
6904#ifdef TARGET_NR_getresgid
6905 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00006906 ret = get_errno(setresgid(low2highgid(arg1),
6907 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00006908 low2highgid(arg3)));
6909 break;
6910#endif
6911#ifdef TARGET_NR_getresgid
6912 case TARGET_NR_getresgid:
6913 {
pbrook53a59602006-03-25 19:31:22 +00006914 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00006915 ret = get_errno(getresgid(&rgid, &egid, &sgid));
6916 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006917 if (put_user_u16(high2lowgid(rgid), arg1)
6918 || put_user_u16(high2lowgid(egid), arg2)
6919 || put_user_u16(high2lowgid(sgid), arg3))
6920 goto efault;
bellard67867302003-11-23 17:05:30 +00006921 }
6922 }
6923 break;
6924#endif
6925 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00006926 if (!(p = lock_user_string(arg1)))
6927 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006928 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
6929 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00006930 break;
6931 case TARGET_NR_setuid:
6932 ret = get_errno(setuid(low2highuid(arg1)));
6933 break;
6934 case TARGET_NR_setgid:
6935 ret = get_errno(setgid(low2highgid(arg1)));
6936 break;
6937 case TARGET_NR_setfsuid:
6938 ret = get_errno(setfsuid(arg1));
6939 break;
6940 case TARGET_NR_setfsgid:
6941 ret = get_errno(setfsgid(arg1));
6942 break;
bellard67867302003-11-23 17:05:30 +00006943
bellarda315a142005-01-30 22:59:18 +00006944#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00006945 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00006946 if (!(p = lock_user_string(arg1)))
6947 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006948 ret = get_errno(lchown(p, arg2, arg3));
6949 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00006950 break;
bellarda315a142005-01-30 22:59:18 +00006951#endif
6952#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00006953 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00006954 ret = get_errno(getuid());
6955 break;
bellarda315a142005-01-30 22:59:18 +00006956#endif
aurel3264b4d282008-11-14 17:20:15 +00006957
6958#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
6959 /* Alpha specific */
6960 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08006961 {
6962 uid_t euid;
6963 euid=geteuid();
6964 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
6965 }
aurel3264b4d282008-11-14 17:20:15 +00006966 ret = get_errno(getuid());
6967 break;
6968#endif
6969#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
6970 /* Alpha specific */
6971 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08006972 {
6973 uid_t egid;
6974 egid=getegid();
6975 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
6976 }
aurel3264b4d282008-11-14 17:20:15 +00006977 ret = get_errno(getgid());
6978 break;
6979#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08006980#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
6981 /* Alpha specific */
6982 case TARGET_NR_osf_getsysinfo:
6983 ret = -TARGET_EOPNOTSUPP;
6984 switch (arg1) {
6985 case TARGET_GSI_IEEE_FP_CONTROL:
6986 {
6987 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
6988
6989 /* Copied from linux ieee_fpcr_to_swcr. */
6990 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
6991 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
6992 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
6993 | SWCR_TRAP_ENABLE_DZE
6994 | SWCR_TRAP_ENABLE_OVF);
6995 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
6996 | SWCR_TRAP_ENABLE_INE);
6997 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
6998 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
6999
7000 if (put_user_u64 (swcr, arg2))
7001 goto efault;
7002 ret = 0;
7003 }
7004 break;
7005
7006 /* case GSI_IEEE_STATE_AT_SIGNAL:
7007 -- Not implemented in linux kernel.
7008 case GSI_UACPROC:
7009 -- Retrieves current unaligned access state; not much used.
7010 case GSI_PROC_TYPE:
7011 -- Retrieves implver information; surely not used.
7012 case GSI_GET_HWRPB:
7013 -- Grabs a copy of the HWRPB; surely not used.
7014 */
7015 }
7016 break;
7017#endif
7018#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7019 /* Alpha specific */
7020 case TARGET_NR_osf_setsysinfo:
7021 ret = -TARGET_EOPNOTSUPP;
7022 switch (arg1) {
7023 case TARGET_SSI_IEEE_FP_CONTROL:
7024 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7025 {
7026 uint64_t swcr, fpcr, orig_fpcr;
7027
7028 if (get_user_u64 (swcr, arg2))
7029 goto efault;
7030 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7031 fpcr = orig_fpcr & FPCR_DYN_MASK;
7032
7033 /* Copied from linux ieee_swcr_to_fpcr. */
7034 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7035 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7036 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7037 | SWCR_TRAP_ENABLE_DZE
7038 | SWCR_TRAP_ENABLE_OVF)) << 48;
7039 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7040 | SWCR_TRAP_ENABLE_INE)) << 57;
7041 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7042 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7043
7044 cpu_alpha_store_fpcr (cpu_env, fpcr);
7045 ret = 0;
7046
7047 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7048 /* Old exceptions are not signaled. */
7049 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7050
7051 /* If any exceptions set by this call, and are unmasked,
7052 send a signal. */
7053 /* ??? FIXME */
7054 }
7055 }
7056 break;
7057
7058 /* case SSI_NVPAIRS:
7059 -- Used with SSIN_UACPROC to enable unaligned accesses.
7060 case SSI_IEEE_STATE_AT_SIGNAL:
7061 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7062 -- Not implemented in linux kernel
7063 */
7064 }
7065 break;
7066#endif
7067#ifdef TARGET_NR_osf_sigprocmask
7068 /* Alpha specific. */
7069 case TARGET_NR_osf_sigprocmask:
7070 {
7071 abi_ulong mask;
7072 int how = arg1;
7073 sigset_t set, oldset;
7074
7075 switch(arg1) {
7076 case TARGET_SIG_BLOCK:
7077 how = SIG_BLOCK;
7078 break;
7079 case TARGET_SIG_UNBLOCK:
7080 how = SIG_UNBLOCK;
7081 break;
7082 case TARGET_SIG_SETMASK:
7083 how = SIG_SETMASK;
7084 break;
7085 default:
7086 ret = -TARGET_EINVAL;
7087 goto fail;
7088 }
7089 mask = arg2;
7090 target_to_host_old_sigset(&set, &mask);
7091 sigprocmask(arg1, &set, &oldset);
7092 host_to_target_old_sigset(&mask, &oldset);
7093 ret = mask;
7094 }
7095 break;
7096#endif
aurel3264b4d282008-11-14 17:20:15 +00007097
bellarda315a142005-01-30 22:59:18 +00007098#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007099 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007100 ret = get_errno(getgid());
7101 break;
bellarda315a142005-01-30 22:59:18 +00007102#endif
7103#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007104 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007105 ret = get_errno(geteuid());
7106 break;
bellarda315a142005-01-30 22:59:18 +00007107#endif
7108#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007109 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007110 ret = get_errno(getegid());
7111 break;
bellarda315a142005-01-30 22:59:18 +00007112#endif
7113#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007114 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007115 ret = get_errno(setreuid(arg1, arg2));
7116 break;
bellarda315a142005-01-30 22:59:18 +00007117#endif
7118#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007119 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007120 ret = get_errno(setregid(arg1, arg2));
7121 break;
bellarda315a142005-01-30 22:59:18 +00007122#endif
7123#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007124 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007125 {
7126 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007127 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007128 gid_t *grouplist;
7129 int i;
7130
7131 grouplist = alloca(gidsetsize * sizeof(gid_t));
7132 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007133 if (gidsetsize == 0)
7134 break;
bellard99c475a2005-01-31 20:45:13 +00007135 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007136 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7137 if (!target_grouplist) {
7138 ret = -TARGET_EFAULT;
7139 goto fail;
7140 }
balroga2155fc2008-09-20 02:12:08 +00007141 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007142 target_grouplist[i] = tswap32(grouplist[i]);
7143 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007144 }
7145 }
7146 break;
bellarda315a142005-01-30 22:59:18 +00007147#endif
7148#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007149 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007150 {
7151 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007152 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007153 gid_t *grouplist;
7154 int i;
ths3b46e622007-09-17 08:09:54 +00007155
bellard99c475a2005-01-31 20:45:13 +00007156 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007157 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7158 if (!target_grouplist) {
7159 ret = -TARGET_EFAULT;
7160 goto fail;
7161 }
bellard99c475a2005-01-31 20:45:13 +00007162 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007163 grouplist[i] = tswap32(target_grouplist[i]);
7164 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007165 ret = get_errno(setgroups(gidsetsize, grouplist));
7166 }
7167 break;
bellarda315a142005-01-30 22:59:18 +00007168#endif
7169#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007170 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007171 ret = get_errno(fchown(arg1, arg2, arg3));
7172 break;
bellarda315a142005-01-30 22:59:18 +00007173#endif
7174#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007175 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007176 ret = get_errno(setresuid(arg1, arg2, arg3));
7177 break;
bellarda315a142005-01-30 22:59:18 +00007178#endif
7179#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007180 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007181 {
pbrook53a59602006-03-25 19:31:22 +00007182 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007183 ret = get_errno(getresuid(&ruid, &euid, &suid));
7184 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007185 if (put_user_u32(ruid, arg1)
7186 || put_user_u32(euid, arg2)
7187 || put_user_u32(suid, arg3))
7188 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007189 }
7190 }
7191 break;
bellarda315a142005-01-30 22:59:18 +00007192#endif
7193#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007194 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007195 ret = get_errno(setresgid(arg1, arg2, arg3));
7196 break;
bellarda315a142005-01-30 22:59:18 +00007197#endif
7198#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007199 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007200 {
pbrook53a59602006-03-25 19:31:22 +00007201 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007202 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7203 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007204 if (put_user_u32(rgid, arg1)
7205 || put_user_u32(egid, arg2)
7206 || put_user_u32(sgid, arg3))
7207 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007208 }
7209 }
7210 break;
bellarda315a142005-01-30 22:59:18 +00007211#endif
7212#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007213 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007214 if (!(p = lock_user_string(arg1)))
7215 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007216 ret = get_errno(chown(p, arg2, arg3));
7217 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007218 break;
bellarda315a142005-01-30 22:59:18 +00007219#endif
7220#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007221 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007222 ret = get_errno(setuid(arg1));
7223 break;
bellarda315a142005-01-30 22:59:18 +00007224#endif
7225#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007226 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007227 ret = get_errno(setgid(arg1));
7228 break;
bellarda315a142005-01-30 22:59:18 +00007229#endif
7230#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007231 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007232 ret = get_errno(setfsuid(arg1));
7233 break;
bellarda315a142005-01-30 22:59:18 +00007234#endif
7235#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007236 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007237 ret = get_errno(setfsgid(arg1));
7238 break;
bellarda315a142005-01-30 22:59:18 +00007239#endif
bellard67867302003-11-23 17:05:30 +00007240
bellard31e31b82003-02-18 22:55:36 +00007241 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007242 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007243#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007244 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007245 {
7246 void *a;
7247 ret = -TARGET_EFAULT;
7248 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7249 goto efault;
7250 if (!(p = lock_user_string(arg3)))
7251 goto mincore_fail;
7252 ret = get_errno(mincore(a, arg2, p));
7253 unlock_user(p, arg3, ret);
7254 mincore_fail:
7255 unlock_user(a, arg1, 0);
7256 }
7257 break;
bellardffa65c32004-01-04 23:57:22 +00007258#endif
aurel32408321b2008-10-01 21:46:32 +00007259#ifdef TARGET_NR_arm_fadvise64_64
7260 case TARGET_NR_arm_fadvise64_64:
7261 {
7262 /*
7263 * arm_fadvise64_64 looks like fadvise64_64 but
7264 * with different argument order
7265 */
7266 abi_long temp;
7267 temp = arg3;
7268 arg3 = arg4;
7269 arg4 = temp;
7270 }
7271#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007272#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007273#ifdef TARGET_NR_fadvise64_64
7274 case TARGET_NR_fadvise64_64:
7275#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007276#ifdef TARGET_NR_fadvise64
7277 case TARGET_NR_fadvise64:
7278#endif
7279#ifdef TARGET_S390X
7280 switch (arg4) {
7281 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7282 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7283 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7284 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7285 default: break;
7286 }
7287#endif
7288 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007289 break;
7290#endif
bellardffa65c32004-01-04 23:57:22 +00007291#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007292 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007293 /* A straight passthrough may not be safe because qemu sometimes
7294 turns private flie-backed mappings into anonymous mappings.
7295 This will break MADV_DONTNEED.
7296 This is a hint, so ignoring and returning success is ok. */
7297 ret = get_errno(0);
7298 break;
bellardffa65c32004-01-04 23:57:22 +00007299#endif
blueswir1992f48a2007-10-14 16:27:31 +00007300#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007301 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007302 {
thsb1e341e2007-03-20 21:50:52 +00007303 int cmd;
bellard77e46722003-04-29 20:39:06 +00007304 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007305 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007306#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007307 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007308#endif
bellard77e46722003-04-29 20:39:06 +00007309
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007310 cmd = target_to_host_fcntl_cmd(arg2);
7311 if (cmd == -TARGET_EINVAL)
7312 return cmd;
thsb1e341e2007-03-20 21:50:52 +00007313
bellard60cd49d2003-03-16 22:53:56 +00007314 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007315 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007316#ifdef TARGET_ARM
7317 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007318 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7319 goto efault;
ths58134272007-03-31 18:59:32 +00007320 fl.l_type = tswap16(target_efl->l_type);
7321 fl.l_whence = tswap16(target_efl->l_whence);
7322 fl.l_start = tswap64(target_efl->l_start);
7323 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007324 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007325 unlock_user_struct(target_efl, arg3, 0);
7326 } else
7327#endif
7328 {
bellard9ee1fa22007-11-11 15:11:19 +00007329 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7330 goto efault;
ths58134272007-03-31 18:59:32 +00007331 fl.l_type = tswap16(target_fl->l_type);
7332 fl.l_whence = tswap16(target_fl->l_whence);
7333 fl.l_start = tswap64(target_fl->l_start);
7334 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007335 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007336 unlock_user_struct(target_fl, arg3, 0);
7337 }
thsb1e341e2007-03-20 21:50:52 +00007338 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007339 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007340#ifdef TARGET_ARM
7341 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007342 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7343 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007344 target_efl->l_type = tswap16(fl.l_type);
7345 target_efl->l_whence = tswap16(fl.l_whence);
7346 target_efl->l_start = tswap64(fl.l_start);
7347 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007348 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007349 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007350 } else
7351#endif
7352 {
bellard9ee1fa22007-11-11 15:11:19 +00007353 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7354 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007355 target_fl->l_type = tswap16(fl.l_type);
7356 target_fl->l_whence = tswap16(fl.l_whence);
7357 target_fl->l_start = tswap64(fl.l_start);
7358 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007359 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007360 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007361 }
bellard77e46722003-04-29 20:39:06 +00007362 }
7363 break;
7364
thsb1e341e2007-03-20 21:50:52 +00007365 case TARGET_F_SETLK64:
7366 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00007367#ifdef TARGET_ARM
7368 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007369 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7370 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007371 fl.l_type = tswap16(target_efl->l_type);
7372 fl.l_whence = tswap16(target_efl->l_whence);
7373 fl.l_start = tswap64(target_efl->l_start);
7374 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007375 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007376 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007377 } else
7378#endif
7379 {
bellard9ee1fa22007-11-11 15:11:19 +00007380 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7381 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007382 fl.l_type = tswap16(target_fl->l_type);
7383 fl.l_whence = tswap16(target_fl->l_whence);
7384 fl.l_start = tswap64(target_fl->l_start);
7385 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007386 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007387 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007388 }
thsb1e341e2007-03-20 21:50:52 +00007389 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007390 break;
bellard60cd49d2003-03-16 22:53:56 +00007391 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007392 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00007393 break;
7394 }
bellard77e46722003-04-29 20:39:06 +00007395 break;
7396 }
bellard60cd49d2003-03-16 22:53:56 +00007397#endif
ths7d600c82006-12-08 01:32:58 +00007398#ifdef TARGET_NR_cacheflush
7399 case TARGET_NR_cacheflush:
7400 /* self-modifying code is handled automatically, so nothing needed */
7401 ret = 0;
7402 break;
7403#endif
bellardebc05482003-09-30 21:08:41 +00007404#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00007405 case TARGET_NR_security:
7406 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007407#endif
bellardc573ff62004-01-04 15:51:36 +00007408#ifdef TARGET_NR_getpagesize
7409 case TARGET_NR_getpagesize:
7410 ret = TARGET_PAGE_SIZE;
7411 break;
7412#endif
bellard31e31b82003-02-18 22:55:36 +00007413 case TARGET_NR_gettid:
7414 ret = get_errno(gettid());
7415 break;
thse5febef2007-04-01 18:31:35 +00007416#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00007417 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00007418#if TARGET_ABI_BITS == 32
7419#ifdef TARGET_ARM
7420 if (((CPUARMState *)cpu_env)->eabi)
7421 {
7422 arg2 = arg3;
7423 arg3 = arg4;
7424 arg4 = arg5;
7425 }
7426#endif
7427 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
7428#else
7429 ret = get_errno(readahead(arg1, arg2, arg3));
7430#endif
7431 break;
thse5febef2007-04-01 18:31:35 +00007432#endif
bellardebc05482003-09-30 21:08:41 +00007433#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00007434 case TARGET_NR_setxattr:
7435 case TARGET_NR_lsetxattr:
7436 case TARGET_NR_fsetxattr:
7437 case TARGET_NR_getxattr:
7438 case TARGET_NR_lgetxattr:
7439 case TARGET_NR_fgetxattr:
7440 case TARGET_NR_listxattr:
7441 case TARGET_NR_llistxattr:
7442 case TARGET_NR_flistxattr:
7443 case TARGET_NR_removexattr:
7444 case TARGET_NR_lremovexattr:
7445 case TARGET_NR_fremovexattr:
Arnaud Patard6f932f92009-04-21 21:04:18 +03007446 ret = -TARGET_EOPNOTSUPP;
7447 break;
bellardebc05482003-09-30 21:08:41 +00007448#endif
7449#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00007450 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007451#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00007452 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
7453 ret = 0;
7454 break;
edgar_iglef967792009-01-07 14:19:38 +00007455#elif defined(TARGET_CRIS)
7456 if (arg1 & 0xff)
7457 ret = -TARGET_EINVAL;
7458 else {
7459 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
7460 ret = 0;
7461 }
7462 break;
bellard8d18e892007-11-14 15:18:40 +00007463#elif defined(TARGET_I386) && defined(TARGET_ABI32)
7464 ret = do_set_thread_area(cpu_env, arg1);
7465 break;
ths6f5b89a2007-03-02 20:48:00 +00007466#else
7467 goto unimplemented_nowarn;
7468#endif
7469#endif
7470#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00007471 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007472#if defined(TARGET_I386) && defined(TARGET_ABI32)
7473 ret = do_get_thread_area(cpu_env, arg1);
7474#else
bellard5cd43932003-03-29 16:54:36 +00007475 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00007476#endif
bellard8d18e892007-11-14 15:18:40 +00007477#endif
bellard48dc41e2006-06-21 18:15:50 +00007478#ifdef TARGET_NR_getdomainname
7479 case TARGET_NR_getdomainname:
7480 goto unimplemented_nowarn;
7481#endif
ths6f5b89a2007-03-02 20:48:00 +00007482
thsb5906f92007-03-19 13:32:45 +00007483#ifdef TARGET_NR_clock_gettime
7484 case TARGET_NR_clock_gettime:
7485 {
7486 struct timespec ts;
7487 ret = get_errno(clock_gettime(arg1, &ts));
7488 if (!is_error(ret)) {
7489 host_to_target_timespec(arg2, &ts);
7490 }
7491 break;
7492 }
7493#endif
7494#ifdef TARGET_NR_clock_getres
7495 case TARGET_NR_clock_getres:
7496 {
7497 struct timespec ts;
7498 ret = get_errno(clock_getres(arg1, &ts));
7499 if (!is_error(ret)) {
7500 host_to_target_timespec(arg2, &ts);
7501 }
7502 break;
7503 }
7504#endif
pbrook63d76512008-05-29 13:43:29 +00007505#ifdef TARGET_NR_clock_nanosleep
7506 case TARGET_NR_clock_nanosleep:
7507 {
7508 struct timespec ts;
7509 target_to_host_timespec(&ts, arg3);
7510 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
7511 if (arg4)
7512 host_to_target_timespec(arg4, &ts);
7513 break;
7514 }
7515#endif
thsb5906f92007-03-19 13:32:45 +00007516
ths6f5b89a2007-03-02 20:48:00 +00007517#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
7518 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00007519 ret = get_errno(set_tid_address((int *)g2h(arg1)));
7520 break;
ths6f5b89a2007-03-02 20:48:00 +00007521#endif
7522
ths3ae43202007-09-16 21:39:48 +00007523#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00007524 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00007525 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00007526 break;
7527#endif
7528
ths3ae43202007-09-16 21:39:48 +00007529#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00007530 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00007531 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
7532 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00007533 break;
7534#endif
7535
ths4f2b1fe2007-06-21 21:57:12 +00007536#ifdef TARGET_NR_set_robust_list
7537 case TARGET_NR_set_robust_list:
7538 goto unimplemented_nowarn;
7539#endif
7540
ths9007f0e2007-09-25 17:50:37 +00007541#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
7542 case TARGET_NR_utimensat:
7543 {
Riku Voipioebc996f2009-04-21 15:01:51 +03007544 struct timespec *tsp, ts[2];
7545 if (!arg3) {
7546 tsp = NULL;
7547 } else {
7548 target_to_host_timespec(ts, arg3);
7549 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
7550 tsp = ts;
7551 }
ths9007f0e2007-09-25 17:50:37 +00007552 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03007553 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00007554 else {
bellard579a97f2007-11-11 14:26:47 +00007555 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00007556 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00007557 goto fail;
7558 }
Riku Voipioebc996f2009-04-21 15:01:51 +03007559 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00007560 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00007561 }
7562 }
7563 break;
7564#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02007565#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00007566 case TARGET_NR_futex:
7567 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
7568 break;
7569#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007570#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00007571 case TARGET_NR_inotify_init:
7572 ret = get_errno(sys_inotify_init());
7573 break;
7574#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007575#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00007576#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
7577 case TARGET_NR_inotify_init1:
7578 ret = get_errno(sys_inotify_init1(arg1));
7579 break;
7580#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007581#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007582#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00007583 case TARGET_NR_inotify_add_watch:
7584 p = lock_user_string(arg2);
7585 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
7586 unlock_user(p, arg2, 0);
7587 break;
7588#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007589#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00007590 case TARGET_NR_inotify_rm_watch:
7591 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
7592 break;
7593#endif
ths9007f0e2007-09-25 17:50:37 +00007594
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07007595#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00007596 case TARGET_NR_mq_open:
7597 {
7598 struct mq_attr posix_mq_attr;
7599
7600 p = lock_user_string(arg1 - 1);
7601 if (arg4 != 0)
7602 copy_from_user_mq_attr (&posix_mq_attr, arg4);
7603 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
7604 unlock_user (p, arg1, 0);
7605 }
7606 break;
7607
7608 case TARGET_NR_mq_unlink:
7609 p = lock_user_string(arg1 - 1);
7610 ret = get_errno(mq_unlink(p));
7611 unlock_user (p, arg1, 0);
7612 break;
7613
7614 case TARGET_NR_mq_timedsend:
7615 {
7616 struct timespec ts;
7617
7618 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7619 if (arg5 != 0) {
7620 target_to_host_timespec(&ts, arg5);
7621 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
7622 host_to_target_timespec(arg5, &ts);
7623 }
7624 else
7625 ret = get_errno(mq_send(arg1, p, arg3, arg4));
7626 unlock_user (p, arg2, arg3);
7627 }
7628 break;
7629
7630 case TARGET_NR_mq_timedreceive:
7631 {
7632 struct timespec ts;
7633 unsigned int prio;
7634
7635 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7636 if (arg5 != 0) {
7637 target_to_host_timespec(&ts, arg5);
7638 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
7639 host_to_target_timespec(arg5, &ts);
7640 }
7641 else
7642 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
7643 unlock_user (p, arg2, arg3);
7644 if (arg4 != 0)
7645 put_user_u32(prio, arg4);
7646 }
7647 break;
7648
7649 /* Not implemented for now... */
7650/* case TARGET_NR_mq_notify: */
7651/* break; */
7652
7653 case TARGET_NR_mq_getsetattr:
7654 {
7655 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
7656 ret = 0;
7657 if (arg3 != 0) {
7658 ret = mq_getattr(arg1, &posix_mq_attr_out);
7659 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
7660 }
7661 if (arg2 != 0) {
7662 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
7663 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
7664 }
7665
7666 }
7667 break;
7668#endif
7669
vibisreenivasan3ce34df2009-05-16 18:32:41 +05307670#ifdef CONFIG_SPLICE
7671#ifdef TARGET_NR_tee
7672 case TARGET_NR_tee:
7673 {
7674 ret = get_errno(tee(arg1,arg2,arg3,arg4));
7675 }
7676 break;
7677#endif
7678#ifdef TARGET_NR_splice
7679 case TARGET_NR_splice:
7680 {
7681 loff_t loff_in, loff_out;
7682 loff_t *ploff_in = NULL, *ploff_out = NULL;
7683 if(arg2) {
7684 get_user_u64(loff_in, arg2);
7685 ploff_in = &loff_in;
7686 }
7687 if(arg4) {
7688 get_user_u64(loff_out, arg2);
7689 ploff_out = &loff_out;
7690 }
7691 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
7692 }
7693 break;
7694#endif
7695#ifdef TARGET_NR_vmsplice
7696 case TARGET_NR_vmsplice:
7697 {
7698 int count = arg3;
7699 struct iovec *vec;
7700
7701 vec = alloca(count * sizeof(struct iovec));
7702 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7703 goto efault;
7704 ret = get_errno(vmsplice(arg1, vec, count, arg4));
7705 unlock_iovec(vec, arg2, count, 0);
7706 }
7707 break;
7708#endif
7709#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03007710#ifdef CONFIG_EVENTFD
7711#if defined(TARGET_NR_eventfd)
7712 case TARGET_NR_eventfd:
7713 ret = get_errno(eventfd(arg1, 0));
7714 break;
7715#endif
7716#if defined(TARGET_NR_eventfd2)
7717 case TARGET_NR_eventfd2:
7718 ret = get_errno(eventfd(arg1, arg2));
7719 break;
7720#endif
7721#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03007722#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
7723 case TARGET_NR_fallocate:
7724 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
7725 break;
7726#endif
Peter Maydellc727f472011-01-06 11:05:10 +00007727#if defined(CONFIG_SYNC_FILE_RANGE)
7728#if defined(TARGET_NR_sync_file_range)
7729 case TARGET_NR_sync_file_range:
7730#if TARGET_ABI_BITS == 32
7731 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
7732 target_offset64(arg4, arg5), arg6));
7733#else
7734 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
7735#endif
7736 break;
7737#endif
7738#if defined(TARGET_NR_sync_file_range2)
7739 case TARGET_NR_sync_file_range2:
7740 /* This is like sync_file_range but the arguments are reordered */
7741#if TARGET_ABI_BITS == 32
7742 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7743 target_offset64(arg5, arg6), arg2));
7744#else
7745 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
7746#endif
7747 break;
7748#endif
7749#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00007750#if defined(CONFIG_EPOLL)
7751#if defined(TARGET_NR_epoll_create)
7752 case TARGET_NR_epoll_create:
7753 ret = get_errno(epoll_create(arg1));
7754 break;
7755#endif
7756#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
7757 case TARGET_NR_epoll_create1:
7758 ret = get_errno(epoll_create1(arg1));
7759 break;
7760#endif
7761#if defined(TARGET_NR_epoll_ctl)
7762 case TARGET_NR_epoll_ctl:
7763 {
7764 struct epoll_event ep;
7765 struct epoll_event *epp = 0;
7766 if (arg4) {
7767 struct target_epoll_event *target_ep;
7768 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
7769 goto efault;
7770 }
7771 ep.events = tswap32(target_ep->events);
7772 /* The epoll_data_t union is just opaque data to the kernel,
7773 * so we transfer all 64 bits across and need not worry what
7774 * actual data type it is.
7775 */
7776 ep.data.u64 = tswap64(target_ep->data.u64);
7777 unlock_user_struct(target_ep, arg4, 0);
7778 epp = &ep;
7779 }
7780 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
7781 break;
7782 }
7783#endif
7784
7785#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
7786#define IMPLEMENT_EPOLL_PWAIT
7787#endif
7788#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
7789#if defined(TARGET_NR_epoll_wait)
7790 case TARGET_NR_epoll_wait:
7791#endif
7792#if defined(IMPLEMENT_EPOLL_PWAIT)
7793 case TARGET_NR_epoll_pwait:
7794#endif
7795 {
7796 struct target_epoll_event *target_ep;
7797 struct epoll_event *ep;
7798 int epfd = arg1;
7799 int maxevents = arg3;
7800 int timeout = arg4;
7801
7802 target_ep = lock_user(VERIFY_WRITE, arg2,
7803 maxevents * sizeof(struct target_epoll_event), 1);
7804 if (!target_ep) {
7805 goto efault;
7806 }
7807
7808 ep = alloca(maxevents * sizeof(struct epoll_event));
7809
7810 switch (num) {
7811#if defined(IMPLEMENT_EPOLL_PWAIT)
7812 case TARGET_NR_epoll_pwait:
7813 {
7814 target_sigset_t *target_set;
7815 sigset_t _set, *set = &_set;
7816
7817 if (arg5) {
7818 target_set = lock_user(VERIFY_READ, arg5,
7819 sizeof(target_sigset_t), 1);
7820 if (!target_set) {
7821 unlock_user(target_ep, arg2, 0);
7822 goto efault;
7823 }
7824 target_to_host_sigset(set, target_set);
7825 unlock_user(target_set, arg5, 0);
7826 } else {
7827 set = NULL;
7828 }
7829
7830 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
7831 break;
7832 }
7833#endif
7834#if defined(TARGET_NR_epoll_wait)
7835 case TARGET_NR_epoll_wait:
7836 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
7837 break;
7838#endif
7839 default:
7840 ret = -TARGET_ENOSYS;
7841 }
7842 if (!is_error(ret)) {
7843 int i;
7844 for (i = 0; i < ret; i++) {
7845 target_ep[i].events = tswap32(ep[i].events);
7846 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
7847 }
7848 }
7849 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
7850 break;
7851 }
7852#endif
7853#endif
bellard31e31b82003-02-18 22:55:36 +00007854 default:
7855 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00007856 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00007857#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
bellard5cd43932003-03-29 16:54:36 +00007858 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00007859#endif
ths0da46a62007-10-20 20:23:07 +00007860 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00007861 break;
7862 }
bellard579a97f2007-11-11 14:26:47 +00007863fail:
bellardc573ff62004-01-04 15:51:36 +00007864#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00007865 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00007866#endif
thsb92c47c2007-11-01 00:07:38 +00007867 if(do_strace)
7868 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00007869 return ret;
bellard579a97f2007-11-11 14:26:47 +00007870efault:
7871 ret = -TARGET_EFAULT;
7872 goto fail;
bellard31e31b82003-02-18 22:55:36 +00007873}