blob: 39a34db4b1480d4bd0c91584a79f86aa19e66e88 [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
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#ifdef CONFIG_ATTR
74#include <attr/xattr.h>
75#endif
bellard31e31b82003-02-18 22:55:36 +000076
77#define termios host_termios
78#define winsize host_winsize
79#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000080#define sgttyb host_sgttyb /* same as target */
81#define tchars host_tchars /* same as target */
82#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000083
84#include <linux/termios.h>
85#include <linux/unistd.h>
86#include <linux/utsname.h>
87#include <linux/cdrom.h>
88#include <linux/hdreg.h>
89#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000090#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000091#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030092#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000093#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000094#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020096#include <linux/fb.h>
97#include <linux/vt.h>
pbrookd7e40362008-05-23 16:06:43 +000098#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +010099#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000100
bellard3ef693a2003-03-23 20:17:16 +0000101#include "qemu.h"
balrog526ccb72008-07-16 12:13:52 +0000102#include "qemu-common.h"
bellard31e31b82003-02-18 22:55:36 +0000103
Juan Quintela2f7bb872009-07-27 16:13:24 +0200104#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000105#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
106 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
107#else
108/* XXX: Hardcode the above values. */
109#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000110#endif
111
bellard72f03902003-02-18 23:33:18 +0000112//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000113
bellard1a9353d2003-03-16 20:28:50 +0000114//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000115#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
116#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000117
bellard70a194b2003-08-11 22:20:16 +0000118
bellard70a194b2003-08-11 22:20:16 +0000119#undef _syscall0
120#undef _syscall1
121#undef _syscall2
122#undef _syscall3
123#undef _syscall4
124#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000125#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000126
bellard83fcb512006-06-14 13:37:16 +0000127#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000128static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000129{ \
130 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000131}
132
bellard83fcb512006-06-14 13:37:16 +0000133#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000134static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000135{ \
136 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000137}
138
bellard83fcb512006-06-14 13:37:16 +0000139#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000140static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000141{ \
142 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000143}
144
bellard83fcb512006-06-14 13:37:16 +0000145#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000146static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000147{ \
148 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000149}
150
bellard83fcb512006-06-14 13:37:16 +0000151#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000152static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000153{ \
154 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000155}
156
bellard83fcb512006-06-14 13:37:16 +0000157#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
158 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000162}
bellard83fcb512006-06-14 13:37:16 +0000163
164
165#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
166 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000167static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
168 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000169{ \
170 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
171}
172
bellard70a194b2003-08-11 22:20:16 +0000173
bellard31e31b82003-02-18 22:55:36 +0000174#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000175#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000176#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000177#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000178#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000179#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000180#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000181#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000182#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000183#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000184#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000185#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000186#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000187#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000188#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000189#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000190#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000191#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000192#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000193#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000194#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000195#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000196#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000197#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000198#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000199#define __NR_sys_inotify_init __NR_inotify_init
200#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
201#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000202
Alexander Graf42a39fb2011-04-15 17:32:45 +0200203#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
204 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000205#define __NR__llseek __NR_lseek
206#endif
207
bellard72f03902003-02-18 23:33:18 +0000208#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000209_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000210#else
ths0da46a62007-10-20 20:23:07 +0000211/* This is a replacement for the host gettid() and must return a host
212 errno. */
bellard72f03902003-02-18 23:33:18 +0000213static int gettid(void) {
214 return -ENOSYS;
215}
216#endif
aurel323b3f24a2009-04-15 16:12:13 +0000217_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000218#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
219_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
220#endif
221_syscall2(int, sys_getpriority, int, which, int, who);
Richard Hendersond35b2612010-06-04 12:14:10 -0700222#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000223_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
224 loff_t *, res, uint, wh);
225#endif
226_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
227_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
228#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
229_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
230#endif
231#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
232_syscall2(int,sys_tkill,int,tid,int,sig)
233#endif
234#ifdef __NR_exit_group
235_syscall1(int,exit_group,int,error_code)
236#endif
237#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
238_syscall1(int,set_tid_address,int *,tidptr)
239#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200240#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000241#if defined(TARGET_NR_futex) && defined(__NR_futex)
242_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
243 const struct timespec *,timeout,int *,uaddr2,int,val3)
244#endif
245#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500246#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
247_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
248 unsigned long *, user_mask_ptr);
249#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
250_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
251 unsigned long *, user_mask_ptr);
aurel323b3f24a2009-04-15 16:12:13 +0000252
253static bitmask_transtbl fcntl_flags_tbl[] = {
254 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
255 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
256 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
257 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
258 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
259 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
260 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
261 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
262 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
263 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
264 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
265 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
266 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
267#if defined(O_DIRECT)
268 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
269#endif
270 { 0, 0, 0, 0 }
271};
272
273#define COPY_UTSNAME_FIELD(dest, src) \
274 do { \
275 /* __NEW_UTS_LEN doesn't include terminating null */ \
276 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
277 (dest)[__NEW_UTS_LEN] = '\0'; \
278 } while (0)
279
280static int sys_uname(struct new_utsname *buf)
281{
282 struct utsname uts_buf;
283
284 if (uname(&uts_buf) < 0)
285 return (-1);
286
287 /*
288 * Just in case these have some differences, we
289 * translate utsname to new_utsname (which is the
290 * struct linux kernel uses).
291 */
292
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200293 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000294 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
295 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
296 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
297 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
298 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
299#ifdef _GNU_SOURCE
300 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
301#endif
302 return (0);
303
304#undef COPY_UTSNAME_FIELD
305}
306
307static int sys_getcwd1(char *buf, size_t size)
308{
309 if (getcwd(buf, size) == NULL) {
310 /* getcwd() sets errno */
311 return (-1);
312 }
aurel32aaf4ad32009-04-16 14:17:14 +0000313 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000314}
315
316#ifdef CONFIG_ATFILE
317/*
318 * Host system seems to have atfile syscall stubs available. We
319 * now enable them one by one as specified by target syscall_nr.h.
320 */
321
322#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000323static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000324{
aurel32465c9f02009-04-19 08:52:17 +0000325 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000326}
327#endif
328#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000329static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000330{
aurel32465c9f02009-04-19 08:52:17 +0000331 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000332}
333#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300334#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000335static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
336 gid_t group, int flags)
337{
338 return (fchownat(dirfd, pathname, owner, group, flags));
339}
340#endif
341#ifdef __NR_fstatat64
342static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
343 int flags)
344{
345 return (fstatat(dirfd, pathname, buf, flags));
346}
347#endif
348#ifdef __NR_newfstatat
349static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
350 int flags)
351{
352 return (fstatat(dirfd, pathname, buf, flags));
353}
354#endif
355#ifdef TARGET_NR_futimesat
356static int sys_futimesat(int dirfd, const char *pathname,
357 const struct timeval times[2])
358{
359 return (futimesat(dirfd, pathname, times));
360}
361#endif
362#ifdef TARGET_NR_linkat
363static int sys_linkat(int olddirfd, const char *oldpath,
364 int newdirfd, const char *newpath, int flags)
365{
366 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
367}
368#endif
369#ifdef TARGET_NR_mkdirat
370static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
371{
372 return (mkdirat(dirfd, pathname, mode));
373}
374#endif
375#ifdef TARGET_NR_mknodat
376static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
377 dev_t dev)
378{
379 return (mknodat(dirfd, pathname, mode, dev));
380}
381#endif
382#ifdef TARGET_NR_openat
383static int sys_openat(int dirfd, const char *pathname, int flags, ...)
384{
385 /*
386 * open(2) has extra parameter 'mode' when called with
387 * flag O_CREAT.
388 */
389 if ((flags & O_CREAT) != 0) {
390 va_list ap;
391 mode_t mode;
392
393 /*
394 * Get the 'mode' parameter and translate it to
395 * host bits.
396 */
397 va_start(ap, flags);
398 mode = va_arg(ap, mode_t);
399 mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
400 va_end(ap);
401
402 return (openat(dirfd, pathname, flags, mode));
403 }
404 return (openat(dirfd, pathname, flags));
405}
406#endif
407#ifdef TARGET_NR_readlinkat
408static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
409{
410 return (readlinkat(dirfd, pathname, buf, bufsiz));
411}
412#endif
413#ifdef TARGET_NR_renameat
414static int sys_renameat(int olddirfd, const char *oldpath,
415 int newdirfd, const char *newpath)
416{
417 return (renameat(olddirfd, oldpath, newdirfd, newpath));
418}
419#endif
420#ifdef TARGET_NR_symlinkat
421static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
422{
423 return (symlinkat(oldpath, newdirfd, newpath));
424}
425#endif
426#ifdef TARGET_NR_unlinkat
427static int sys_unlinkat(int dirfd, const char *pathname, int flags)
428{
429 return (unlinkat(dirfd, pathname, flags));
430}
431#endif
aurel323b3f24a2009-04-15 16:12:13 +0000432#else /* !CONFIG_ATFILE */
433
434/*
435 * Try direct syscalls instead
436 */
ths92a34c12007-09-24 09:27:49 +0000437#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000438_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000439#endif
ths814d7972007-09-24 09:26:51 +0000440#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000441_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000442#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300443#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000444_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
445 uid_t,owner,gid_t,group,int,flags)
446#endif
aurel329d33b762009-04-08 23:07:05 +0000447#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
448 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000449_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
450 struct stat *,buf,int,flags)
451#endif
balrogac8a6552008-09-20 02:25:39 +0000452#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
453_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
454 const struct timeval *,times)
455#endif
aurel323b3f24a2009-04-15 16:12:13 +0000456#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
457 defined(__NR_newfstatat)
458_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
459 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000460#endif
ths64f0ce42007-09-24 09:25:06 +0000461#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
462_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000463 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000464#endif
ths4472ad02007-09-24 09:22:32 +0000465#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
466_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
467#endif
ths75ac37a2007-09-24 09:23:05 +0000468#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
469_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
470 mode_t,mode,dev_t,dev)
471#endif
ths82424832007-09-24 09:21:55 +0000472#if defined(TARGET_NR_openat) && defined(__NR_openat)
473_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
474#endif
ths5e0ccb12007-09-24 09:26:10 +0000475#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
476_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
477 char *,buf,size_t,bufsize)
478#endif
ths722183f2007-09-24 09:24:37 +0000479#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
480_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
481 int,newdirfd,const char *,newpath)
482#endif
thsb51eaa82007-09-25 16:09:22 +0000483#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000484_syscall3(int,sys_symlinkat,const char *,oldpath,
485 int,newdirfd,const char *,newpath)
486#endif
ths8170f562007-09-24 09:24:11 +0000487#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
488_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
489#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300490
491#endif /* CONFIG_ATFILE */
492
493#ifdef CONFIG_UTIMENSAT
494static int sys_utimensat(int dirfd, const char *pathname,
495 const struct timespec times[2], int flags)
496{
497 if (pathname == NULL)
498 return futimens(dirfd, times);
499 else
500 return utimensat(dirfd, pathname, times, flags);
501}
502#else
ths9007f0e2007-09-25 17:50:37 +0000503#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
504_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
505 const struct timespec *,tsp,int,flags)
506#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300507#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000508
509#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000510#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000511
aurel3239b59762008-10-01 21:46:50 +0000512#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000513static int sys_inotify_init(void)
514{
515 return (inotify_init());
516}
aurel3239b59762008-10-01 21:46:50 +0000517#endif
518#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000519static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
520{
521 return (inotify_add_watch(fd, pathname, mask));
522}
aurel3239b59762008-10-01 21:46:50 +0000523#endif
524#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000525static int sys_inotify_rm_watch(int fd, int32_t wd)
526{
aurel328690e422009-04-17 13:50:32 +0000527 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000528}
aurel3239b59762008-10-01 21:46:50 +0000529#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000530#ifdef CONFIG_INOTIFY1
531#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
532static int sys_inotify_init1(int flags)
533{
534 return (inotify_init1(flags));
535}
536#endif
537#endif
aurel323b3f24a2009-04-15 16:12:13 +0000538#else
539/* Userspace can usually survive runtime without inotify */
540#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000541#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000542#undef TARGET_NR_inotify_add_watch
543#undef TARGET_NR_inotify_rm_watch
544#endif /* CONFIG_INOTIFY */
545
Mike Frysingerd8035d42011-02-07 01:05:51 -0500546#if defined(TARGET_NR_ppoll)
547#ifndef __NR_ppoll
548# define __NR_ppoll -1
549#endif
550#define __NR_sys_ppoll __NR_ppoll
551_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
552 struct timespec *, timeout, const __sigset_t *, sigmask,
553 size_t, sigsetsize)
554#endif
bellard66fb9762003-03-23 01:06:05 +0000555
Mike Frysinger055e0902011-06-03 17:01:49 -0400556#if defined(TARGET_NR_pselect6)
557#ifndef __NR_pselect6
558# define __NR_pselect6 -1
559#endif
560#define __NR_sys_pselect6 __NR_pselect6
561_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
562 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
563#endif
564
Peter Maydell163a05a2011-06-27 17:44:52 +0100565#if defined(TARGET_NR_prlimit64)
566#ifndef __NR_prlimit64
567# define __NR_prlimit64 -1
568#endif
569#define __NR_sys_prlimit64 __NR_prlimit64
570/* The glibc rlimit structure may not be that used by the underlying syscall */
571struct host_rlimit64 {
572 uint64_t rlim_cur;
573 uint64_t rlim_max;
574};
575_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
576 const struct host_rlimit64 *, new_limit,
577 struct host_rlimit64 *, old_limit)
578#endif
579
bellard66fb9762003-03-23 01:06:05 +0000580extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000581extern int flock(int, int);
582extern int setfsuid(int);
583extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000584extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000585
Riku Voipio48e515d2011-07-12 15:40:51 +0300586/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
587#ifdef TARGET_ARM
588static inline int regpairs_aligned(void *cpu_env) {
589 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
590}
591#elif defined(TARGET_MIPS)
592static inline int regpairs_aligned(void *cpu_env) { return 1; }
593#else
594static inline int regpairs_aligned(void *cpu_env) { return 0; }
595#endif
596
thsb92c47c2007-11-01 00:07:38 +0000597#define ERRNO_TABLE_SIZE 1200
598
599/* target_to_host_errno_table[] is initialized from
600 * host_to_target_errno_table[] in syscall_init(). */
601static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
602};
603
ths637947f2007-06-01 12:09:19 +0000604/*
thsfe8f0962007-07-12 10:59:21 +0000605 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000606 * minus the errnos that are not actually generic to all archs.
607 */
thsb92c47c2007-11-01 00:07:38 +0000608static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000609 [EIDRM] = TARGET_EIDRM,
610 [ECHRNG] = TARGET_ECHRNG,
611 [EL2NSYNC] = TARGET_EL2NSYNC,
612 [EL3HLT] = TARGET_EL3HLT,
613 [EL3RST] = TARGET_EL3RST,
614 [ELNRNG] = TARGET_ELNRNG,
615 [EUNATCH] = TARGET_EUNATCH,
616 [ENOCSI] = TARGET_ENOCSI,
617 [EL2HLT] = TARGET_EL2HLT,
618 [EDEADLK] = TARGET_EDEADLK,
619 [ENOLCK] = TARGET_ENOLCK,
620 [EBADE] = TARGET_EBADE,
621 [EBADR] = TARGET_EBADR,
622 [EXFULL] = TARGET_EXFULL,
623 [ENOANO] = TARGET_ENOANO,
624 [EBADRQC] = TARGET_EBADRQC,
625 [EBADSLT] = TARGET_EBADSLT,
626 [EBFONT] = TARGET_EBFONT,
627 [ENOSTR] = TARGET_ENOSTR,
628 [ENODATA] = TARGET_ENODATA,
629 [ETIME] = TARGET_ETIME,
630 [ENOSR] = TARGET_ENOSR,
631 [ENONET] = TARGET_ENONET,
632 [ENOPKG] = TARGET_ENOPKG,
633 [EREMOTE] = TARGET_EREMOTE,
634 [ENOLINK] = TARGET_ENOLINK,
635 [EADV] = TARGET_EADV,
636 [ESRMNT] = TARGET_ESRMNT,
637 [ECOMM] = TARGET_ECOMM,
638 [EPROTO] = TARGET_EPROTO,
639 [EDOTDOT] = TARGET_EDOTDOT,
640 [EMULTIHOP] = TARGET_EMULTIHOP,
641 [EBADMSG] = TARGET_EBADMSG,
642 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
643 [EOVERFLOW] = TARGET_EOVERFLOW,
644 [ENOTUNIQ] = TARGET_ENOTUNIQ,
645 [EBADFD] = TARGET_EBADFD,
646 [EREMCHG] = TARGET_EREMCHG,
647 [ELIBACC] = TARGET_ELIBACC,
648 [ELIBBAD] = TARGET_ELIBBAD,
649 [ELIBSCN] = TARGET_ELIBSCN,
650 [ELIBMAX] = TARGET_ELIBMAX,
651 [ELIBEXEC] = TARGET_ELIBEXEC,
652 [EILSEQ] = TARGET_EILSEQ,
653 [ENOSYS] = TARGET_ENOSYS,
654 [ELOOP] = TARGET_ELOOP,
655 [ERESTART] = TARGET_ERESTART,
656 [ESTRPIPE] = TARGET_ESTRPIPE,
657 [ENOTEMPTY] = TARGET_ENOTEMPTY,
658 [EUSERS] = TARGET_EUSERS,
659 [ENOTSOCK] = TARGET_ENOTSOCK,
660 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
661 [EMSGSIZE] = TARGET_EMSGSIZE,
662 [EPROTOTYPE] = TARGET_EPROTOTYPE,
663 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
664 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
665 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
666 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
667 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
668 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
669 [EADDRINUSE] = TARGET_EADDRINUSE,
670 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
671 [ENETDOWN] = TARGET_ENETDOWN,
672 [ENETUNREACH] = TARGET_ENETUNREACH,
673 [ENETRESET] = TARGET_ENETRESET,
674 [ECONNABORTED] = TARGET_ECONNABORTED,
675 [ECONNRESET] = TARGET_ECONNRESET,
676 [ENOBUFS] = TARGET_ENOBUFS,
677 [EISCONN] = TARGET_EISCONN,
678 [ENOTCONN] = TARGET_ENOTCONN,
679 [EUCLEAN] = TARGET_EUCLEAN,
680 [ENOTNAM] = TARGET_ENOTNAM,
681 [ENAVAIL] = TARGET_ENAVAIL,
682 [EISNAM] = TARGET_EISNAM,
683 [EREMOTEIO] = TARGET_EREMOTEIO,
684 [ESHUTDOWN] = TARGET_ESHUTDOWN,
685 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
686 [ETIMEDOUT] = TARGET_ETIMEDOUT,
687 [ECONNREFUSED] = TARGET_ECONNREFUSED,
688 [EHOSTDOWN] = TARGET_EHOSTDOWN,
689 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
690 [EALREADY] = TARGET_EALREADY,
691 [EINPROGRESS] = TARGET_EINPROGRESS,
692 [ESTALE] = TARGET_ESTALE,
693 [ECANCELED] = TARGET_ECANCELED,
694 [ENOMEDIUM] = TARGET_ENOMEDIUM,
695 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000696#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000697 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000698#endif
699#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000700 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000701#endif
702#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000703 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000704#endif
705#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000706 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000707#endif
708#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000709 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000710#endif
711#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000712 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000713#endif
thsb92c47c2007-11-01 00:07:38 +0000714};
ths637947f2007-06-01 12:09:19 +0000715
716static inline int host_to_target_errno(int err)
717{
718 if(host_to_target_errno_table[err])
719 return host_to_target_errno_table[err];
720 return err;
721}
722
thsb92c47c2007-11-01 00:07:38 +0000723static inline int target_to_host_errno(int err)
724{
725 if (target_to_host_errno_table[err])
726 return target_to_host_errno_table[err];
727 return err;
728}
729
blueswir1992f48a2007-10-14 16:27:31 +0000730static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000731{
732 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000733 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000734 else
735 return ret;
736}
737
blueswir1992f48a2007-10-14 16:27:31 +0000738static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000739{
blueswir1992f48a2007-10-14 16:27:31 +0000740 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000741}
742
thsb92c47c2007-11-01 00:07:38 +0000743char *target_strerror(int err)
744{
745 return strerror(target_to_host_errno(err));
746}
747
blueswir1992f48a2007-10-14 16:27:31 +0000748static abi_ulong target_brk;
749static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000750static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000751
blueswir1992f48a2007-10-14 16:27:31 +0000752void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000753{
blueswir14c1de732007-07-07 20:45:44 +0000754 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000755 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000756}
757
vincent4d1de872011-06-14 21:56:33 +0000758//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
759#define DEBUGF_BRK(message, args...)
760
ths0da46a62007-10-20 20:23:07 +0000761/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000762abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000763{
blueswir1992f48a2007-10-14 16:27:31 +0000764 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000765 int new_alloc_size;
766
vincent4d1de872011-06-14 21:56:33 +0000767 DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000768
vincent4d1de872011-06-14 21:56:33 +0000769 if (!new_brk) {
770 DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
771 return target_brk;
772 }
773 if (new_brk < target_original_brk) {
774 DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
775 return target_brk;
776 }
bellard31e31b82003-02-18 22:55:36 +0000777
vincent4d1de872011-06-14 21:56:33 +0000778 /* If the new brk is less than the highest page reserved to the
779 * target heap allocation, set it and we're almost done... */
780 if (new_brk <= brk_page) {
781 /* Heap contents are initialized to zero, as for anonymous
782 * mapped pages. */
783 if (new_brk > target_brk) {
784 memset(g2h(target_brk), 0, new_brk - target_brk);
785 }
bellard31e31b82003-02-18 22:55:36 +0000786 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000787 DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000788 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000789 }
790
Peter Maydell00faf082011-04-18 16:34:24 +0100791 /* We need to allocate more memory after the brk... Note that
792 * we don't use MAP_FIXED because that will map over the top of
793 * any existing mapping (like the one with the host libc or qemu
794 * itself); instead we treat "mapped but at wrong address" as
795 * a failure and unmap again.
796 */
vincent4d1de872011-06-14 21:56:33 +0000797 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000798 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000799 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100800 MAP_ANON|MAP_PRIVATE, 0, 0));
801
802 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200803 /* Heap contents are initialized to zero, as for anonymous
804 * mapped pages. Technically the new pages are already
805 * initialized to zero since they *are* anonymous mapped
806 * pages, however we have to take care with the contents that
807 * come from the remaining part of the previous page: it may
808 * contains garbage data due to a previous heap usage (grown
809 * then shrunken). */
810 memset(g2h(target_brk), 0, brk_page - target_brk);
811
Peter Maydell00faf082011-04-18 16:34:24 +0100812 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000813 brk_page = HOST_PAGE_ALIGN(target_brk);
814 DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100815 return target_brk;
816 } else if (mapped_addr != -1) {
817 /* Mapped but at wrong address, meaning there wasn't actually
818 * enough space for this brk.
819 */
820 target_munmap(mapped_addr, new_alloc_size);
821 mapped_addr = -1;
vincent4d1de872011-06-14 21:56:33 +0000822 DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
823 }
824 else {
825 DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100826 }
balrog7ab240a2008-04-26 12:17:34 +0000827
Richard Henderson7dd46c02010-05-03 10:07:49 -0700828#if defined(TARGET_ALPHA)
829 /* We (partially) emulate OSF/1 on Alpha, which requires we
830 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100831 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700832#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100833 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000834 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000835}
836
ths26edcf42007-12-09 02:25:24 +0000837static inline abi_long copy_from_user_fdset(fd_set *fds,
838 abi_ulong target_fds_addr,
839 int n)
bellard31e31b82003-02-18 22:55:36 +0000840{
ths26edcf42007-12-09 02:25:24 +0000841 int i, nw, j, k;
842 abi_ulong b, *target_fds;
843
844 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
845 if (!(target_fds = lock_user(VERIFY_READ,
846 target_fds_addr,
847 sizeof(abi_ulong) * nw,
848 1)))
849 return -TARGET_EFAULT;
850
851 FD_ZERO(fds);
852 k = 0;
853 for (i = 0; i < nw; i++) {
854 /* grab the abi_ulong */
855 __get_user(b, &target_fds[i]);
856 for (j = 0; j < TARGET_ABI_BITS; j++) {
857 /* check the bit inside the abi_ulong */
858 if ((b >> j) & 1)
859 FD_SET(k, fds);
860 k++;
bellard31e31b82003-02-18 22:55:36 +0000861 }
bellard31e31b82003-02-18 22:55:36 +0000862 }
ths26edcf42007-12-09 02:25:24 +0000863
864 unlock_user(target_fds, target_fds_addr, 0);
865
866 return 0;
bellard31e31b82003-02-18 22:55:36 +0000867}
868
Mike Frysinger055e0902011-06-03 17:01:49 -0400869static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
870 abi_ulong target_fds_addr,
871 int n)
872{
873 if (target_fds_addr) {
874 if (copy_from_user_fdset(fds, target_fds_addr, n))
875 return -TARGET_EFAULT;
876 *fds_ptr = fds;
877 } else {
878 *fds_ptr = NULL;
879 }
880 return 0;
881}
882
ths26edcf42007-12-09 02:25:24 +0000883static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
884 const fd_set *fds,
885 int n)
bellard31e31b82003-02-18 22:55:36 +0000886{
bellard31e31b82003-02-18 22:55:36 +0000887 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000888 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000889 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000890
ths26edcf42007-12-09 02:25:24 +0000891 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
892 if (!(target_fds = lock_user(VERIFY_WRITE,
893 target_fds_addr,
894 sizeof(abi_ulong) * nw,
895 0)))
896 return -TARGET_EFAULT;
897
898 k = 0;
899 for (i = 0; i < nw; i++) {
900 v = 0;
901 for (j = 0; j < TARGET_ABI_BITS; j++) {
902 v |= ((FD_ISSET(k, fds) != 0) << j);
903 k++;
bellard31e31b82003-02-18 22:55:36 +0000904 }
ths26edcf42007-12-09 02:25:24 +0000905 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000906 }
ths26edcf42007-12-09 02:25:24 +0000907
908 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
909
910 return 0;
bellard31e31b82003-02-18 22:55:36 +0000911}
912
bellardc596ed12003-07-13 17:32:31 +0000913#if defined(__alpha__)
914#define HOST_HZ 1024
915#else
916#define HOST_HZ 100
917#endif
918
blueswir1992f48a2007-10-14 16:27:31 +0000919static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000920{
921#if HOST_HZ == TARGET_HZ
922 return ticks;
923#else
924 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
925#endif
926}
927
bellard579a97f2007-11-11 14:26:47 +0000928static inline abi_long host_to_target_rusage(abi_ulong target_addr,
929 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000930{
pbrook53a59602006-03-25 19:31:22 +0000931 struct target_rusage *target_rusage;
932
bellard579a97f2007-11-11 14:26:47 +0000933 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
934 return -TARGET_EFAULT;
bellardb4091862003-05-16 15:39:34 +0000935 target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
936 target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
937 target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
938 target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
939 target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
940 target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
941 target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
942 target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
943 target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
944 target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
945 target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
946 target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
947 target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
948 target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
949 target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
950 target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
951 target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
952 target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000953 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000954
955 return 0;
bellardb4091862003-05-16 15:39:34 +0000956}
957
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900958static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
959{
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300960 target_ulong target_rlim_swap;
961 rlim_t result;
962
963 target_rlim_swap = tswapl(target_rlim);
964 if (target_rlim_swap == TARGET_RLIM_INFINITY || target_rlim_swap != (rlim_t)target_rlim_swap)
965 result = RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900966 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300967 result = target_rlim_swap;
968
969 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900970}
971
972static inline target_ulong host_to_target_rlim(rlim_t rlim)
973{
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300974 target_ulong target_rlim_swap;
975 target_ulong result;
976
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900977 if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300978 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900979 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300980 target_rlim_swap = rlim;
981 result = tswapl(target_rlim_swap);
982
983 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900984}
985
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300986static inline int target_to_host_resource(int code)
987{
988 switch (code) {
989 case TARGET_RLIMIT_AS:
990 return RLIMIT_AS;
991 case TARGET_RLIMIT_CORE:
992 return RLIMIT_CORE;
993 case TARGET_RLIMIT_CPU:
994 return RLIMIT_CPU;
995 case TARGET_RLIMIT_DATA:
996 return RLIMIT_DATA;
997 case TARGET_RLIMIT_FSIZE:
998 return RLIMIT_FSIZE;
999 case TARGET_RLIMIT_LOCKS:
1000 return RLIMIT_LOCKS;
1001 case TARGET_RLIMIT_MEMLOCK:
1002 return RLIMIT_MEMLOCK;
1003 case TARGET_RLIMIT_MSGQUEUE:
1004 return RLIMIT_MSGQUEUE;
1005 case TARGET_RLIMIT_NICE:
1006 return RLIMIT_NICE;
1007 case TARGET_RLIMIT_NOFILE:
1008 return RLIMIT_NOFILE;
1009 case TARGET_RLIMIT_NPROC:
1010 return RLIMIT_NPROC;
1011 case TARGET_RLIMIT_RSS:
1012 return RLIMIT_RSS;
1013 case TARGET_RLIMIT_RTPRIO:
1014 return RLIMIT_RTPRIO;
1015 case TARGET_RLIMIT_SIGPENDING:
1016 return RLIMIT_SIGPENDING;
1017 case TARGET_RLIMIT_STACK:
1018 return RLIMIT_STACK;
1019 default:
1020 return code;
1021 }
1022}
1023
ths788f5ec2007-12-09 02:37:05 +00001024static inline abi_long copy_from_user_timeval(struct timeval *tv,
1025 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001026{
pbrook53a59602006-03-25 19:31:22 +00001027 struct target_timeval *target_tv;
1028
ths788f5ec2007-12-09 02:37:05 +00001029 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001030 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001031
1032 __get_user(tv->tv_sec, &target_tv->tv_sec);
1033 __get_user(tv->tv_usec, &target_tv->tv_usec);
1034
1035 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001036
1037 return 0;
bellard31e31b82003-02-18 22:55:36 +00001038}
1039
ths788f5ec2007-12-09 02:37:05 +00001040static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1041 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001042{
pbrook53a59602006-03-25 19:31:22 +00001043 struct target_timeval *target_tv;
1044
ths788f5ec2007-12-09 02:37:05 +00001045 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001046 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001047
1048 __put_user(tv->tv_sec, &target_tv->tv_sec);
1049 __put_user(tv->tv_usec, &target_tv->tv_usec);
1050
1051 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001052
1053 return 0;
bellard31e31b82003-02-18 22:55:36 +00001054}
1055
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001056#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1057#include <mqueue.h>
1058
aurel3224e10032009-04-15 16:11:43 +00001059static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1060 abi_ulong target_mq_attr_addr)
1061{
1062 struct target_mq_attr *target_mq_attr;
1063
1064 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1065 target_mq_attr_addr, 1))
1066 return -TARGET_EFAULT;
1067
1068 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1069 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1070 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1071 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1072
1073 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1074
1075 return 0;
1076}
1077
1078static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1079 const struct mq_attr *attr)
1080{
1081 struct target_mq_attr *target_mq_attr;
1082
1083 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1084 target_mq_attr_addr, 0))
1085 return -TARGET_EFAULT;
1086
1087 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1088 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1089 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1090 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1091
1092 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1093
1094 return 0;
1095}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001096#endif
bellard31e31b82003-02-18 22:55:36 +00001097
Mike Frysinger055e0902011-06-03 17:01:49 -04001098#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001099/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001100static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001101 abi_ulong rfd_addr, abi_ulong wfd_addr,
1102 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001103{
1104 fd_set rfds, wfds, efds;
1105 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1106 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001107 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001108
Mike Frysinger055e0902011-06-03 17:01:49 -04001109 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1110 if (ret) {
1111 return ret;
pbrook53a59602006-03-25 19:31:22 +00001112 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001113 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1114 if (ret) {
1115 return ret;
pbrook53a59602006-03-25 19:31:22 +00001116 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001117 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1118 if (ret) {
1119 return ret;
pbrook53a59602006-03-25 19:31:22 +00001120 }
ths3b46e622007-09-17 08:09:54 +00001121
ths26edcf42007-12-09 02:25:24 +00001122 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001123 if (copy_from_user_timeval(&tv, target_tv_addr))
1124 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001125 tv_ptr = &tv;
1126 } else {
1127 tv_ptr = NULL;
1128 }
ths26edcf42007-12-09 02:25:24 +00001129
bellard31e31b82003-02-18 22:55:36 +00001130 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001131
ths26edcf42007-12-09 02:25:24 +00001132 if (!is_error(ret)) {
1133 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1134 return -TARGET_EFAULT;
1135 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1136 return -TARGET_EFAULT;
1137 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1138 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001139
ths788f5ec2007-12-09 02:37:05 +00001140 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1141 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001142 }
bellard579a97f2007-11-11 14:26:47 +00001143
bellard31e31b82003-02-18 22:55:36 +00001144 return ret;
1145}
Mike Frysinger055e0902011-06-03 17:01:49 -04001146#endif
bellard31e31b82003-02-18 22:55:36 +00001147
Riku Voipio099d6b02009-05-05 12:10:04 +03001148static abi_long do_pipe2(int host_pipe[], int flags)
1149{
1150#ifdef CONFIG_PIPE2
1151 return pipe2(host_pipe, flags);
1152#else
1153 return -ENOSYS;
1154#endif
1155}
1156
Richard Hendersonfb41a662010-05-03 10:07:52 -07001157static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1158 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001159{
1160 int host_pipe[2];
1161 abi_long ret;
1162 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1163
1164 if (is_error(ret))
1165 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001166
1167 /* Several targets have special calling conventions for the original
1168 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1169 if (!is_pipe2) {
1170#if defined(TARGET_ALPHA)
1171 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1172 return host_pipe[0];
1173#elif defined(TARGET_MIPS)
1174 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1175 return host_pipe[0];
1176#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001177 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001178 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001179#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001180 }
1181
Riku Voipio099d6b02009-05-05 12:10:04 +03001182 if (put_user_s32(host_pipe[0], pipedes)
1183 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1184 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001185 return get_errno(ret);
1186}
1187
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001188static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1189 abi_ulong target_addr,
1190 socklen_t len)
1191{
1192 struct target_ip_mreqn *target_smreqn;
1193
1194 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1195 if (!target_smreqn)
1196 return -TARGET_EFAULT;
1197 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1198 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1199 if (len == sizeof(struct target_ip_mreqn))
1200 mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
1201 unlock_user(target_smreqn, target_addr, 0);
1202
1203 return 0;
1204}
1205
bellard579a97f2007-11-11 14:26:47 +00001206static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1207 abi_ulong target_addr,
1208 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001209{
aurel32607175e2009-04-15 16:11:59 +00001210 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1211 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001212 struct target_sockaddr *target_saddr;
1213
bellard579a97f2007-11-11 14:26:47 +00001214 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1215 if (!target_saddr)
1216 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001217
1218 sa_family = tswap16(target_saddr->sa_family);
1219
1220 /* Oops. The caller might send a incomplete sun_path; sun_path
1221 * must be terminated by \0 (see the manual page), but
1222 * unfortunately it is quite common to specify sockaddr_un
1223 * length as "strlen(x->sun_path)" while it should be
1224 * "strlen(...) + 1". We'll fix that here if needed.
1225 * Linux kernel has a similar feature.
1226 */
1227
1228 if (sa_family == AF_UNIX) {
1229 if (len < unix_maxlen && len > 0) {
1230 char *cp = (char*)target_saddr;
1231
1232 if ( cp[len-1] && !cp[len] )
1233 len++;
1234 }
1235 if (len > unix_maxlen)
1236 len = unix_maxlen;
1237 }
1238
pbrook53a59602006-03-25 19:31:22 +00001239 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001240 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001241 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001242
1243 return 0;
bellard7854b052003-03-29 17:22:23 +00001244}
1245
bellard579a97f2007-11-11 14:26:47 +00001246static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1247 struct sockaddr *addr,
1248 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001249{
pbrook53a59602006-03-25 19:31:22 +00001250 struct target_sockaddr *target_saddr;
1251
bellard579a97f2007-11-11 14:26:47 +00001252 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1253 if (!target_saddr)
1254 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001255 memcpy(target_saddr, addr, len);
1256 target_saddr->sa_family = tswap16(addr->sa_family);
1257 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001258
1259 return 0;
bellard7854b052003-03-29 17:22:23 +00001260}
1261
pbrook53a59602006-03-25 19:31:22 +00001262/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001263static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1264 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001265{
1266 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001267 abi_long msg_controllen;
1268 abi_ulong target_cmsg_addr;
1269 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001270 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001271
1272 msg_controllen = tswapl(target_msgh->msg_controllen);
1273 if (msg_controllen < sizeof (struct target_cmsghdr))
1274 goto the_end;
1275 target_cmsg_addr = tswapl(target_msgh->msg_control);
1276 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1277 if (!target_cmsg)
1278 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001279
1280 while (cmsg && target_cmsg) {
1281 void *data = CMSG_DATA(cmsg);
1282 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1283
ths5fafdf22007-09-16 21:08:06 +00001284 int len = tswapl(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001285 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1286
1287 space += CMSG_SPACE(len);
1288 if (space > msgh->msg_controllen) {
1289 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001290 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001291 break;
1292 }
1293
1294 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1295 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1296 cmsg->cmsg_len = CMSG_LEN(len);
1297
bellard3532fa72006-06-24 15:06:03 +00001298 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001299 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1300 memcpy(data, target_data, len);
1301 } else {
1302 int *fd = (int *)data;
1303 int *target_fd = (int *)target_data;
1304 int i, numfds = len / sizeof(int);
1305
1306 for (i = 0; i < numfds; i++)
1307 fd[i] = tswap32(target_fd[i]);
1308 }
1309
1310 cmsg = CMSG_NXTHDR(msgh, cmsg);
1311 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1312 }
bellard5a4a8982007-11-11 17:39:18 +00001313 unlock_user(target_cmsg, target_cmsg_addr, 0);
1314 the_end:
bellard7854b052003-03-29 17:22:23 +00001315 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001316 return 0;
bellard7854b052003-03-29 17:22:23 +00001317}
1318
pbrook53a59602006-03-25 19:31:22 +00001319/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001320static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1321 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001322{
1323 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001324 abi_long msg_controllen;
1325 abi_ulong target_cmsg_addr;
1326 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001327 socklen_t space = 0;
1328
bellard5a4a8982007-11-11 17:39:18 +00001329 msg_controllen = tswapl(target_msgh->msg_controllen);
1330 if (msg_controllen < sizeof (struct target_cmsghdr))
1331 goto the_end;
1332 target_cmsg_addr = tswapl(target_msgh->msg_control);
1333 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1334 if (!target_cmsg)
1335 return -TARGET_EFAULT;
1336
bellard7854b052003-03-29 17:22:23 +00001337 while (cmsg && target_cmsg) {
1338 void *data = CMSG_DATA(cmsg);
1339 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1340
1341 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1342
1343 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001344 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001345 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001346 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001347 break;
1348 }
1349
1350 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1351 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
1352 target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
1353
bellard3532fa72006-06-24 15:06:03 +00001354 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001355 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1356 memcpy(target_data, data, len);
1357 } else {
1358 int *fd = (int *)data;
1359 int *target_fd = (int *)target_data;
1360 int i, numfds = len / sizeof(int);
1361
1362 for (i = 0; i < numfds; i++)
1363 target_fd[i] = tswap32(fd[i]);
1364 }
1365
1366 cmsg = CMSG_NXTHDR(msgh, cmsg);
1367 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1368 }
bellard5a4a8982007-11-11 17:39:18 +00001369 unlock_user(target_cmsg, target_cmsg_addr, space);
1370 the_end:
1371 target_msgh->msg_controllen = tswapl(space);
1372 return 0;
bellard7854b052003-03-29 17:22:23 +00001373}
1374
ths0da46a62007-10-20 20:23:07 +00001375/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001376static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001377 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001378{
blueswir1992f48a2007-10-14 16:27:31 +00001379 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001380 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001381 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001382 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001383
bellard8853f862004-02-22 14:57:26 +00001384 switch(level) {
1385 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001386 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001387 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001388 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001389
bellard2f619692007-11-16 10:46:05 +00001390 if (get_user_u32(val, optval_addr))
1391 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001392 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1393 break;
1394 case SOL_IP:
1395 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001396 case IP_TOS:
1397 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001398 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001399 case IP_ROUTER_ALERT:
1400 case IP_RECVOPTS:
1401 case IP_RETOPTS:
1402 case IP_PKTINFO:
1403 case IP_MTU_DISCOVER:
1404 case IP_RECVERR:
1405 case IP_RECVTOS:
1406#ifdef IP_FREEBIND
1407 case IP_FREEBIND:
1408#endif
1409 case IP_MULTICAST_TTL:
1410 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001411 val = 0;
1412 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001413 if (get_user_u32(val, optval_addr))
1414 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001415 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001416 if (get_user_u8(val, optval_addr))
1417 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001418 }
1419 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1420 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001421 case IP_ADD_MEMBERSHIP:
1422 case IP_DROP_MEMBERSHIP:
1423 if (optlen < sizeof (struct target_ip_mreq) ||
1424 optlen > sizeof (struct target_ip_mreqn))
1425 return -TARGET_EINVAL;
1426
1427 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1428 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1429 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1430 break;
1431
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001432 case IP_BLOCK_SOURCE:
1433 case IP_UNBLOCK_SOURCE:
1434 case IP_ADD_SOURCE_MEMBERSHIP:
1435 case IP_DROP_SOURCE_MEMBERSHIP:
1436 if (optlen != sizeof (struct target_ip_mreq_source))
1437 return -TARGET_EINVAL;
1438
1439 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1440 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1441 unlock_user (ip_mreq_source, optval_addr, 0);
1442 break;
1443
bellard8853f862004-02-22 14:57:26 +00001444 default:
1445 goto unimplemented;
1446 }
1447 break;
bellard3532fa72006-06-24 15:06:03 +00001448 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001449 switch (optname) {
1450 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001451 case TARGET_SO_DEBUG:
1452 optname = SO_DEBUG;
1453 break;
1454 case TARGET_SO_REUSEADDR:
1455 optname = SO_REUSEADDR;
1456 break;
1457 case TARGET_SO_TYPE:
1458 optname = SO_TYPE;
1459 break;
1460 case TARGET_SO_ERROR:
1461 optname = SO_ERROR;
1462 break;
1463 case TARGET_SO_DONTROUTE:
1464 optname = SO_DONTROUTE;
1465 break;
1466 case TARGET_SO_BROADCAST:
1467 optname = SO_BROADCAST;
1468 break;
1469 case TARGET_SO_SNDBUF:
1470 optname = SO_SNDBUF;
1471 break;
1472 case TARGET_SO_RCVBUF:
1473 optname = SO_RCVBUF;
1474 break;
1475 case TARGET_SO_KEEPALIVE:
1476 optname = SO_KEEPALIVE;
1477 break;
1478 case TARGET_SO_OOBINLINE:
1479 optname = SO_OOBINLINE;
1480 break;
1481 case TARGET_SO_NO_CHECK:
1482 optname = SO_NO_CHECK;
1483 break;
1484 case TARGET_SO_PRIORITY:
1485 optname = SO_PRIORITY;
1486 break;
bellard5e83e8e2005-03-01 22:32:06 +00001487#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001488 case TARGET_SO_BSDCOMPAT:
1489 optname = SO_BSDCOMPAT;
1490 break;
bellard5e83e8e2005-03-01 22:32:06 +00001491#endif
bellard3532fa72006-06-24 15:06:03 +00001492 case TARGET_SO_PASSCRED:
1493 optname = SO_PASSCRED;
1494 break;
1495 case TARGET_SO_TIMESTAMP:
1496 optname = SO_TIMESTAMP;
1497 break;
1498 case TARGET_SO_RCVLOWAT:
1499 optname = SO_RCVLOWAT;
1500 break;
1501 case TARGET_SO_RCVTIMEO:
1502 optname = SO_RCVTIMEO;
1503 break;
1504 case TARGET_SO_SNDTIMEO:
1505 optname = SO_SNDTIMEO;
1506 break;
bellard8853f862004-02-22 14:57:26 +00001507 break;
1508 default:
1509 goto unimplemented;
1510 }
bellard3532fa72006-06-24 15:06:03 +00001511 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001512 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001513
bellard2f619692007-11-16 10:46:05 +00001514 if (get_user_u32(val, optval_addr))
1515 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001516 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001517 break;
bellard7854b052003-03-29 17:22:23 +00001518 default:
bellard8853f862004-02-22 14:57:26 +00001519 unimplemented:
1520 gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001521 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001522 }
bellard8853f862004-02-22 14:57:26 +00001523 return ret;
bellard7854b052003-03-29 17:22:23 +00001524}
1525
ths0da46a62007-10-20 20:23:07 +00001526/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001527static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001528 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001529{
blueswir1992f48a2007-10-14 16:27:31 +00001530 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001531 int len, val;
1532 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001533
1534 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001535 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001536 level = SOL_SOCKET;
1537 switch (optname) {
1538 /* These don't just return a single integer */
1539 case TARGET_SO_LINGER:
1540 case TARGET_SO_RCVTIMEO:
1541 case TARGET_SO_SNDTIMEO:
1542 case TARGET_SO_PEERCRED:
1543 case TARGET_SO_PEERNAME:
1544 goto unimplemented;
1545 /* Options with 'int' argument. */
1546 case TARGET_SO_DEBUG:
1547 optname = SO_DEBUG;
1548 goto int_case;
1549 case TARGET_SO_REUSEADDR:
1550 optname = SO_REUSEADDR;
1551 goto int_case;
1552 case TARGET_SO_TYPE:
1553 optname = SO_TYPE;
1554 goto int_case;
1555 case TARGET_SO_ERROR:
1556 optname = SO_ERROR;
1557 goto int_case;
1558 case TARGET_SO_DONTROUTE:
1559 optname = SO_DONTROUTE;
1560 goto int_case;
1561 case TARGET_SO_BROADCAST:
1562 optname = SO_BROADCAST;
1563 goto int_case;
1564 case TARGET_SO_SNDBUF:
1565 optname = SO_SNDBUF;
1566 goto int_case;
1567 case TARGET_SO_RCVBUF:
1568 optname = SO_RCVBUF;
1569 goto int_case;
1570 case TARGET_SO_KEEPALIVE:
1571 optname = SO_KEEPALIVE;
1572 goto int_case;
1573 case TARGET_SO_OOBINLINE:
1574 optname = SO_OOBINLINE;
1575 goto int_case;
1576 case TARGET_SO_NO_CHECK:
1577 optname = SO_NO_CHECK;
1578 goto int_case;
1579 case TARGET_SO_PRIORITY:
1580 optname = SO_PRIORITY;
1581 goto int_case;
1582#ifdef SO_BSDCOMPAT
1583 case TARGET_SO_BSDCOMPAT:
1584 optname = SO_BSDCOMPAT;
1585 goto int_case;
1586#endif
1587 case TARGET_SO_PASSCRED:
1588 optname = SO_PASSCRED;
1589 goto int_case;
1590 case TARGET_SO_TIMESTAMP:
1591 optname = SO_TIMESTAMP;
1592 goto int_case;
1593 case TARGET_SO_RCVLOWAT:
1594 optname = SO_RCVLOWAT;
1595 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001596 default:
bellard2efbe912005-07-23 15:10:20 +00001597 goto int_case;
1598 }
1599 break;
1600 case SOL_TCP:
1601 /* TCP options all take an 'int' value. */
1602 int_case:
bellard2f619692007-11-16 10:46:05 +00001603 if (get_user_u32(len, optlen))
1604 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001605 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001606 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001607 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001608 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1609 if (ret < 0)
1610 return ret;
bellard2efbe912005-07-23 15:10:20 +00001611 if (len > lv)
1612 len = lv;
bellard2f619692007-11-16 10:46:05 +00001613 if (len == 4) {
1614 if (put_user_u32(val, optval_addr))
1615 return -TARGET_EFAULT;
1616 } else {
1617 if (put_user_u8(val, optval_addr))
1618 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001619 }
bellard2f619692007-11-16 10:46:05 +00001620 if (put_user_u32(len, optlen))
1621 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001622 break;
1623 case SOL_IP:
1624 switch(optname) {
1625 case IP_TOS:
1626 case IP_TTL:
1627 case IP_HDRINCL:
1628 case IP_ROUTER_ALERT:
1629 case IP_RECVOPTS:
1630 case IP_RETOPTS:
1631 case IP_PKTINFO:
1632 case IP_MTU_DISCOVER:
1633 case IP_RECVERR:
1634 case IP_RECVTOS:
1635#ifdef IP_FREEBIND
1636 case IP_FREEBIND:
1637#endif
1638 case IP_MULTICAST_TTL:
1639 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001640 if (get_user_u32(len, optlen))
1641 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001642 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001643 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001644 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001645 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1646 if (ret < 0)
1647 return ret;
bellard2efbe912005-07-23 15:10:20 +00001648 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001649 len = 1;
bellard2f619692007-11-16 10:46:05 +00001650 if (put_user_u32(len, optlen)
1651 || put_user_u8(val, optval_addr))
1652 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001653 } else {
bellard2efbe912005-07-23 15:10:20 +00001654 if (len > sizeof(int))
1655 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001656 if (put_user_u32(len, optlen)
1657 || put_user_u32(val, optval_addr))
1658 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001659 }
bellard8853f862004-02-22 14:57:26 +00001660 break;
bellard2efbe912005-07-23 15:10:20 +00001661 default:
thsc02f4992007-12-18 02:39:59 +00001662 ret = -TARGET_ENOPROTOOPT;
1663 break;
bellard8853f862004-02-22 14:57:26 +00001664 }
1665 break;
1666 default:
1667 unimplemented:
1668 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1669 level, optname);
thsc02f4992007-12-18 02:39:59 +00001670 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001671 break;
1672 }
1673 return ret;
bellard7854b052003-03-29 17:22:23 +00001674}
1675
bellard579a97f2007-11-11 14:26:47 +00001676/* FIXME
1677 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1678 * other lock functions have a return code of 0 for failure.
1679 */
1680static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1681 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001682{
1683 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001684 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001685 int i;
pbrook53a59602006-03-25 19:31:22 +00001686
bellard579a97f2007-11-11 14:26:47 +00001687 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1688 if (!target_vec)
1689 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001690 for(i = 0;i < count; i++) {
1691 base = tswapl(target_vec[i].iov_base);
1692 vec[i].iov_len = tswapl(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001693 if (vec[i].iov_len != 0) {
1694 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001695 /* Don't check lock_user return value. We must call writev even
1696 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001697 } else {
1698 /* zero length pointer is ignored */
1699 vec[i].iov_base = NULL;
1700 }
pbrook53a59602006-03-25 19:31:22 +00001701 }
1702 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001703 return 0;
pbrook53a59602006-03-25 19:31:22 +00001704}
1705
bellard579a97f2007-11-11 14:26:47 +00001706static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1707 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001708{
1709 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001710 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001711 int i;
1712
bellard579a97f2007-11-11 14:26:47 +00001713 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1714 if (!target_vec)
1715 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001716 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001717 if (target_vec[i].iov_base) {
1718 base = tswapl(target_vec[i].iov_base);
1719 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1720 }
pbrook53a59602006-03-25 19:31:22 +00001721 }
1722 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001723
1724 return 0;
pbrook53a59602006-03-25 19:31:22 +00001725}
1726
ths0da46a62007-10-20 20:23:07 +00001727/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001728static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001729{
1730#if defined(TARGET_MIPS)
1731 switch(type) {
1732 case TARGET_SOCK_DGRAM:
1733 type = SOCK_DGRAM;
1734 break;
1735 case TARGET_SOCK_STREAM:
1736 type = SOCK_STREAM;
1737 break;
1738 case TARGET_SOCK_RAW:
1739 type = SOCK_RAW;
1740 break;
1741 case TARGET_SOCK_RDM:
1742 type = SOCK_RDM;
1743 break;
1744 case TARGET_SOCK_SEQPACKET:
1745 type = SOCK_SEQPACKET;
1746 break;
1747 case TARGET_SOCK_PACKET:
1748 type = SOCK_PACKET;
1749 break;
1750 }
1751#endif
balrog12bc92a2007-10-30 21:06:14 +00001752 if (domain == PF_NETLINK)
1753 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001754 return get_errno(socket(domain, type, protocol));
1755}
1756
ths0da46a62007-10-20 20:23:07 +00001757/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001758static abi_long do_bind(int sockfd, abi_ulong target_addr,
1759 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001760{
aurel328f7aeaf2009-01-30 19:47:57 +00001761 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001762 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001763
Blue Swirl38724252010-09-18 05:53:14 +00001764 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001765 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001766 }
aurel328f7aeaf2009-01-30 19:47:57 +00001767
aurel32607175e2009-04-15 16:11:59 +00001768 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001769
Arnaud Patard917507b2009-06-19 10:44:45 +03001770 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1771 if (ret)
1772 return ret;
1773
bellard3532fa72006-06-24 15:06:03 +00001774 return get_errno(bind(sockfd, addr, addrlen));
1775}
1776
ths0da46a62007-10-20 20:23:07 +00001777/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001778static abi_long do_connect(int sockfd, abi_ulong target_addr,
1779 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001780{
aurel328f7aeaf2009-01-30 19:47:57 +00001781 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001782 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001783
Blue Swirl38724252010-09-18 05:53:14 +00001784 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001785 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001786 }
aurel328f7aeaf2009-01-30 19:47:57 +00001787
1788 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001789
Arnaud Patard917507b2009-06-19 10:44:45 +03001790 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1791 if (ret)
1792 return ret;
1793
bellard3532fa72006-06-24 15:06:03 +00001794 return get_errno(connect(sockfd, addr, addrlen));
1795}
1796
ths0da46a62007-10-20 20:23:07 +00001797/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001798static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1799 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001800{
balrog6de645c2008-10-28 10:26:29 +00001801 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001802 struct target_msghdr *msgp;
1803 struct msghdr msg;
1804 int count;
1805 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001806 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001807
bellard579a97f2007-11-11 14:26:47 +00001808 /* FIXME */
1809 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1810 msgp,
1811 target_msg,
1812 send ? 1 : 0))
1813 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001814 if (msgp->msg_name) {
1815 msg.msg_namelen = tswap32(msgp->msg_namelen);
1816 msg.msg_name = alloca(msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001817 ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001818 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001819 if (ret) {
1820 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1821 return ret;
1822 }
bellard3532fa72006-06-24 15:06:03 +00001823 } else {
1824 msg.msg_name = NULL;
1825 msg.msg_namelen = 0;
1826 }
1827 msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
1828 msg.msg_control = alloca(msg.msg_controllen);
1829 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001830
bellard3532fa72006-06-24 15:06:03 +00001831 count = tswapl(msgp->msg_iovlen);
1832 vec = alloca(count * sizeof(struct iovec));
1833 target_vec = tswapl(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001834 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001835 msg.msg_iovlen = count;
1836 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001837
bellard3532fa72006-06-24 15:06:03 +00001838 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001839 ret = target_to_host_cmsg(&msg, msgp);
1840 if (ret == 0)
1841 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001842 } else {
1843 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001844 if (!is_error(ret)) {
1845 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001846 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001847 if (!is_error(ret))
1848 ret = len;
1849 }
bellard3532fa72006-06-24 15:06:03 +00001850 }
1851 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001852 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001853 return ret;
1854}
1855
ths0da46a62007-10-20 20:23:07 +00001856/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001857static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001858 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001859{
bellard2f619692007-11-16 10:46:05 +00001860 socklen_t addrlen;
1861 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001862 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001863
Arnaud Patard917507b2009-06-19 10:44:45 +03001864 if (target_addr == 0)
1865 return get_errno(accept(fd, NULL, NULL));
1866
1867 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001868 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001869 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001870
Blue Swirl38724252010-09-18 05:53:14 +00001871 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001872 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001873 }
aurel328f7aeaf2009-01-30 19:47:57 +00001874
Arnaud Patard917507b2009-06-19 10:44:45 +03001875 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1876 return -TARGET_EINVAL;
1877
bellard2f619692007-11-16 10:46:05 +00001878 addr = alloca(addrlen);
1879
pbrook1be9e1d2006-11-19 15:26:04 +00001880 ret = get_errno(accept(fd, addr, &addrlen));
1881 if (!is_error(ret)) {
1882 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001883 if (put_user_u32(addrlen, target_addrlen_addr))
1884 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001885 }
1886 return ret;
1887}
1888
ths0da46a62007-10-20 20:23:07 +00001889/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001890static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001891 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001892{
bellard2f619692007-11-16 10:46:05 +00001893 socklen_t addrlen;
1894 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001895 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001896
bellard2f619692007-11-16 10:46:05 +00001897 if (get_user_u32(addrlen, target_addrlen_addr))
1898 return -TARGET_EFAULT;
1899
Blue Swirl38724252010-09-18 05:53:14 +00001900 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001901 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001902 }
aurel328f7aeaf2009-01-30 19:47:57 +00001903
Arnaud Patard917507b2009-06-19 10:44:45 +03001904 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1905 return -TARGET_EFAULT;
1906
bellard2f619692007-11-16 10:46:05 +00001907 addr = alloca(addrlen);
1908
pbrook1be9e1d2006-11-19 15:26:04 +00001909 ret = get_errno(getpeername(fd, addr, &addrlen));
1910 if (!is_error(ret)) {
1911 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001912 if (put_user_u32(addrlen, target_addrlen_addr))
1913 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001914 }
1915 return ret;
1916}
1917
ths0da46a62007-10-20 20:23:07 +00001918/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001919static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001920 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001921{
bellard2f619692007-11-16 10:46:05 +00001922 socklen_t addrlen;
1923 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001924 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001925
bellard2f619692007-11-16 10:46:05 +00001926 if (get_user_u32(addrlen, target_addrlen_addr))
1927 return -TARGET_EFAULT;
1928
Blue Swirl38724252010-09-18 05:53:14 +00001929 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001930 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001931 }
aurel328f7aeaf2009-01-30 19:47:57 +00001932
Arnaud Patard917507b2009-06-19 10:44:45 +03001933 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1934 return -TARGET_EFAULT;
1935
bellard2f619692007-11-16 10:46:05 +00001936 addr = alloca(addrlen);
1937
pbrook1be9e1d2006-11-19 15:26:04 +00001938 ret = get_errno(getsockname(fd, addr, &addrlen));
1939 if (!is_error(ret)) {
1940 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001941 if (put_user_u32(addrlen, target_addrlen_addr))
1942 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001943 }
1944 return ret;
1945}
1946
ths0da46a62007-10-20 20:23:07 +00001947/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001948static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001949 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001950{
1951 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001952 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001953
1954 ret = get_errno(socketpair(domain, type, protocol, tab));
1955 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001956 if (put_user_s32(tab[0], target_tab_addr)
1957 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1958 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001959 }
1960 return ret;
1961}
1962
ths0da46a62007-10-20 20:23:07 +00001963/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001964static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1965 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001966{
1967 void *addr;
1968 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001969 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001970
Blue Swirl38724252010-09-18 05:53:14 +00001971 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001972 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001973 }
aurel328f7aeaf2009-01-30 19:47:57 +00001974
bellard579a97f2007-11-11 14:26:47 +00001975 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1976 if (!host_msg)
1977 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001978 if (target_addr) {
1979 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001980 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1981 if (ret) {
1982 unlock_user(host_msg, msg, 0);
1983 return ret;
1984 }
pbrook1be9e1d2006-11-19 15:26:04 +00001985 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1986 } else {
1987 ret = get_errno(send(fd, host_msg, len, flags));
1988 }
1989 unlock_user(host_msg, msg, 0);
1990 return ret;
1991}
1992
ths0da46a62007-10-20 20:23:07 +00001993/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001994static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1995 abi_ulong target_addr,
1996 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001997{
1998 socklen_t addrlen;
1999 void *addr;
2000 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002001 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002002
bellard579a97f2007-11-11 14:26:47 +00002003 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2004 if (!host_msg)
2005 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002006 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002007 if (get_user_u32(addrlen, target_addrlen)) {
2008 ret = -TARGET_EFAULT;
2009 goto fail;
2010 }
Blue Swirl38724252010-09-18 05:53:14 +00002011 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002012 ret = -TARGET_EINVAL;
2013 goto fail;
2014 }
pbrook1be9e1d2006-11-19 15:26:04 +00002015 addr = alloca(addrlen);
2016 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2017 } else {
2018 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002019 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002020 }
2021 if (!is_error(ret)) {
2022 if (target_addr) {
2023 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002024 if (put_user_u32(addrlen, target_addrlen)) {
2025 ret = -TARGET_EFAULT;
2026 goto fail;
2027 }
pbrook1be9e1d2006-11-19 15:26:04 +00002028 }
2029 unlock_user(host_msg, msg, len);
2030 } else {
bellard2f619692007-11-16 10:46:05 +00002031fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002032 unlock_user(host_msg, msg, 0);
2033 }
2034 return ret;
2035}
2036
j_mayer32407102007-09-26 23:01:49 +00002037#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002038/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002039static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002040{
blueswir1992f48a2007-10-14 16:27:31 +00002041 abi_long ret;
2042 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002043
2044 switch(num) {
2045 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002046 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002047 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002048
Ulrich Hecht98818182009-07-03 17:09:28 +02002049 if (get_user_ual(domain, vptr)
2050 || get_user_ual(type, vptr + n)
2051 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002052 return -TARGET_EFAULT;
2053
bellard3532fa72006-06-24 15:06:03 +00002054 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002055 }
bellard31e31b82003-02-18 22:55:36 +00002056 break;
2057 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002058 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002059 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002060 abi_ulong target_addr;
2061 socklen_t addrlen;
2062
Ulrich Hecht98818182009-07-03 17:09:28 +02002063 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002064 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002065 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002066 return -TARGET_EFAULT;
2067
bellard3532fa72006-06-24 15:06:03 +00002068 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002069 }
bellard31e31b82003-02-18 22:55:36 +00002070 break;
2071 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002072 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002073 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002074 abi_ulong target_addr;
2075 socklen_t addrlen;
2076
Ulrich Hecht98818182009-07-03 17:09:28 +02002077 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002078 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002079 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002080 return -TARGET_EFAULT;
2081
bellard3532fa72006-06-24 15:06:03 +00002082 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002083 }
bellard31e31b82003-02-18 22:55:36 +00002084 break;
2085 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002086 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002087 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002088
Ulrich Hecht98818182009-07-03 17:09:28 +02002089 if (get_user_ual(sockfd, vptr)
2090 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002091 return -TARGET_EFAULT;
2092
bellard7854b052003-03-29 17:22:23 +00002093 ret = get_errno(listen(sockfd, backlog));
2094 }
bellard31e31b82003-02-18 22:55:36 +00002095 break;
2096 case SOCKOP_accept:
2097 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002098 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002099 abi_ulong target_addr, target_addrlen;
2100
Ulrich Hecht98818182009-07-03 17:09:28 +02002101 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002102 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002103 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002104 return -TARGET_EFAULT;
2105
pbrook1be9e1d2006-11-19 15:26:04 +00002106 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002107 }
2108 break;
2109 case SOCKOP_getsockname:
2110 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002111 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002112 abi_ulong target_addr, target_addrlen;
2113
Ulrich Hecht98818182009-07-03 17:09:28 +02002114 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002115 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002116 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002117 return -TARGET_EFAULT;
2118
pbrook1be9e1d2006-11-19 15:26:04 +00002119 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002120 }
2121 break;
2122 case SOCKOP_getpeername:
2123 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002124 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002125 abi_ulong target_addr, target_addrlen;
2126
Ulrich Hecht98818182009-07-03 17:09:28 +02002127 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002128 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002129 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002130 return -TARGET_EFAULT;
2131
pbrook1be9e1d2006-11-19 15:26:04 +00002132 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002133 }
2134 break;
2135 case SOCKOP_socketpair:
2136 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002137 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002138 abi_ulong tab;
2139
Ulrich Hecht98818182009-07-03 17:09:28 +02002140 if (get_user_ual(domain, vptr)
2141 || get_user_ual(type, vptr + n)
2142 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002143 || get_user_ual(tab, vptr + 3 * n))
2144 return -TARGET_EFAULT;
2145
pbrook1be9e1d2006-11-19 15:26:04 +00002146 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002147 }
2148 break;
2149 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002150 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002151 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002152 abi_ulong msg;
2153 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002154 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002155
Ulrich Hecht98818182009-07-03 17:09:28 +02002156 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002157 || get_user_ual(msg, vptr + n)
2158 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002159 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002160 return -TARGET_EFAULT;
2161
pbrook1be9e1d2006-11-19 15:26:04 +00002162 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002163 }
bellard31e31b82003-02-18 22:55:36 +00002164 break;
2165 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002166 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002167 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002168 abi_ulong msg;
2169 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002170 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002171
Ulrich Hecht98818182009-07-03 17:09:28 +02002172 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002173 || get_user_ual(msg, vptr + n)
2174 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002175 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002176 return -TARGET_EFAULT;
2177
pbrook1be9e1d2006-11-19 15:26:04 +00002178 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002179 }
bellard31e31b82003-02-18 22:55:36 +00002180 break;
2181 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002182 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002183 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002184 abi_ulong msg;
2185 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002186 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002187 abi_ulong addr;
2188 socklen_t addrlen;
2189
Ulrich Hecht98818182009-07-03 17:09:28 +02002190 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002191 || get_user_ual(msg, vptr + n)
2192 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002193 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002194 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002195 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002196 return -TARGET_EFAULT;
2197
pbrook1be9e1d2006-11-19 15:26:04 +00002198 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002199 }
bellard31e31b82003-02-18 22:55:36 +00002200 break;
2201 case SOCKOP_recvfrom:
2202 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002203 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002204 abi_ulong msg;
2205 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002206 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002207 abi_ulong addr;
2208 socklen_t addrlen;
2209
Ulrich Hecht98818182009-07-03 17:09:28 +02002210 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002211 || get_user_ual(msg, vptr + n)
2212 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002213 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002214 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002215 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002216 return -TARGET_EFAULT;
2217
pbrook1be9e1d2006-11-19 15:26:04 +00002218 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002219 }
2220 break;
2221 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002222 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002223 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002224
Ulrich Hecht98818182009-07-03 17:09:28 +02002225 if (get_user_ual(sockfd, vptr)
2226 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002227 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002228
2229 ret = get_errno(shutdown(sockfd, how));
2230 }
bellard31e31b82003-02-18 22:55:36 +00002231 break;
2232 case SOCKOP_sendmsg:
2233 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002234 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002235 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002236 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002237 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002238
Ulrich Hecht98818182009-07-03 17:09:28 +02002239 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002240 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002241 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002242 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002243
ths5fafdf22007-09-16 21:08:06 +00002244 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002245 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002246 }
2247 break;
bellard31e31b82003-02-18 22:55:36 +00002248 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002249 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002250 abi_ulong sockfd;
2251 abi_ulong level;
2252 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002253 abi_ulong optval;
2254 socklen_t optlen;
2255
Ulrich Hecht98818182009-07-03 17:09:28 +02002256 if (get_user_ual(sockfd, vptr)
2257 || get_user_ual(level, vptr + n)
2258 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002259 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002260 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002261 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002262
2263 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2264 }
2265 break;
bellard31e31b82003-02-18 22:55:36 +00002266 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002267 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002268 abi_ulong sockfd;
2269 abi_ulong level;
2270 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002271 abi_ulong optval;
2272 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002273
Ulrich Hecht98818182009-07-03 17:09:28 +02002274 if (get_user_ual(sockfd, vptr)
2275 || get_user_ual(level, vptr + n)
2276 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002277 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002278 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002279 return -TARGET_EFAULT;
2280
2281 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002282 }
2283 break;
bellard31e31b82003-02-18 22:55:36 +00002284 default:
2285 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002286 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002287 break;
2288 }
2289 return ret;
2290}
j_mayer32407102007-09-26 23:01:49 +00002291#endif
bellard31e31b82003-02-18 22:55:36 +00002292
bellard8853f862004-02-22 14:57:26 +00002293#define N_SHM_REGIONS 32
2294
2295static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002296 abi_ulong start;
2297 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002298} shm_regions[N_SHM_REGIONS];
2299
ths3eb6b042007-06-03 14:26:27 +00002300struct target_ipc_perm
2301{
blueswir1992f48a2007-10-14 16:27:31 +00002302 abi_long __key;
2303 abi_ulong uid;
2304 abi_ulong gid;
2305 abi_ulong cuid;
2306 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002307 unsigned short int mode;
2308 unsigned short int __pad1;
2309 unsigned short int __seq;
2310 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002311 abi_ulong __unused1;
2312 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002313};
2314
2315struct target_semid_ds
2316{
2317 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002318 abi_ulong sem_otime;
2319 abi_ulong __unused1;
2320 abi_ulong sem_ctime;
2321 abi_ulong __unused2;
2322 abi_ulong sem_nsems;
2323 abi_ulong __unused3;
2324 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002325};
2326
bellard579a97f2007-11-11 14:26:47 +00002327static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2328 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002329{
2330 struct target_ipc_perm *target_ip;
2331 struct target_semid_ds *target_sd;
2332
bellard579a97f2007-11-11 14:26:47 +00002333 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2334 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002335 target_ip = &(target_sd->sem_perm);
ths3eb6b042007-06-03 14:26:27 +00002336 host_ip->__key = tswapl(target_ip->__key);
2337 host_ip->uid = tswapl(target_ip->uid);
2338 host_ip->gid = tswapl(target_ip->gid);
2339 host_ip->cuid = tswapl(target_ip->cuid);
2340 host_ip->cgid = tswapl(target_ip->cgid);
2341 host_ip->mode = tswapl(target_ip->mode);
2342 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002343 return 0;
ths3eb6b042007-06-03 14:26:27 +00002344}
2345
bellard579a97f2007-11-11 14:26:47 +00002346static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2347 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002348{
2349 struct target_ipc_perm *target_ip;
2350 struct target_semid_ds *target_sd;
2351
bellard579a97f2007-11-11 14:26:47 +00002352 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2353 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002354 target_ip = &(target_sd->sem_perm);
2355 target_ip->__key = tswapl(host_ip->__key);
2356 target_ip->uid = tswapl(host_ip->uid);
2357 target_ip->gid = tswapl(host_ip->gid);
2358 target_ip->cuid = tswapl(host_ip->cuid);
2359 target_ip->cgid = tswapl(host_ip->cgid);
2360 target_ip->mode = tswapl(host_ip->mode);
2361 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002362 return 0;
ths3eb6b042007-06-03 14:26:27 +00002363}
2364
bellard579a97f2007-11-11 14:26:47 +00002365static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2366 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002367{
2368 struct target_semid_ds *target_sd;
2369
bellard579a97f2007-11-11 14:26:47 +00002370 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2371 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002372 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2373 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002374 host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
2375 host_sd->sem_otime = tswapl(target_sd->sem_otime);
2376 host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
2377 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002378 return 0;
ths3eb6b042007-06-03 14:26:27 +00002379}
2380
bellard579a97f2007-11-11 14:26:47 +00002381static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2382 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002383{
2384 struct target_semid_ds *target_sd;
2385
bellard579a97f2007-11-11 14:26:47 +00002386 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2387 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002388 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2389 return -TARGET_EFAULT;;
ths3eb6b042007-06-03 14:26:27 +00002390 target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
2391 target_sd->sem_otime = tswapl(host_sd->sem_otime);
2392 target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
2393 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002394 return 0;
ths3eb6b042007-06-03 14:26:27 +00002395}
2396
aurel32e5289082009-04-18 16:16:12 +00002397struct target_seminfo {
2398 int semmap;
2399 int semmni;
2400 int semmns;
2401 int semmnu;
2402 int semmsl;
2403 int semopm;
2404 int semume;
2405 int semusz;
2406 int semvmx;
2407 int semaem;
2408};
2409
2410static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2411 struct seminfo *host_seminfo)
2412{
2413 struct target_seminfo *target_seminfo;
2414 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2415 return -TARGET_EFAULT;
2416 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2417 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2418 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2419 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2420 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2421 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2422 __put_user(host_seminfo->semume, &target_seminfo->semume);
2423 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2424 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2425 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2426 unlock_user_struct(target_seminfo, target_addr, 1);
2427 return 0;
2428}
2429
thsfa294812007-02-02 22:05:00 +00002430union semun {
2431 int val;
ths3eb6b042007-06-03 14:26:27 +00002432 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002433 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002434 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002435};
2436
ths3eb6b042007-06-03 14:26:27 +00002437union target_semun {
2438 int val;
aurel32e5289082009-04-18 16:16:12 +00002439 abi_ulong buf;
2440 abi_ulong array;
2441 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002442};
2443
aurel32e5289082009-04-18 16:16:12 +00002444static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2445 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002446{
aurel32e5289082009-04-18 16:16:12 +00002447 int nsems;
2448 unsigned short *array;
2449 union semun semun;
2450 struct semid_ds semid_ds;
2451 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002452
aurel32e5289082009-04-18 16:16:12 +00002453 semun.buf = &semid_ds;
2454
2455 ret = semctl(semid, 0, IPC_STAT, semun);
2456 if (ret == -1)
2457 return get_errno(ret);
2458
2459 nsems = semid_ds.sem_nsems;
2460
2461 *host_array = malloc(nsems*sizeof(unsigned short));
2462 array = lock_user(VERIFY_READ, target_addr,
2463 nsems*sizeof(unsigned short), 1);
2464 if (!array)
2465 return -TARGET_EFAULT;
2466
2467 for(i=0; i<nsems; i++) {
2468 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002469 }
aurel32e5289082009-04-18 16:16:12 +00002470 unlock_user(array, target_addr, 0);
2471
bellard579a97f2007-11-11 14:26:47 +00002472 return 0;
ths3eb6b042007-06-03 14:26:27 +00002473}
2474
aurel32e5289082009-04-18 16:16:12 +00002475static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2476 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002477{
aurel32e5289082009-04-18 16:16:12 +00002478 int nsems;
2479 unsigned short *array;
2480 union semun semun;
2481 struct semid_ds semid_ds;
2482 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002483
aurel32e5289082009-04-18 16:16:12 +00002484 semun.buf = &semid_ds;
2485
2486 ret = semctl(semid, 0, IPC_STAT, semun);
2487 if (ret == -1)
2488 return get_errno(ret);
2489
2490 nsems = semid_ds.sem_nsems;
2491
2492 array = lock_user(VERIFY_WRITE, target_addr,
2493 nsems*sizeof(unsigned short), 0);
2494 if (!array)
2495 return -TARGET_EFAULT;
2496
2497 for(i=0; i<nsems; i++) {
2498 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002499 }
aurel32e5289082009-04-18 16:16:12 +00002500 free(*host_array);
2501 unlock_user(array, target_addr, 1);
2502
bellard579a97f2007-11-11 14:26:47 +00002503 return 0;
ths3eb6b042007-06-03 14:26:27 +00002504}
2505
aurel32e5289082009-04-18 16:16:12 +00002506static inline abi_long do_semctl(int semid, int semnum, int cmd,
2507 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002508{
2509 union semun arg;
2510 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302511 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002512 struct seminfo seminfo;
2513 abi_long ret = -TARGET_EINVAL;
2514 abi_long err;
2515 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002516
2517 switch( cmd ) {
2518 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002519 case SETVAL:
aurel32e5289082009-04-18 16:16:12 +00002520 arg.val = tswapl(target_su.val);
2521 ret = get_errno(semctl(semid, semnum, cmd, arg));
2522 target_su.val = tswapl(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002523 break;
2524 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002525 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002526 err = target_to_host_semarray(semid, &array, target_su.array);
2527 if (err)
2528 return err;
2529 arg.array = array;
2530 ret = get_errno(semctl(semid, semnum, cmd, arg));
2531 err = host_to_target_semarray(semid, target_su.array, &array);
2532 if (err)
2533 return err;
ths3eb6b042007-06-03 14:26:27 +00002534 break;
2535 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002536 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002537 case SEM_STAT:
2538 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2539 if (err)
2540 return err;
2541 arg.buf = &dsarg;
2542 ret = get_errno(semctl(semid, semnum, cmd, arg));
2543 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2544 if (err)
2545 return err;
ths3eb6b042007-06-03 14:26:27 +00002546 break;
aurel32e5289082009-04-18 16:16:12 +00002547 case IPC_INFO:
2548 case SEM_INFO:
2549 arg.__buf = &seminfo;
2550 ret = get_errno(semctl(semid, semnum, cmd, arg));
2551 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2552 if (err)
2553 return err;
2554 break;
2555 case IPC_RMID:
2556 case GETPID:
2557 case GETNCNT:
2558 case GETZCNT:
2559 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2560 break;
ths3eb6b042007-06-03 14:26:27 +00002561 }
2562
2563 return ret;
2564}
2565
aurel32e5289082009-04-18 16:16:12 +00002566struct target_sembuf {
2567 unsigned short sem_num;
2568 short sem_op;
2569 short sem_flg;
2570};
2571
2572static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2573 abi_ulong target_addr,
2574 unsigned nsops)
2575{
2576 struct target_sembuf *target_sembuf;
2577 int i;
2578
2579 target_sembuf = lock_user(VERIFY_READ, target_addr,
2580 nsops*sizeof(struct target_sembuf), 1);
2581 if (!target_sembuf)
2582 return -TARGET_EFAULT;
2583
2584 for(i=0; i<nsops; i++) {
2585 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2586 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2587 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2588 }
2589
2590 unlock_user(target_sembuf, target_addr, 0);
2591
2592 return 0;
2593}
2594
2595static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2596{
2597 struct sembuf sops[nsops];
2598
2599 if (target_to_host_sembuf(sops, ptr, nsops))
2600 return -TARGET_EFAULT;
2601
2602 return semop(semid, sops, nsops);
2603}
2604
ths1bc012f2007-06-03 14:27:49 +00002605struct target_msqid_ds
2606{
aurel321c54ff92008-10-13 21:08:44 +00002607 struct target_ipc_perm msg_perm;
2608 abi_ulong msg_stime;
2609#if TARGET_ABI_BITS == 32
2610 abi_ulong __unused1;
2611#endif
2612 abi_ulong msg_rtime;
2613#if TARGET_ABI_BITS == 32
2614 abi_ulong __unused2;
2615#endif
2616 abi_ulong msg_ctime;
2617#if TARGET_ABI_BITS == 32
2618 abi_ulong __unused3;
2619#endif
2620 abi_ulong __msg_cbytes;
2621 abi_ulong msg_qnum;
2622 abi_ulong msg_qbytes;
2623 abi_ulong msg_lspid;
2624 abi_ulong msg_lrpid;
2625 abi_ulong __unused4;
2626 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002627};
2628
bellard579a97f2007-11-11 14:26:47 +00002629static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2630 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002631{
2632 struct target_msqid_ds *target_md;
2633
bellard579a97f2007-11-11 14:26:47 +00002634 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2635 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002636 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2637 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002638 host_md->msg_stime = tswapl(target_md->msg_stime);
2639 host_md->msg_rtime = tswapl(target_md->msg_rtime);
2640 host_md->msg_ctime = tswapl(target_md->msg_ctime);
2641 host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
2642 host_md->msg_qnum = tswapl(target_md->msg_qnum);
2643 host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
2644 host_md->msg_lspid = tswapl(target_md->msg_lspid);
2645 host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
2646 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002647 return 0;
ths1bc012f2007-06-03 14:27:49 +00002648}
2649
bellard579a97f2007-11-11 14:26:47 +00002650static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2651 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002652{
2653 struct target_msqid_ds *target_md;
2654
bellard579a97f2007-11-11 14:26:47 +00002655 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2656 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002657 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2658 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002659 target_md->msg_stime = tswapl(host_md->msg_stime);
2660 target_md->msg_rtime = tswapl(host_md->msg_rtime);
2661 target_md->msg_ctime = tswapl(host_md->msg_ctime);
2662 target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
2663 target_md->msg_qnum = tswapl(host_md->msg_qnum);
2664 target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
2665 target_md->msg_lspid = tswapl(host_md->msg_lspid);
2666 target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
2667 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002668 return 0;
ths1bc012f2007-06-03 14:27:49 +00002669}
2670
aurel321c54ff92008-10-13 21:08:44 +00002671struct target_msginfo {
2672 int msgpool;
2673 int msgmap;
2674 int msgmax;
2675 int msgmnb;
2676 int msgmni;
2677 int msgssz;
2678 int msgtql;
2679 unsigned short int msgseg;
2680};
2681
2682static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2683 struct msginfo *host_msginfo)
2684{
2685 struct target_msginfo *target_msginfo;
2686 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2687 return -TARGET_EFAULT;
2688 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2689 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2690 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2691 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2692 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2693 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2694 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2695 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2696 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002697 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002698}
2699
2700static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002701{
2702 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002703 struct msginfo msginfo;
2704 abi_long ret = -TARGET_EINVAL;
2705
2706 cmd &= 0xff;
2707
2708 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002709 case IPC_STAT:
2710 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002711 case MSG_STAT:
2712 if (target_to_host_msqid_ds(&dsarg,ptr))
2713 return -TARGET_EFAULT;
2714 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2715 if (host_to_target_msqid_ds(ptr,&dsarg))
2716 return -TARGET_EFAULT;
2717 break;
2718 case IPC_RMID:
2719 ret = get_errno(msgctl(msgid, cmd, NULL));
2720 break;
2721 case IPC_INFO:
2722 case MSG_INFO:
2723 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2724 if (host_to_target_msginfo(ptr, &msginfo))
2725 return -TARGET_EFAULT;
2726 break;
ths1bc012f2007-06-03 14:27:49 +00002727 }
aurel321c54ff92008-10-13 21:08:44 +00002728
ths1bc012f2007-06-03 14:27:49 +00002729 return ret;
2730}
2731
2732struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002733 abi_long mtype;
2734 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002735};
2736
blueswir1992f48a2007-10-14 16:27:31 +00002737static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2738 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002739{
2740 struct target_msgbuf *target_mb;
2741 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002742 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002743
bellard579a97f2007-11-11 14:26:47 +00002744 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2745 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002746 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002747 host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
2748 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002749 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2750 free(host_mb);
2751 unlock_user_struct(target_mb, msgp, 0);
2752
2753 return ret;
2754}
2755
blueswir1992f48a2007-10-14 16:27:31 +00002756static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002757 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002758 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002759{
2760 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002761 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002762 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002763 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002764
bellard579a97f2007-11-11 14:26:47 +00002765 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2766 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002767
ths1bc012f2007-06-03 14:27:49 +00002768 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002769 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
2770
bellard579a97f2007-11-11 14:26:47 +00002771 if (ret > 0) {
2772 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2773 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2774 if (!target_mtext) {
2775 ret = -TARGET_EFAULT;
2776 goto end;
2777 }
aurel321c54ff92008-10-13 21:08:44 +00002778 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002779 unlock_user(target_mtext, target_mtext_addr, ret);
2780 }
aurel321c54ff92008-10-13 21:08:44 +00002781
ths1bc012f2007-06-03 14:27:49 +00002782 target_mb->mtype = tswapl(host_mb->mtype);
2783 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002784
bellard579a97f2007-11-11 14:26:47 +00002785end:
2786 if (target_mb)
2787 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002788 return ret;
2789}
2790
Riku Voipio88a8c982009-04-03 10:42:00 +03002791struct target_shmid_ds
2792{
2793 struct target_ipc_perm shm_perm;
2794 abi_ulong shm_segsz;
2795 abi_ulong shm_atime;
2796#if TARGET_ABI_BITS == 32
2797 abi_ulong __unused1;
2798#endif
2799 abi_ulong shm_dtime;
2800#if TARGET_ABI_BITS == 32
2801 abi_ulong __unused2;
2802#endif
2803 abi_ulong shm_ctime;
2804#if TARGET_ABI_BITS == 32
2805 abi_ulong __unused3;
2806#endif
2807 int shm_cpid;
2808 int shm_lpid;
2809 abi_ulong shm_nattch;
2810 unsigned long int __unused4;
2811 unsigned long int __unused5;
2812};
2813
2814static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2815 abi_ulong target_addr)
2816{
2817 struct target_shmid_ds *target_sd;
2818
2819 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2820 return -TARGET_EFAULT;
2821 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2822 return -TARGET_EFAULT;
2823 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2824 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2825 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2826 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2827 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2828 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2829 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2830 unlock_user_struct(target_sd, target_addr, 0);
2831 return 0;
2832}
2833
2834static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2835 struct shmid_ds *host_sd)
2836{
2837 struct target_shmid_ds *target_sd;
2838
2839 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2840 return -TARGET_EFAULT;
2841 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2842 return -TARGET_EFAULT;
2843 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2844 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2845 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2846 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2847 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2848 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2849 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2850 unlock_user_struct(target_sd, target_addr, 1);
2851 return 0;
2852}
2853
2854struct target_shminfo {
2855 abi_ulong shmmax;
2856 abi_ulong shmmin;
2857 abi_ulong shmmni;
2858 abi_ulong shmseg;
2859 abi_ulong shmall;
2860};
2861
2862static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2863 struct shminfo *host_shminfo)
2864{
2865 struct target_shminfo *target_shminfo;
2866 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2867 return -TARGET_EFAULT;
2868 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2869 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2870 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2871 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2872 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2873 unlock_user_struct(target_shminfo, target_addr, 1);
2874 return 0;
2875}
2876
2877struct target_shm_info {
2878 int used_ids;
2879 abi_ulong shm_tot;
2880 abi_ulong shm_rss;
2881 abi_ulong shm_swp;
2882 abi_ulong swap_attempts;
2883 abi_ulong swap_successes;
2884};
2885
2886static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2887 struct shm_info *host_shm_info)
2888{
2889 struct target_shm_info *target_shm_info;
2890 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2891 return -TARGET_EFAULT;
2892 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2893 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2894 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2895 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2896 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2897 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2898 unlock_user_struct(target_shm_info, target_addr, 1);
2899 return 0;
2900}
2901
2902static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2903{
2904 struct shmid_ds dsarg;
2905 struct shminfo shminfo;
2906 struct shm_info shm_info;
2907 abi_long ret = -TARGET_EINVAL;
2908
2909 cmd &= 0xff;
2910
2911 switch(cmd) {
2912 case IPC_STAT:
2913 case IPC_SET:
2914 case SHM_STAT:
2915 if (target_to_host_shmid_ds(&dsarg, buf))
2916 return -TARGET_EFAULT;
2917 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2918 if (host_to_target_shmid_ds(buf, &dsarg))
2919 return -TARGET_EFAULT;
2920 break;
2921 case IPC_INFO:
2922 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2923 if (host_to_target_shminfo(buf, &shminfo))
2924 return -TARGET_EFAULT;
2925 break;
2926 case SHM_INFO:
2927 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2928 if (host_to_target_shm_info(buf, &shm_info))
2929 return -TARGET_EFAULT;
2930 break;
2931 case IPC_RMID:
2932 case SHM_LOCK:
2933 case SHM_UNLOCK:
2934 ret = get_errno(shmctl(shmid, cmd, NULL));
2935 break;
2936 }
2937
2938 return ret;
2939}
2940
2941static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2942{
2943 abi_long raddr;
2944 void *host_raddr;
2945 struct shmid_ds shm_info;
2946 int i,ret;
2947
2948 /* find out the length of the shared memory segment */
2949 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2950 if (is_error(ret)) {
2951 /* can't get length, bail out */
2952 return ret;
2953 }
2954
2955 mmap_lock();
2956
2957 if (shmaddr)
2958 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2959 else {
2960 abi_ulong mmap_start;
2961
2962 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2963
2964 if (mmap_start == -1) {
2965 errno = ENOMEM;
2966 host_raddr = (void *)-1;
2967 } else
2968 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2969 }
2970
2971 if (host_raddr == (void *)-1) {
2972 mmap_unlock();
2973 return get_errno((long)host_raddr);
2974 }
2975 raddr=h2g((unsigned long)host_raddr);
2976
2977 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2978 PAGE_VALID | PAGE_READ |
2979 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2980
2981 for (i = 0; i < N_SHM_REGIONS; i++) {
2982 if (shm_regions[i].start == 0) {
2983 shm_regions[i].start = raddr;
2984 shm_regions[i].size = shm_info.shm_segsz;
2985 break;
2986 }
2987 }
2988
2989 mmap_unlock();
2990 return raddr;
2991
2992}
2993
2994static inline abi_long do_shmdt(abi_ulong shmaddr)
2995{
2996 int i;
2997
2998 for (i = 0; i < N_SHM_REGIONS; ++i) {
2999 if (shm_regions[i].start == shmaddr) {
3000 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003001 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003002 break;
3003 }
3004 }
3005
3006 return get_errno(shmdt(g2h(shmaddr)));
3007}
3008
aurel321c54ff92008-10-13 21:08:44 +00003009#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003010/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003011/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003012static abi_long do_ipc(unsigned int call, int first,
3013 int second, int third,
3014 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003015{
3016 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003017 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003018
3019 version = call >> 16;
3020 call &= 0xffff;
3021
3022 switch (call) {
thsfa294812007-02-02 22:05:00 +00003023 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003024 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003025 break;
3026
3027 case IPCOP_semget:
3028 ret = get_errno(semget(first, second, third));
3029 break;
3030
3031 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003032 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003033 break;
thsd96372e2007-02-02 22:05:44 +00003034
aurel321c54ff92008-10-13 21:08:44 +00003035 case IPCOP_msgget:
3036 ret = get_errno(msgget(first, second));
3037 break;
thsd96372e2007-02-02 22:05:44 +00003038
aurel321c54ff92008-10-13 21:08:44 +00003039 case IPCOP_msgsnd:
3040 ret = do_msgsnd(first, ptr, second, third);
3041 break;
thsd96372e2007-02-02 22:05:44 +00003042
aurel321c54ff92008-10-13 21:08:44 +00003043 case IPCOP_msgctl:
3044 ret = do_msgctl(first, second, ptr);
3045 break;
thsd96372e2007-02-02 22:05:44 +00003046
aurel321c54ff92008-10-13 21:08:44 +00003047 case IPCOP_msgrcv:
3048 switch (version) {
3049 case 0:
3050 {
3051 struct target_ipc_kludge {
3052 abi_long msgp;
3053 abi_long msgtyp;
3054 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003055
aurel321c54ff92008-10-13 21:08:44 +00003056 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3057 ret = -TARGET_EFAULT;
3058 break;
ths1bc012f2007-06-03 14:27:49 +00003059 }
aurel321c54ff92008-10-13 21:08:44 +00003060
3061 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3062
3063 unlock_user_struct(tmp, ptr, 0);
3064 break;
3065 }
3066 default:
3067 ret = do_msgrcv(first, ptr, second, fifth, third);
3068 }
3069 break;
thsd96372e2007-02-02 22:05:44 +00003070
bellard8853f862004-02-22 14:57:26 +00003071 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003072 switch (version) {
3073 default:
bellard5a4a8982007-11-11 17:39:18 +00003074 {
3075 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003076 raddr = do_shmat(first, ptr, second);
3077 if (is_error(raddr))
3078 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003079 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003080 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003081 break;
3082 }
3083 case 1:
3084 ret = -TARGET_EINVAL;
3085 break;
bellard5a4a8982007-11-11 17:39:18 +00003086 }
bellard8853f862004-02-22 14:57:26 +00003087 break;
3088 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003089 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003090 break;
3091
3092 case IPCOP_shmget:
3093 /* IPC_* flag values are the same on all linux platforms */
3094 ret = get_errno(shmget(first, second, third));
3095 break;
3096
3097 /* IPC_* and SHM_* command values are the same on all linux platforms */
3098 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003099 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003100 break;
3101 default:
j_mayer32407102007-09-26 23:01:49 +00003102 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003103 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003104 break;
3105 }
3106 return ret;
3107}
j_mayer32407102007-09-26 23:01:49 +00003108#endif
bellard8853f862004-02-22 14:57:26 +00003109
bellard31e31b82003-02-18 22:55:36 +00003110/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003111
Blue Swirl001faf32009-05-13 17:53:17 +00003112#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003113#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3114enum {
3115#include "syscall_types.h"
3116};
3117#undef STRUCT
3118#undef STRUCT_SPECIAL
3119
Blue Swirl001faf32009-05-13 17:53:17 +00003120#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003121#define STRUCT_SPECIAL(name)
3122#include "syscall_types.h"
3123#undef STRUCT
3124#undef STRUCT_SPECIAL
3125
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003126typedef struct IOCTLEntry IOCTLEntry;
3127
3128typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3129 int fd, abi_long cmd, abi_long arg);
3130
3131struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003132 unsigned int target_cmd;
3133 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003134 const char *name;
3135 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003136 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003137 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003138};
bellard31e31b82003-02-18 22:55:36 +00003139
3140#define IOC_R 0x0001
3141#define IOC_W 0x0002
3142#define IOC_RW (IOC_R | IOC_W)
3143
3144#define MAX_STRUCT_SIZE 4096
3145
Peter Maydelldace20d2011-01-10 13:11:24 +00003146#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003147/* So fiemap access checks don't overflow on 32 bit systems.
3148 * This is very slightly smaller than the limit imposed by
3149 * the underlying kernel.
3150 */
3151#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3152 / sizeof(struct fiemap_extent))
3153
3154static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3155 int fd, abi_long cmd, abi_long arg)
3156{
3157 /* The parameter for this ioctl is a struct fiemap followed
3158 * by an array of struct fiemap_extent whose size is set
3159 * in fiemap->fm_extent_count. The array is filled in by the
3160 * ioctl.
3161 */
3162 int target_size_in, target_size_out;
3163 struct fiemap *fm;
3164 const argtype *arg_type = ie->arg_type;
3165 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3166 void *argptr, *p;
3167 abi_long ret;
3168 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3169 uint32_t outbufsz;
3170 int free_fm = 0;
3171
3172 assert(arg_type[0] == TYPE_PTR);
3173 assert(ie->access == IOC_RW);
3174 arg_type++;
3175 target_size_in = thunk_type_size(arg_type, 0);
3176 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3177 if (!argptr) {
3178 return -TARGET_EFAULT;
3179 }
3180 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3181 unlock_user(argptr, arg, 0);
3182 fm = (struct fiemap *)buf_temp;
3183 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3184 return -TARGET_EINVAL;
3185 }
3186
3187 outbufsz = sizeof (*fm) +
3188 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3189
3190 if (outbufsz > MAX_STRUCT_SIZE) {
3191 /* We can't fit all the extents into the fixed size buffer.
3192 * Allocate one that is large enough and use it instead.
3193 */
3194 fm = malloc(outbufsz);
3195 if (!fm) {
3196 return -TARGET_ENOMEM;
3197 }
3198 memcpy(fm, buf_temp, sizeof(struct fiemap));
3199 free_fm = 1;
3200 }
3201 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3202 if (!is_error(ret)) {
3203 target_size_out = target_size_in;
3204 /* An extent_count of 0 means we were only counting the extents
3205 * so there are no structs to copy
3206 */
3207 if (fm->fm_extent_count != 0) {
3208 target_size_out += fm->fm_mapped_extents * extent_size;
3209 }
3210 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3211 if (!argptr) {
3212 ret = -TARGET_EFAULT;
3213 } else {
3214 /* Convert the struct fiemap */
3215 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3216 if (fm->fm_extent_count != 0) {
3217 p = argptr + target_size_in;
3218 /* ...and then all the struct fiemap_extents */
3219 for (i = 0; i < fm->fm_mapped_extents; i++) {
3220 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3221 THUNK_TARGET);
3222 p += extent_size;
3223 }
3224 }
3225 unlock_user(argptr, arg, target_size_out);
3226 }
3227 }
3228 if (free_fm) {
3229 free(fm);
3230 }
3231 return ret;
3232}
Peter Maydelldace20d2011-01-10 13:11:24 +00003233#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003234
Laurent Vivier059c2f22011-03-30 00:12:12 +02003235static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3236 int fd, abi_long cmd, abi_long arg)
3237{
3238 const argtype *arg_type = ie->arg_type;
3239 int target_size;
3240 void *argptr;
3241 int ret;
3242 struct ifconf *host_ifconf;
3243 uint32_t outbufsz;
3244 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3245 int target_ifreq_size;
3246 int nb_ifreq;
3247 int free_buf = 0;
3248 int i;
3249 int target_ifc_len;
3250 abi_long target_ifc_buf;
3251 int host_ifc_len;
3252 char *host_ifc_buf;
3253
3254 assert(arg_type[0] == TYPE_PTR);
3255 assert(ie->access == IOC_RW);
3256
3257 arg_type++;
3258 target_size = thunk_type_size(arg_type, 0);
3259
3260 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3261 if (!argptr)
3262 return -TARGET_EFAULT;
3263 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3264 unlock_user(argptr, arg, 0);
3265
3266 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3267 target_ifc_len = host_ifconf->ifc_len;
3268 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3269
3270 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3271 nb_ifreq = target_ifc_len / target_ifreq_size;
3272 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3273
3274 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3275 if (outbufsz > MAX_STRUCT_SIZE) {
3276 /* We can't fit all the extents into the fixed size buffer.
3277 * Allocate one that is large enough and use it instead.
3278 */
3279 host_ifconf = malloc(outbufsz);
3280 if (!host_ifconf) {
3281 return -TARGET_ENOMEM;
3282 }
3283 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3284 free_buf = 1;
3285 }
3286 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3287
3288 host_ifconf->ifc_len = host_ifc_len;
3289 host_ifconf->ifc_buf = host_ifc_buf;
3290
3291 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3292 if (!is_error(ret)) {
3293 /* convert host ifc_len to target ifc_len */
3294
3295 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3296 target_ifc_len = nb_ifreq * target_ifreq_size;
3297 host_ifconf->ifc_len = target_ifc_len;
3298
3299 /* restore target ifc_buf */
3300
3301 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3302
3303 /* copy struct ifconf to target user */
3304
3305 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3306 if (!argptr)
3307 return -TARGET_EFAULT;
3308 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3309 unlock_user(argptr, arg, target_size);
3310
3311 /* copy ifreq[] to target user */
3312
3313 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3314 for (i = 0; i < nb_ifreq ; i++) {
3315 thunk_convert(argptr + i * target_ifreq_size,
3316 host_ifc_buf + i * sizeof(struct ifreq),
3317 ifreq_arg_type, THUNK_TARGET);
3318 }
3319 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3320 }
3321
3322 if (free_buf) {
3323 free(host_ifconf);
3324 }
3325
3326 return ret;
3327}
3328
blueswir19f106a72008-10-05 10:52:52 +00003329static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003330#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003331 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3332#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3333 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003334#include "ioctls.h"
3335 { 0, 0, },
3336};
3337
pbrook53a59602006-03-25 19:31:22 +00003338/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003339/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003340static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003341{
3342 const IOCTLEntry *ie;
3343 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003344 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003345 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003346 int target_size;
3347 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003348
3349 ie = ioctl_entries;
3350 for(;;) {
3351 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003352 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003353 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003354 }
3355 if (ie->target_cmd == cmd)
3356 break;
3357 ie++;
3358 }
3359 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003360#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003361 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003362#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003363 if (ie->do_ioctl) {
3364 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3365 }
3366
bellard31e31b82003-02-18 22:55:36 +00003367 switch(arg_type[0]) {
3368 case TYPE_NULL:
3369 /* no argument */
3370 ret = get_errno(ioctl(fd, ie->host_cmd));
3371 break;
3372 case TYPE_PTRVOID:
3373 case TYPE_INT:
3374 /* int argment */
3375 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3376 break;
3377 case TYPE_PTR:
3378 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003379 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003380 switch(ie->access) {
3381 case IOC_R:
3382 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3383 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003384 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3385 if (!argptr)
3386 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003387 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3388 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003389 }
3390 break;
3391 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003392 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3393 if (!argptr)
3394 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003395 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3396 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003397 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3398 break;
3399 default:
3400 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003401 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3402 if (!argptr)
3403 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003404 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3405 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003406 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3407 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003408 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3409 if (!argptr)
3410 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003411 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3412 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003413 }
3414 break;
3415 }
3416 break;
3417 default:
j_mayer32407102007-09-26 23:01:49 +00003418 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3419 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003420 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003421 break;
3422 }
3423 return ret;
3424}
3425
blueswir1b39bc502008-10-05 10:51:10 +00003426static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003427 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3428 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3429 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3430 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3431 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3432 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3433 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3434 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3435 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3436 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3437 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3438 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3439 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3440 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3441 { 0, 0, 0, 0 }
3442};
3443
blueswir1b39bc502008-10-05 10:51:10 +00003444static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003445 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3446 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3447 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3448 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3449 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3450 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3451 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3452 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3453 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3454 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3455 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3456 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3457 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3458 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3459 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3460 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3461 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3462 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3463 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3464 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3465 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3466 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3467 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3468 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3469 { 0, 0, 0, 0 }
3470};
3471
blueswir1b39bc502008-10-05 10:51:10 +00003472static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003473 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3474 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3475 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3476 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3477 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3478 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3479 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3480 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3481 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3482 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3483 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3484 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3485 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3486 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3487 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3488 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3489 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3490 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3491 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3492 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3493 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3494 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3495 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3496 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3497 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3498 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3499 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3500 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3501 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3502 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3503 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3504 { 0, 0, 0, 0 }
3505};
3506
blueswir1b39bc502008-10-05 10:51:10 +00003507static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003508 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3509 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3510 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3511 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3512 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3513 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3514 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3515 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3516 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3517 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3518 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3519 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3520 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3521 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3522 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3523 { 0, 0, 0, 0 }
3524};
3525
3526static void target_to_host_termios (void *dst, const void *src)
3527{
3528 struct host_termios *host = dst;
3529 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003530
ths5fafdf22007-09-16 21:08:06 +00003531 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003532 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003533 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003534 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003535 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003536 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003537 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003538 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3539 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003540
Arnaud Patard44607122009-04-21 17:39:08 +03003541 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003542 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3543 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003544 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003545 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003546 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003547 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003548 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003549 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003550 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003551 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3552 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003553 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3554 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3555 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3556 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3557 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003558 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003559}
ths3b46e622007-09-17 08:09:54 +00003560
bellard31e31b82003-02-18 22:55:36 +00003561static void host_to_target_termios (void *dst, const void *src)
3562{
3563 struct target_termios *target = dst;
3564 const struct host_termios *host = src;
3565
ths5fafdf22007-09-16 21:08:06 +00003566 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003567 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003568 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003569 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003570 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003571 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003572 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003573 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3574 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003575
Arnaud Patard44607122009-04-21 17:39:08 +03003576 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003577 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3578 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3579 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3580 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3581 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3582 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3583 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3584 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3585 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3586 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3587 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3588 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3589 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3590 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3591 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3592 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3593 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3594}
3595
blueswir18e853dc2008-10-05 10:49:32 +00003596static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003597 .convert = { host_to_target_termios, target_to_host_termios },
3598 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3599 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3600};
3601
bellard5286db72003-06-05 00:57:30 +00003602static bitmask_transtbl mmap_flags_tbl[] = {
3603 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3604 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3605 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3606 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3607 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3608 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3609 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3610 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3611 { 0, 0, 0, 0 }
3612};
3613
bellard2ab83ea2003-06-15 19:56:46 +00003614#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003615
3616/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003617static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003618
bellard03acab62007-11-11 14:57:14 +00003619static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003620{
3621 int size;
pbrook53a59602006-03-25 19:31:22 +00003622 void *p;
bellard6dbad632003-03-16 18:05:05 +00003623
3624 if (!ldt_table)
3625 return 0;
3626 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3627 if (size > bytecount)
3628 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003629 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3630 if (!p)
bellard03acab62007-11-11 14:57:14 +00003631 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003632 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003633 memcpy(p, ldt_table, size);
3634 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003635 return size;
3636}
3637
3638/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003639static abi_long write_ldt(CPUX86State *env,
3640 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003641{
3642 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003643 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003644 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003645 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003646 uint32_t *lp, entry_1, entry_2;
3647
3648 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003649 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003650 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003651 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003652 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3653 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3654 ldt_info.limit = tswap32(target_ldt_info->limit);
3655 ldt_info.flags = tswap32(target_ldt_info->flags);
3656 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003657
bellard6dbad632003-03-16 18:05:05 +00003658 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003659 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003660 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;
bellard8d18e892007-11-14 15:18:40 +00003666#ifdef TARGET_ABI32
3667 lm = 0;
3668#else
3669 lm = (ldt_info.flags >> 7) & 1;
3670#endif
bellard6dbad632003-03-16 18:05:05 +00003671 if (contents == 3) {
3672 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003673 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003674 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003675 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003676 }
3677 /* allocate the LDT */
3678 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003679 env->ldt.base = target_mmap(0,
3680 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3681 PROT_READ|PROT_WRITE,
3682 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3683 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003684 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003685 memset(g2h(env->ldt.base), 0,
3686 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003687 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003688 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003689 }
3690
3691 /* NOTE: same code as Linux kernel */
3692 /* Allow LDTs to be cleared by the user. */
3693 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3694 if (oldmode ||
3695 (contents == 0 &&
3696 read_exec_only == 1 &&
3697 seg_32bit == 0 &&
3698 limit_in_pages == 0 &&
3699 seg_not_present == 1 &&
3700 useable == 0 )) {
3701 entry_1 = 0;
3702 entry_2 = 0;
3703 goto install;
3704 }
3705 }
ths3b46e622007-09-17 08:09:54 +00003706
bellard6dbad632003-03-16 18:05:05 +00003707 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3708 (ldt_info.limit & 0x0ffff);
3709 entry_2 = (ldt_info.base_addr & 0xff000000) |
3710 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3711 (ldt_info.limit & 0xf0000) |
3712 ((read_exec_only ^ 1) << 9) |
3713 (contents << 10) |
3714 ((seg_not_present ^ 1) << 15) |
3715 (seg_32bit << 22) |
3716 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003717 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003718 0x7000;
3719 if (!oldmode)
3720 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003721
bellard6dbad632003-03-16 18:05:05 +00003722 /* Install the new entry ... */
3723install:
3724 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3725 lp[0] = tswap32(entry_1);
3726 lp[1] = tswap32(entry_2);
3727 return 0;
3728}
3729
3730/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003731static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3732 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003733{
bellard03acab62007-11-11 14:57:14 +00003734 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003735
bellard6dbad632003-03-16 18:05:05 +00003736 switch (func) {
3737 case 0:
3738 ret = read_ldt(ptr, bytecount);
3739 break;
3740 case 1:
3741 ret = write_ldt(env, ptr, bytecount, 1);
3742 break;
3743 case 0x11:
3744 ret = write_ldt(env, ptr, bytecount, 0);
3745 break;
bellard03acab62007-11-11 14:57:14 +00003746 default:
3747 ret = -TARGET_ENOSYS;
3748 break;
bellard6dbad632003-03-16 18:05:05 +00003749 }
3750 return ret;
3751}
bellard1b6b0292003-03-22 17:31:38 +00003752
blueswir14583f582008-08-24 10:35:55 +00003753#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003754static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003755{
3756 uint64_t *gdt_table = g2h(env->gdt.base);
3757 struct target_modify_ldt_ldt_s ldt_info;
3758 struct target_modify_ldt_ldt_s *target_ldt_info;
3759 int seg_32bit, contents, read_exec_only, limit_in_pages;
3760 int seg_not_present, useable, lm;
3761 uint32_t *lp, entry_1, entry_2;
3762 int i;
3763
3764 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3765 if (!target_ldt_info)
3766 return -TARGET_EFAULT;
3767 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3768 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3769 ldt_info.limit = tswap32(target_ldt_info->limit);
3770 ldt_info.flags = tswap32(target_ldt_info->flags);
3771 if (ldt_info.entry_number == -1) {
3772 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3773 if (gdt_table[i] == 0) {
3774 ldt_info.entry_number = i;
3775 target_ldt_info->entry_number = tswap32(i);
3776 break;
3777 }
3778 }
3779 }
3780 unlock_user_struct(target_ldt_info, ptr, 1);
3781
3782 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
3783 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
3784 return -TARGET_EINVAL;
3785 seg_32bit = ldt_info.flags & 1;
3786 contents = (ldt_info.flags >> 1) & 3;
3787 read_exec_only = (ldt_info.flags >> 3) & 1;
3788 limit_in_pages = (ldt_info.flags >> 4) & 1;
3789 seg_not_present = (ldt_info.flags >> 5) & 1;
3790 useable = (ldt_info.flags >> 6) & 1;
3791#ifdef TARGET_ABI32
3792 lm = 0;
3793#else
3794 lm = (ldt_info.flags >> 7) & 1;
3795#endif
3796
3797 if (contents == 3) {
3798 if (seg_not_present == 0)
3799 return -TARGET_EINVAL;
3800 }
3801
3802 /* NOTE: same code as Linux kernel */
3803 /* Allow LDTs to be cleared by the user. */
3804 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3805 if ((contents == 0 &&
3806 read_exec_only == 1 &&
3807 seg_32bit == 0 &&
3808 limit_in_pages == 0 &&
3809 seg_not_present == 1 &&
3810 useable == 0 )) {
3811 entry_1 = 0;
3812 entry_2 = 0;
3813 goto install;
3814 }
3815 }
3816
3817 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3818 (ldt_info.limit & 0x0ffff);
3819 entry_2 = (ldt_info.base_addr & 0xff000000) |
3820 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3821 (ldt_info.limit & 0xf0000) |
3822 ((read_exec_only ^ 1) << 9) |
3823 (contents << 10) |
3824 ((seg_not_present ^ 1) << 15) |
3825 (seg_32bit << 22) |
3826 (limit_in_pages << 23) |
3827 (useable << 20) |
3828 (lm << 21) |
3829 0x7000;
3830
3831 /* Install the new entry ... */
3832install:
3833 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
3834 lp[0] = tswap32(entry_1);
3835 lp[1] = tswap32(entry_2);
3836 return 0;
3837}
3838
blueswir18fcd3692008-08-17 20:26:25 +00003839static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003840{
3841 struct target_modify_ldt_ldt_s *target_ldt_info;
3842 uint64_t *gdt_table = g2h(env->gdt.base);
3843 uint32_t base_addr, limit, flags;
3844 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
3845 int seg_not_present, useable, lm;
3846 uint32_t *lp, entry_1, entry_2;
3847
3848 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3849 if (!target_ldt_info)
3850 return -TARGET_EFAULT;
3851 idx = tswap32(target_ldt_info->entry_number);
3852 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
3853 idx > TARGET_GDT_ENTRY_TLS_MAX) {
3854 unlock_user_struct(target_ldt_info, ptr, 1);
3855 return -TARGET_EINVAL;
3856 }
3857 lp = (uint32_t *)(gdt_table + idx);
3858 entry_1 = tswap32(lp[0]);
3859 entry_2 = tswap32(lp[1]);
3860
3861 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
3862 contents = (entry_2 >> 10) & 3;
3863 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
3864 seg_32bit = (entry_2 >> 22) & 1;
3865 limit_in_pages = (entry_2 >> 23) & 1;
3866 useable = (entry_2 >> 20) & 1;
3867#ifdef TARGET_ABI32
3868 lm = 0;
3869#else
3870 lm = (entry_2 >> 21) & 1;
3871#endif
3872 flags = (seg_32bit << 0) | (contents << 1) |
3873 (read_exec_only << 3) | (limit_in_pages << 4) |
3874 (seg_not_present << 5) | (useable << 6) | (lm << 7);
3875 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
3876 base_addr = (entry_1 >> 16) |
3877 (entry_2 & 0xff000000) |
3878 ((entry_2 & 0xff) << 16);
3879 target_ldt_info->base_addr = tswapl(base_addr);
3880 target_ldt_info->limit = tswap32(limit);
3881 target_ldt_info->flags = tswap32(flags);
3882 unlock_user_struct(target_ldt_info, ptr, 1);
3883 return 0;
3884}
blueswir14583f582008-08-24 10:35:55 +00003885#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00003886
bellardd2fd1af2007-11-14 18:08:56 +00003887#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00003888static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00003889{
Juan Quintela1add8692011-06-16 17:37:09 +01003890 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00003891 abi_ulong val;
3892 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01003893
bellardd2fd1af2007-11-14 18:08:56 +00003894 switch(code) {
3895 case TARGET_ARCH_SET_GS:
3896 case TARGET_ARCH_SET_FS:
3897 if (code == TARGET_ARCH_SET_GS)
3898 idx = R_GS;
3899 else
3900 idx = R_FS;
3901 cpu_x86_load_seg(env, idx, 0);
3902 env->segs[idx].base = addr;
3903 break;
3904 case TARGET_ARCH_GET_GS:
3905 case TARGET_ARCH_GET_FS:
3906 if (code == TARGET_ARCH_GET_GS)
3907 idx = R_GS;
3908 else
3909 idx = R_FS;
3910 val = env->segs[idx].base;
3911 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01003912 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00003913 break;
3914 default:
3915 ret = -TARGET_EINVAL;
3916 break;
3917 }
Juan Quintela1add8692011-06-16 17:37:09 +01003918 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00003919}
3920#endif
3921
bellard2ab83ea2003-06-15 19:56:46 +00003922#endif /* defined(TARGET_I386) */
3923
Riku Voipio05098a92011-03-04 15:27:29 +02003924#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00003925
Riku Voipio05098a92011-03-04 15:27:29 +02003926#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003927
3928static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
3929typedef struct {
3930 CPUState *env;
3931 pthread_mutex_t mutex;
3932 pthread_cond_t cond;
3933 pthread_t thread;
3934 uint32_t tid;
3935 abi_ulong child_tidptr;
3936 abi_ulong parent_tidptr;
3937 sigset_t sigmask;
3938} new_thread_info;
3939
3940static void *clone_func(void *arg)
3941{
3942 new_thread_info *info = arg;
3943 CPUState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003944 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00003945
3946 env = info->env;
3947 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003948 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00003949 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07003950 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003951 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00003952 if (info->child_tidptr)
3953 put_user_u32(info->tid, info->child_tidptr);
3954 if (info->parent_tidptr)
3955 put_user_u32(info->tid, info->parent_tidptr);
3956 /* Enable signals. */
3957 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
3958 /* Signal to the parent that we're ready. */
3959 pthread_mutex_lock(&info->mutex);
3960 pthread_cond_broadcast(&info->cond);
3961 pthread_mutex_unlock(&info->mutex);
3962 /* Wait until the parent has finshed initializing the tls state. */
3963 pthread_mutex_lock(&clone_lock);
3964 pthread_mutex_unlock(&clone_lock);
3965 cpu_loop(env);
3966 /* never exits */
3967 return NULL;
3968}
3969#else
bellard1b6b0292003-03-22 17:31:38 +00003970
3971static int clone_func(void *arg)
3972{
bellard2ab83ea2003-06-15 19:56:46 +00003973 CPUState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00003974 cpu_loop(env);
3975 /* never exits */
3976 return 0;
3977}
pbrookd865bab2008-06-07 22:12:17 +00003978#endif
bellard1b6b0292003-03-22 17:31:38 +00003979
ths0da46a62007-10-20 20:23:07 +00003980/* do_fork() Must return host values and target errnos (unlike most
3981 do_*() functions). */
pbrookd865bab2008-06-07 22:12:17 +00003982static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3983 abi_ulong parent_tidptr, target_ulong newtls,
3984 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00003985{
3986 int ret;
bellard5cd43932003-03-29 16:54:36 +00003987 TaskState *ts;
bellard2ab83ea2003-06-15 19:56:46 +00003988 CPUState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003989#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003990 unsigned int nptl_flags;
3991 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02003992#else
3993 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00003994#endif
ths3b46e622007-09-17 08:09:54 +00003995
balrog436d1242008-09-21 02:39:45 +00003996 /* Emulate vfork() with fork() */
3997 if (flags & CLONE_VFORK)
3998 flags &= ~(CLONE_VFORK | CLONE_VM);
3999
bellard1b6b0292003-03-22 17:31:38 +00004000 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004001 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004002#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004003 new_thread_info info;
4004 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004005#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004006 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004007 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004008 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004009 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004010#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
4011 cpu_reset(new_env);
4012#endif
pbrook6e68e072008-05-30 17:22:15 +00004013 /* Init regs that differ from the parent. */
4014 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004015 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004016 ts->bprm = parent_ts->bprm;
4017 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004018#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004019 nptl_flags = flags;
4020 flags &= ~CLONE_NPTL_FLAGS2;
4021
pbrookc2764712009-03-07 15:24:59 +00004022 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4023 ts->child_tidptr = child_tidptr;
4024 }
4025
pbrookd865bab2008-06-07 22:12:17 +00004026 if (nptl_flags & CLONE_SETTLS)
4027 cpu_set_tls (new_env, newtls);
4028
4029 /* Grab a mutex so that thread setup appears atomic. */
4030 pthread_mutex_lock(&clone_lock);
4031
4032 memset(&info, 0, sizeof(info));
4033 pthread_mutex_init(&info.mutex, NULL);
4034 pthread_mutex_lock(&info.mutex);
4035 pthread_cond_init(&info.cond, NULL);
4036 info.env = new_env;
4037 if (nptl_flags & CLONE_CHILD_SETTID)
4038 info.child_tidptr = child_tidptr;
4039 if (nptl_flags & CLONE_PARENT_SETTID)
4040 info.parent_tidptr = parent_tidptr;
4041
4042 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004043 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4044 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004045 /* It is not safe to deliver signals until the child has finished
4046 initializing, so temporarily block all signals. */
4047 sigfillset(&sigmask);
4048 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4049
4050 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004051 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004052
4053 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4054 pthread_attr_destroy(&attr);
4055 if (ret == 0) {
4056 /* Wait for the child to initialize. */
4057 pthread_cond_wait(&info.cond, &info.mutex);
4058 ret = info.tid;
4059 if (flags & CLONE_PARENT_SETTID)
4060 put_user_u32(ret, parent_tidptr);
4061 } else {
4062 ret = -1;
4063 }
4064 pthread_mutex_unlock(&info.mutex);
4065 pthread_cond_destroy(&info.cond);
4066 pthread_mutex_destroy(&info.mutex);
4067 pthread_mutex_unlock(&clone_lock);
4068#else
4069 if (flags & CLONE_NPTL_FLAGS2)
4070 return -EINVAL;
4071 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004072 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004073#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004074 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004075#else
4076 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4077#endif
pbrookd865bab2008-06-07 22:12:17 +00004078#endif
bellard1b6b0292003-03-22 17:31:38 +00004079 } else {
4080 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004081 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004082 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004083 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004084 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004085 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004086 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004087 cpu_clone_regs(env, newsp);
4088 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004089#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004090 /* There is a race condition here. The parent process could
4091 theoretically read the TID in the child process before the child
4092 tid is set. This would require using either ptrace
4093 (not implemented) or having *_tidptr to point at a shared memory
4094 mapping. We can't repeat the spinlock hack used above because
4095 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004096 if (flags & CLONE_CHILD_SETTID)
4097 put_user_u32(gettid(), child_tidptr);
4098 if (flags & CLONE_PARENT_SETTID)
4099 put_user_u32(gettid(), parent_tidptr);
4100 ts = (TaskState *)env->opaque;
4101 if (flags & CLONE_SETTLS)
4102 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004103 if (flags & CLONE_CHILD_CLEARTID)
4104 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004105#endif
pbrookd865bab2008-06-07 22:12:17 +00004106 } else {
4107 fork_end(0);
4108 }
bellard1b6b0292003-03-22 17:31:38 +00004109 }
4110 return ret;
4111}
4112
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004113/* warning : doesn't handle linux specific flags... */
4114static int target_to_host_fcntl_cmd(int cmd)
4115{
4116 switch(cmd) {
4117 case TARGET_F_DUPFD:
4118 case TARGET_F_GETFD:
4119 case TARGET_F_SETFD:
4120 case TARGET_F_GETFL:
4121 case TARGET_F_SETFL:
4122 return cmd;
4123 case TARGET_F_GETLK:
4124 return F_GETLK;
4125 case TARGET_F_SETLK:
4126 return F_SETLK;
4127 case TARGET_F_SETLKW:
4128 return F_SETLKW;
4129 case TARGET_F_GETOWN:
4130 return F_GETOWN;
4131 case TARGET_F_SETOWN:
4132 return F_SETOWN;
4133 case TARGET_F_GETSIG:
4134 return F_GETSIG;
4135 case TARGET_F_SETSIG:
4136 return F_SETSIG;
4137#if TARGET_ABI_BITS == 32
4138 case TARGET_F_GETLK64:
4139 return F_GETLK64;
4140 case TARGET_F_SETLK64:
4141 return F_SETLK64;
4142 case TARGET_F_SETLKW64:
4143 return F_SETLKW64;
4144#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004145 case TARGET_F_SETLEASE:
4146 return F_SETLEASE;
4147 case TARGET_F_GETLEASE:
4148 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004149#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004150 case TARGET_F_DUPFD_CLOEXEC:
4151 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004152#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004153 case TARGET_F_NOTIFY:
4154 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004155 default:
4156 return -TARGET_EINVAL;
4157 }
4158 return -TARGET_EINVAL;
4159}
4160
blueswir1992f48a2007-10-14 16:27:31 +00004161static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004162{
4163 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004164 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004165 struct flock64 fl64;
4166 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004167 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004168 int host_cmd = target_to_host_fcntl_cmd(cmd);
4169
4170 if (host_cmd == -TARGET_EINVAL)
4171 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004172
bellard7775e9e2003-05-14 22:46:48 +00004173 switch(cmd) {
4174 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004175 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4176 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004177 fl.l_type = tswap16(target_fl->l_type);
4178 fl.l_whence = tswap16(target_fl->l_whence);
4179 fl.l_start = tswapl(target_fl->l_start);
4180 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004181 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004182 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004183 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004184 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004185 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4186 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004187 target_fl->l_type = tswap16(fl.l_type);
4188 target_fl->l_whence = tswap16(fl.l_whence);
4189 target_fl->l_start = tswapl(fl.l_start);
4190 target_fl->l_len = tswapl(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004191 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004192 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004193 }
4194 break;
ths3b46e622007-09-17 08:09:54 +00004195
bellard7775e9e2003-05-14 22:46:48 +00004196 case TARGET_F_SETLK:
4197 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004198 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4199 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004200 fl.l_type = tswap16(target_fl->l_type);
4201 fl.l_whence = tswap16(target_fl->l_whence);
4202 fl.l_start = tswapl(target_fl->l_start);
4203 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004204 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004205 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004206 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004207 break;
ths3b46e622007-09-17 08:09:54 +00004208
bellard7775e9e2003-05-14 22:46:48 +00004209 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004210 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4211 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004212 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4213 fl64.l_whence = tswap16(target_fl64->l_whence);
4214 fl64.l_start = tswapl(target_fl64->l_start);
4215 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004216 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004217 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004218 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004219 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004220 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4221 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004222 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4223 target_fl64->l_whence = tswap16(fl64.l_whence);
4224 target_fl64->l_start = tswapl(fl64.l_start);
4225 target_fl64->l_len = tswapl(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004226 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004227 unlock_user_struct(target_fl64, arg, 1);
4228 }
bellard9ee1fa22007-11-11 15:11:19 +00004229 break;
bellard7775e9e2003-05-14 22:46:48 +00004230 case TARGET_F_SETLK64:
4231 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004232 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4233 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004234 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4235 fl64.l_whence = tswap16(target_fl64->l_whence);
4236 fl64.l_start = tswapl(target_fl64->l_start);
4237 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004238 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004239 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004240 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004241 break;
4242
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004243 case TARGET_F_GETFL:
4244 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004245 if (ret >= 0) {
4246 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4247 }
bellardffa65c32004-01-04 23:57:22 +00004248 break;
4249
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004250 case TARGET_F_SETFL:
4251 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4252 break;
4253
4254 case TARGET_F_SETOWN:
4255 case TARGET_F_GETOWN:
4256 case TARGET_F_SETSIG:
4257 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004258 case TARGET_F_SETLEASE:
4259 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004260 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004261 break;
4262
bellard7775e9e2003-05-14 22:46:48 +00004263 default:
bellard9ee1fa22007-11-11 15:11:19 +00004264 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004265 break;
4266 }
4267 return ret;
4268}
4269
bellard67867302003-11-23 17:05:30 +00004270#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004271
bellard67867302003-11-23 17:05:30 +00004272static inline int high2lowuid(int uid)
4273{
4274 if (uid > 65535)
4275 return 65534;
4276 else
4277 return uid;
4278}
4279
4280static inline int high2lowgid(int gid)
4281{
4282 if (gid > 65535)
4283 return 65534;
4284 else
4285 return gid;
4286}
4287
4288static inline int low2highuid(int uid)
4289{
4290 if ((int16_t)uid == -1)
4291 return -1;
4292 else
4293 return uid;
4294}
4295
4296static inline int low2highgid(int gid)
4297{
4298 if ((int16_t)gid == -1)
4299 return -1;
4300 else
4301 return gid;
4302}
Riku Voipio0c866a72011-04-18 15:23:06 +03004303static inline int tswapid(int id)
4304{
4305 return tswap16(id);
4306}
4307#else /* !USE_UID16 */
4308static inline int high2lowuid(int uid)
4309{
4310 return uid;
4311}
4312static inline int high2lowgid(int gid)
4313{
4314 return gid;
4315}
4316static inline int low2highuid(int uid)
4317{
4318 return uid;
4319}
4320static inline int low2highgid(int gid)
4321{
4322 return gid;
4323}
4324static inline int tswapid(int id)
4325{
4326 return tswap32(id);
4327}
bellard67867302003-11-23 17:05:30 +00004328#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004329
bellard31e31b82003-02-18 22:55:36 +00004330void syscall_init(void)
4331{
bellard2ab83ea2003-06-15 19:56:46 +00004332 IOCTLEntry *ie;
4333 const argtype *arg_type;
4334 int size;
thsb92c47c2007-11-01 00:07:38 +00004335 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004336
Blue Swirl001faf32009-05-13 17:53:17 +00004337#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004338#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004339#include "syscall_types.h"
4340#undef STRUCT
4341#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004342
4343 /* we patch the ioctl size if necessary. We rely on the fact that
4344 no ioctl has all the bits at '1' in the size field */
4345 ie = ioctl_entries;
4346 while (ie->target_cmd != 0) {
4347 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4348 TARGET_IOC_SIZEMASK) {
4349 arg_type = ie->arg_type;
4350 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004351 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004352 ie->target_cmd);
4353 exit(1);
4354 }
4355 arg_type++;
4356 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004357 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004358 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4359 (size << TARGET_IOC_SIZESHIFT);
4360 }
thsb92c47c2007-11-01 00:07:38 +00004361
4362 /* Build target_to_host_errno_table[] table from
4363 * host_to_target_errno_table[]. */
4364 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4365 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4366
bellard2ab83ea2003-06-15 19:56:46 +00004367 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004368#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4369 (defined(__x86_64__) && defined(TARGET_X86_64))
4370 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4371 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4372 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004373 }
4374#endif
4375 ie++;
4376 }
bellard31e31b82003-02-18 22:55:36 +00004377}
bellardc573ff62004-01-04 15:51:36 +00004378
blueswir1992f48a2007-10-14 16:27:31 +00004379#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004380static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4381{
thsaf325d32008-06-10 15:29:15 +00004382#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004383 return ((uint64_t)word0 << 32) | word1;
4384#else
4385 return ((uint64_t)word1 << 32) | word0;
4386#endif
4387}
blueswir1992f48a2007-10-14 16:27:31 +00004388#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004389static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4390{
4391 return word0;
4392}
blueswir1992f48a2007-10-14 16:27:31 +00004393#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004394
4395#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004396static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4397 abi_long arg2,
4398 abi_long arg3,
4399 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004400{
Riku Voipio48e515d2011-07-12 15:40:51 +03004401 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004402 arg2 = arg3;
4403 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004404 }
pbrookce4defa2006-02-09 16:49:55 +00004405 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4406}
4407#endif
4408
4409#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004410static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4411 abi_long arg2,
4412 abi_long arg3,
4413 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004414{
Riku Voipio48e515d2011-07-12 15:40:51 +03004415 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004416 arg2 = arg3;
4417 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004418 }
pbrookce4defa2006-02-09 16:49:55 +00004419 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4420}
4421#endif
4422
bellard579a97f2007-11-11 14:26:47 +00004423static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4424 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004425{
4426 struct target_timespec *target_ts;
4427
bellard579a97f2007-11-11 14:26:47 +00004428 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4429 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004430 host_ts->tv_sec = tswapl(target_ts->tv_sec);
4431 host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
4432 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004433 return 0;
pbrook53a59602006-03-25 19:31:22 +00004434}
4435
bellard579a97f2007-11-11 14:26:47 +00004436static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4437 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004438{
4439 struct target_timespec *target_ts;
4440
bellard579a97f2007-11-11 14:26:47 +00004441 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4442 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004443 target_ts->tv_sec = tswapl(host_ts->tv_sec);
4444 target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
4445 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004446 return 0;
pbrook53a59602006-03-25 19:31:22 +00004447}
4448
aurel329d33b762009-04-08 23:07:05 +00004449#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004450static inline abi_long host_to_target_stat64(void *cpu_env,
4451 abi_ulong target_addr,
4452 struct stat *host_st)
4453{
4454#ifdef TARGET_ARM
4455 if (((CPUARMState *)cpu_env)->eabi) {
4456 struct target_eabi_stat64 *target_st;
4457
4458 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4459 return -TARGET_EFAULT;
4460 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4461 __put_user(host_st->st_dev, &target_st->st_dev);
4462 __put_user(host_st->st_ino, &target_st->st_ino);
4463#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4464 __put_user(host_st->st_ino, &target_st->__st_ino);
4465#endif
4466 __put_user(host_st->st_mode, &target_st->st_mode);
4467 __put_user(host_st->st_nlink, &target_st->st_nlink);
4468 __put_user(host_st->st_uid, &target_st->st_uid);
4469 __put_user(host_st->st_gid, &target_st->st_gid);
4470 __put_user(host_st->st_rdev, &target_st->st_rdev);
4471 __put_user(host_st->st_size, &target_st->st_size);
4472 __put_user(host_st->st_blksize, &target_st->st_blksize);
4473 __put_user(host_st->st_blocks, &target_st->st_blocks);
4474 __put_user(host_st->st_atime, &target_st->target_st_atime);
4475 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4476 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4477 unlock_user_struct(target_st, target_addr, 1);
4478 } else
4479#endif
4480 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004481#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004482 struct target_stat *target_st;
4483#else
balrog6a24a772008-09-20 02:23:36 +00004484 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004485#endif
balrog6a24a772008-09-20 02:23:36 +00004486
4487 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4488 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004489 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004490 __put_user(host_st->st_dev, &target_st->st_dev);
4491 __put_user(host_st->st_ino, &target_st->st_ino);
4492#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4493 __put_user(host_st->st_ino, &target_st->__st_ino);
4494#endif
4495 __put_user(host_st->st_mode, &target_st->st_mode);
4496 __put_user(host_st->st_nlink, &target_st->st_nlink);
4497 __put_user(host_st->st_uid, &target_st->st_uid);
4498 __put_user(host_st->st_gid, &target_st->st_gid);
4499 __put_user(host_st->st_rdev, &target_st->st_rdev);
4500 /* XXX: better use of kernel struct */
4501 __put_user(host_st->st_size, &target_st->st_size);
4502 __put_user(host_st->st_blksize, &target_st->st_blksize);
4503 __put_user(host_st->st_blocks, &target_st->st_blocks);
4504 __put_user(host_st->st_atime, &target_st->target_st_atime);
4505 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4506 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4507 unlock_user_struct(target_st, target_addr, 1);
4508 }
4509
4510 return 0;
4511}
4512#endif
4513
Juan Quintela2f7bb872009-07-27 16:13:24 +02004514#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004515/* ??? Using host futex calls even when target atomic operations
4516 are not really atomic probably breaks things. However implementing
4517 futexes locally would make futexes shared between multiple processes
4518 tricky. However they're probably useless because guest atomic
4519 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004520static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4521 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004522{
4523 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004524 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004525
4526 /* ??? We assume FUTEX_* constants are the same on both host
4527 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004528#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004529 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004530#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004531 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004532#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004533 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004534 case FUTEX_WAIT:
4535 if (timeout) {
4536 pts = &ts;
4537 target_to_host_timespec(pts, timeout);
4538 } else {
4539 pts = NULL;
4540 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004541 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004542 pts, NULL, 0));
4543 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004544 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004545 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004546 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004547 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004548 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004549 case FUTEX_WAKE_OP:
4550 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4551 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4552 But the prototype takes a `struct timespec *'; insert casts
4553 to satisfy the compiler. We do not need to tswap TIMEOUT
4554 since it's not compared to guest memory. */
4555 pts = (struct timespec *)(uintptr_t) timeout;
4556 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4557 g2h(uaddr2),
4558 (base_op == FUTEX_CMP_REQUEUE
4559 ? tswap32(val3)
4560 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004561 default:
4562 return -TARGET_ENOSYS;
4563 }
4564}
4565#endif
4566
pbrook1d9d8b52009-04-16 15:17:02 +00004567/* Map host to target signal numbers for the wait family of syscalls.
4568 Assume all other status bits are the same. */
4569static int host_to_target_waitstatus(int status)
4570{
4571 if (WIFSIGNALED(status)) {
4572 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4573 }
4574 if (WIFSTOPPED(status)) {
4575 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4576 | (status & 0xff);
4577 }
4578 return status;
4579}
4580
pbrooka745ec62008-05-06 15:36:17 +00004581int get_osversion(void)
4582{
4583 static int osversion;
4584 struct new_utsname buf;
4585 const char *s;
4586 int i, n, tmp;
4587 if (osversion)
4588 return osversion;
4589 if (qemu_uname_release && *qemu_uname_release) {
4590 s = qemu_uname_release;
4591 } else {
4592 if (sys_uname(&buf))
4593 return 0;
4594 s = buf.release;
4595 }
4596 tmp = 0;
4597 for (i = 0; i < 3; i++) {
4598 n = 0;
4599 while (*s >= '0' && *s <= '9') {
4600 n *= 10;
4601 n += *s - '0';
4602 s++;
4603 }
4604 tmp = (tmp << 8) + n;
4605 if (*s == '.')
4606 s++;
4607 }
4608 osversion = tmp;
4609 return osversion;
4610}
4611
ths0da46a62007-10-20 20:23:07 +00004612/* do_syscall() should always have a single exit point at the end so
4613 that actions, such as logging of syscall results, can be performed.
4614 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004615abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4616 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004617 abi_long arg5, abi_long arg6, abi_long arg7,
4618 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00004619{
blueswir1992f48a2007-10-14 16:27:31 +00004620 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004621 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004622 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004623 void *p;
ths3b46e622007-09-17 08:09:54 +00004624
bellard72f03902003-02-18 23:33:18 +00004625#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00004626 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00004627#endif
thsb92c47c2007-11-01 00:07:38 +00004628 if(do_strace)
4629 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
4630
bellard31e31b82003-02-18 22:55:36 +00004631 switch(num) {
4632 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02004633#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00004634 /* In old applications this may be used to implement _exit(2).
4635 However in threaded applictions it is used for thread termination,
4636 and _exit_group is used for application termination.
4637 Do thread termination if we have more then one thread. */
4638 /* FIXME: This probably breaks if a signal arrives. We should probably
4639 be disabling signals. */
4640 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004641 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00004642 CPUState **lastp;
4643 CPUState *p;
4644
4645 cpu_list_lock();
4646 lastp = &first_cpu;
4647 p = first_cpu;
4648 while (p && p != (CPUState *)cpu_env) {
4649 lastp = &p->next_cpu;
4650 p = p->next_cpu;
4651 }
4652 /* If we didn't find the CPU for this thread then something is
4653 horribly wrong. */
4654 if (!p)
4655 abort();
4656 /* Remove the CPU from the list. */
4657 *lastp = p->next_cpu;
4658 cpu_list_unlock();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004659 ts = ((CPUState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00004660 if (ts->child_tidptr) {
4661 put_user_u32(0, ts->child_tidptr);
4662 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
4663 NULL, NULL, 0);
4664 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004665 thread_env = NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05004666 g_free(cpu_env);
4667 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00004668 pthread_exit(NULL);
4669 }
4670#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02004671#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00004672 _mcleanup();
4673#endif
bellarde9009672005-04-26 20:42:36 +00004674 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00004675 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00004676 ret = 0; /* avoid warning */
4677 break;
4678 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00004679 if (arg3 == 0)
4680 ret = 0;
4681 else {
4682 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
4683 goto efault;
4684 ret = get_errno(read(arg1, p, arg3));
4685 unlock_user(p, arg2, ret);
4686 }
bellard31e31b82003-02-18 22:55:36 +00004687 break;
4688 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00004689 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
4690 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004691 ret = get_errno(write(arg1, p, arg3));
4692 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00004693 break;
4694 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00004695 if (!(p = lock_user_string(arg1)))
4696 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004697 ret = get_errno(open(path(p),
bellardffa65c32004-01-04 23:57:22 +00004698 target_to_host_bitmask(arg2, fcntl_flags_tbl),
4699 arg3));
pbrook53a59602006-03-25 19:31:22 +00004700 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004701 break;
ths82424832007-09-24 09:21:55 +00004702#if defined(TARGET_NR_openat) && defined(__NR_openat)
4703 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00004704 if (!(p = lock_user_string(arg2)))
4705 goto efault;
4706 ret = get_errno(sys_openat(arg1,
4707 path(p),
4708 target_to_host_bitmask(arg3, fcntl_flags_tbl),
4709 arg4));
4710 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00004711 break;
4712#endif
bellard31e31b82003-02-18 22:55:36 +00004713 case TARGET_NR_close:
4714 ret = get_errno(close(arg1));
4715 break;
4716 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00004717 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00004718 break;
4719 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00004720 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00004721 break;
thse5febef2007-04-01 18:31:35 +00004722#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00004723 case TARGET_NR_waitpid:
4724 {
pbrook53a59602006-03-25 19:31:22 +00004725 int status;
4726 ret = get_errno(waitpid(arg1, &status, arg3));
bellard2f619692007-11-16 10:46:05 +00004727 if (!is_error(ret) && arg2
pbrook1d9d8b52009-04-16 15:17:02 +00004728 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00004729 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004730 }
4731 break;
thse5febef2007-04-01 18:31:35 +00004732#endif
pbrookf0cbb612008-05-30 18:20:05 +00004733#ifdef TARGET_NR_waitid
4734 case TARGET_NR_waitid:
4735 {
4736 siginfo_t info;
4737 info.si_pid = 0;
4738 ret = get_errno(waitid(arg1, arg2, &info, arg4));
4739 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004740 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00004741 goto efault;
4742 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05004743 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00004744 }
4745 }
4746 break;
4747#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004748#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004749 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00004750 if (!(p = lock_user_string(arg1)))
4751 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004752 ret = get_errno(creat(p, arg2));
4753 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004754 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004755#endif
bellard31e31b82003-02-18 22:55:36 +00004756 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00004757 {
4758 void * p2;
4759 p = lock_user_string(arg1);
4760 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004761 if (!p || !p2)
4762 ret = -TARGET_EFAULT;
4763 else
4764 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004765 unlock_user(p2, arg2, 0);
4766 unlock_user(p, arg1, 0);
4767 }
bellard31e31b82003-02-18 22:55:36 +00004768 break;
ths64f0ce42007-09-24 09:25:06 +00004769#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
4770 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00004771 {
4772 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00004773 if (!arg2 || !arg4)
4774 goto efault;
ths64f0ce42007-09-24 09:25:06 +00004775 p = lock_user_string(arg2);
4776 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004777 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004778 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00004779 else
4780 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00004781 unlock_user(p, arg2, 0);
4782 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00004783 }
4784 break;
4785#endif
bellard31e31b82003-02-18 22:55:36 +00004786 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00004787 if (!(p = lock_user_string(arg1)))
4788 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004789 ret = get_errno(unlink(p));
4790 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004791 break;
ths8170f562007-09-24 09:24:11 +00004792#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
4793 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00004794 if (!(p = lock_user_string(arg2)))
4795 goto efault;
4796 ret = get_errno(sys_unlinkat(arg1, p, arg3));
4797 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00004798 break;
balrogb7d35e62007-12-12 00:40:24 +00004799#endif
bellard31e31b82003-02-18 22:55:36 +00004800 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00004801 {
4802 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00004803 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00004804 abi_ulong gp;
4805 abi_ulong guest_argp;
4806 abi_ulong guest_envp;
4807 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00004808 char **q;
4809
bellardf7341ff2003-03-30 21:00:25 +00004810 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00004811 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00004812 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004813 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004814 goto efault;
ths03aa1972007-12-02 06:28:08 +00004815 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004816 break;
bellard7854b052003-03-29 17:22:23 +00004817 argc++;
bellard2f619692007-11-16 10:46:05 +00004818 }
bellardf7341ff2003-03-30 21:00:25 +00004819 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00004820 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00004821 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004822 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004823 goto efault;
ths03aa1972007-12-02 06:28:08 +00004824 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004825 break;
bellard7854b052003-03-29 17:22:23 +00004826 envc++;
bellard2f619692007-11-16 10:46:05 +00004827 }
bellard7854b052003-03-29 17:22:23 +00004828
bellardf7341ff2003-03-30 21:00:25 +00004829 argp = alloca((argc + 1) * sizeof(void *));
4830 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00004831
pbrookda94d262008-05-30 18:24:00 +00004832 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004833 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004834 if (get_user_ual(addr, gp))
4835 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004836 if (!addr)
4837 break;
bellard2f619692007-11-16 10:46:05 +00004838 if (!(*q = lock_user_string(addr)))
4839 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004840 }
bellardf7341ff2003-03-30 21:00:25 +00004841 *q = NULL;
4842
pbrookda94d262008-05-30 18:24:00 +00004843 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004844 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004845 if (get_user_ual(addr, gp))
4846 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004847 if (!addr)
4848 break;
bellard2f619692007-11-16 10:46:05 +00004849 if (!(*q = lock_user_string(addr)))
4850 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004851 }
bellardf7341ff2003-03-30 21:00:25 +00004852 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00004853
bellard2f619692007-11-16 10:46:05 +00004854 if (!(p = lock_user_string(arg1)))
4855 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004856 ret = get_errno(execve(p, argp, envp));
4857 unlock_user(p, arg1, 0);
4858
bellard2f619692007-11-16 10:46:05 +00004859 goto execve_end;
4860
4861 execve_efault:
4862 ret = -TARGET_EFAULT;
4863
4864 execve_end:
pbrook53a59602006-03-25 19:31:22 +00004865 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004866 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004867 if (get_user_ual(addr, gp)
4868 || !addr)
4869 break;
pbrook53a59602006-03-25 19:31:22 +00004870 unlock_user(*q, addr, 0);
4871 }
4872 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004873 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004874 if (get_user_ual(addr, gp)
4875 || !addr)
4876 break;
pbrook53a59602006-03-25 19:31:22 +00004877 unlock_user(*q, addr, 0);
4878 }
bellard7854b052003-03-29 17:22:23 +00004879 }
bellard31e31b82003-02-18 22:55:36 +00004880 break;
4881 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00004882 if (!(p = lock_user_string(arg1)))
4883 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004884 ret = get_errno(chdir(p));
4885 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004886 break;
bellarda315a142005-01-30 22:59:18 +00004887#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00004888 case TARGET_NR_time:
4889 {
pbrook53a59602006-03-25 19:31:22 +00004890 time_t host_time;
4891 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00004892 if (!is_error(ret)
4893 && arg1
4894 && put_user_sal(host_time, arg1))
4895 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004896 }
4897 break;
bellarda315a142005-01-30 22:59:18 +00004898#endif
bellard31e31b82003-02-18 22:55:36 +00004899 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00004900 if (!(p = lock_user_string(arg1)))
4901 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004902 ret = get_errno(mknod(p, arg2, arg3));
4903 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004904 break;
ths75ac37a2007-09-24 09:23:05 +00004905#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
4906 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00004907 if (!(p = lock_user_string(arg2)))
4908 goto efault;
4909 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
4910 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00004911 break;
4912#endif
bellard31e31b82003-02-18 22:55:36 +00004913 case TARGET_NR_chmod:
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(chmod(p, arg2));
4917 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004918 break;
bellardebc05482003-09-30 21:08:41 +00004919#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00004920 case TARGET_NR_break:
4921 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004922#endif
4923#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00004924 case TARGET_NR_oldstat:
4925 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004926#endif
bellard31e31b82003-02-18 22:55:36 +00004927 case TARGET_NR_lseek:
4928 ret = get_errno(lseek(arg1, arg2, arg3));
4929 break;
Richard Henderson92317332010-05-03 10:07:53 -07004930#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
4931 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00004932 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07004933 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00004934 ret = get_errno(getpid());
4935 break;
Richard Henderson92317332010-05-03 10:07:53 -07004936#endif
4937#ifdef TARGET_NR_getpid
4938 case TARGET_NR_getpid:
4939 ret = get_errno(getpid());
4940 break;
4941#endif
bellard31e31b82003-02-18 22:55:36 +00004942 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00004943 {
4944 /* need to look at the data field */
4945 void *p2, *p3;
4946 p = lock_user_string(arg1);
4947 p2 = lock_user_string(arg2);
4948 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00004949 if (!p || !p2 || !p3)
4950 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004951 else {
bellard579a97f2007-11-11 14:26:47 +00004952 /* FIXME - arg5 should be locked, but it isn't clear how to
4953 * do that since it's not guaranteed to be a NULL-terminated
4954 * string.
4955 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004956 if ( ! arg5 )
4957 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
4958 else
4959 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
4960 }
bellard579a97f2007-11-11 14:26:47 +00004961 unlock_user(p, arg1, 0);
4962 unlock_user(p2, arg2, 0);
4963 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00004964 break;
4965 }
thse5febef2007-04-01 18:31:35 +00004966#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00004967 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00004968 if (!(p = lock_user_string(arg1)))
4969 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004970 ret = get_errno(umount(p));
4971 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004972 break;
thse5febef2007-04-01 18:31:35 +00004973#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004974#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004975 case TARGET_NR_stime:
4976 {
pbrook53a59602006-03-25 19:31:22 +00004977 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00004978 if (get_user_sal(host_time, arg1))
4979 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004980 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00004981 }
4982 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004983#endif
bellard31e31b82003-02-18 22:55:36 +00004984 case TARGET_NR_ptrace:
4985 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00004986#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004987 case TARGET_NR_alarm:
4988 ret = alarm(arg1);
4989 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004990#endif
bellardebc05482003-09-30 21:08:41 +00004991#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00004992 case TARGET_NR_oldfstat:
4993 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004994#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004995#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004996 case TARGET_NR_pause:
4997 ret = get_errno(pause());
4998 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004999#endif
thse5febef2007-04-01 18:31:35 +00005000#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005001 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005002 {
pbrook53a59602006-03-25 19:31:22 +00005003 struct utimbuf tbuf, *host_tbuf;
5004 struct target_utimbuf *target_tbuf;
5005 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005006 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5007 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005008 tbuf.actime = tswapl(target_tbuf->actime);
5009 tbuf.modtime = tswapl(target_tbuf->modtime);
5010 unlock_user_struct(target_tbuf, arg2, 0);
5011 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005012 } else {
pbrook53a59602006-03-25 19:31:22 +00005013 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005014 }
bellard579a97f2007-11-11 14:26:47 +00005015 if (!(p = lock_user_string(arg1)))
5016 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005017 ret = get_errno(utime(p, host_tbuf));
5018 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005019 }
5020 break;
thse5febef2007-04-01 18:31:35 +00005021#endif
bellard978a66f2004-12-06 22:58:05 +00005022 case TARGET_NR_utimes:
5023 {
bellard978a66f2004-12-06 22:58:05 +00005024 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005025 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005026 if (copy_from_user_timeval(&tv[0], arg2)
5027 || copy_from_user_timeval(&tv[1],
5028 arg2 + sizeof(struct target_timeval)))
5029 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005030 tvp = tv;
5031 } else {
5032 tvp = NULL;
5033 }
bellard579a97f2007-11-11 14:26:47 +00005034 if (!(p = lock_user_string(arg1)))
5035 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005036 ret = get_errno(utimes(p, tvp));
5037 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005038 }
5039 break;
balrogac8a6552008-09-20 02:25:39 +00005040#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5041 case TARGET_NR_futimesat:
5042 {
5043 struct timeval *tvp, tv[2];
5044 if (arg3) {
5045 if (copy_from_user_timeval(&tv[0], arg3)
5046 || copy_from_user_timeval(&tv[1],
5047 arg3 + sizeof(struct target_timeval)))
5048 goto efault;
5049 tvp = tv;
5050 } else {
5051 tvp = NULL;
5052 }
5053 if (!(p = lock_user_string(arg2)))
5054 goto efault;
5055 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5056 unlock_user(p, arg2, 0);
5057 }
5058 break;
5059#endif
bellardebc05482003-09-30 21:08:41 +00005060#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005061 case TARGET_NR_stty:
5062 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005063#endif
5064#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005065 case TARGET_NR_gtty:
5066 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005067#endif
bellard31e31b82003-02-18 22:55:36 +00005068 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005069 if (!(p = lock_user_string(arg1)))
5070 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005071 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005072 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005073 break;
ths92a34c12007-09-24 09:27:49 +00005074#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5075 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005076 if (!(p = lock_user_string(arg2)))
5077 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005078 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005079 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005080 break;
5081#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005082#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005083 case TARGET_NR_nice:
5084 ret = get_errno(nice(arg1));
5085 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005086#endif
bellardebc05482003-09-30 21:08:41 +00005087#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005088 case TARGET_NR_ftime:
5089 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005090#endif
bellard31e31b82003-02-18 22:55:36 +00005091 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005092 sync();
5093 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005094 break;
5095 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005096 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005097 break;
5098 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005099 {
5100 void *p2;
5101 p = lock_user_string(arg1);
5102 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005103 if (!p || !p2)
5104 ret = -TARGET_EFAULT;
5105 else
5106 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005107 unlock_user(p2, arg2, 0);
5108 unlock_user(p, arg1, 0);
5109 }
bellard31e31b82003-02-18 22:55:36 +00005110 break;
ths722183f2007-09-24 09:24:37 +00005111#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5112 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005113 {
bellard579a97f2007-11-11 14:26:47 +00005114 void *p2;
ths722183f2007-09-24 09:24:37 +00005115 p = lock_user_string(arg2);
5116 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005117 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005118 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005119 else
5120 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005121 unlock_user(p2, arg4, 0);
5122 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005123 }
5124 break;
5125#endif
bellard31e31b82003-02-18 22:55:36 +00005126 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005127 if (!(p = lock_user_string(arg1)))
5128 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005129 ret = get_errno(mkdir(p, arg2));
5130 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005131 break;
ths4472ad02007-09-24 09:22:32 +00005132#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5133 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005134 if (!(p = lock_user_string(arg2)))
5135 goto efault;
5136 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5137 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005138 break;
5139#endif
bellard31e31b82003-02-18 22:55:36 +00005140 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005141 if (!(p = lock_user_string(arg1)))
5142 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005143 ret = get_errno(rmdir(p));
5144 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005145 break;
5146 case TARGET_NR_dup:
5147 ret = get_errno(dup(arg1));
5148 break;
5149 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005150 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005151 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005152#ifdef TARGET_NR_pipe2
5153 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005154 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005155 break;
5156#endif
bellard31e31b82003-02-18 22:55:36 +00005157 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005158 {
pbrook53a59602006-03-25 19:31:22 +00005159 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005160 struct tms tms;
5161 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005162 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005163 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5164 if (!tmsp)
5165 goto efault;
bellardc596ed12003-07-13 17:32:31 +00005166 tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
5167 tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
5168 tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
5169 tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005170 }
bellardc596ed12003-07-13 17:32:31 +00005171 if (!is_error(ret))
5172 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005173 }
5174 break;
bellardebc05482003-09-30 21:08:41 +00005175#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005176 case TARGET_NR_prof:
5177 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005178#endif
thse5febef2007-04-01 18:31:35 +00005179#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005180 case TARGET_NR_signal:
5181 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005182#endif
bellard31e31b82003-02-18 22:55:36 +00005183 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005184 if (arg1 == 0) {
5185 ret = get_errno(acct(NULL));
5186 } else {
5187 if (!(p = lock_user_string(arg1)))
5188 goto efault;
5189 ret = get_errno(acct(path(p)));
5190 unlock_user(p, arg1, 0);
5191 }
pbrook24836682006-04-16 14:14:53 +00005192 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005193#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005194 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005195 if (!(p = lock_user_string(arg1)))
5196 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005197 ret = get_errno(umount2(p, arg2));
5198 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005199 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005200#endif
bellardebc05482003-09-30 21:08:41 +00005201#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005202 case TARGET_NR_lock:
5203 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005204#endif
bellard31e31b82003-02-18 22:55:36 +00005205 case TARGET_NR_ioctl:
5206 ret = do_ioctl(arg1, arg2, arg3);
5207 break;
5208 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005209 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005210 break;
bellardebc05482003-09-30 21:08:41 +00005211#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005212 case TARGET_NR_mpx:
5213 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005214#endif
bellard31e31b82003-02-18 22:55:36 +00005215 case TARGET_NR_setpgid:
5216 ret = get_errno(setpgid(arg1, arg2));
5217 break;
bellardebc05482003-09-30 21:08:41 +00005218#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005219 case TARGET_NR_ulimit:
5220 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005221#endif
5222#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005223 case TARGET_NR_oldolduname:
5224 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005225#endif
bellard31e31b82003-02-18 22:55:36 +00005226 case TARGET_NR_umask:
5227 ret = get_errno(umask(arg1));
5228 break;
5229 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005230 if (!(p = lock_user_string(arg1)))
5231 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005232 ret = get_errno(chroot(p));
5233 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005234 break;
5235 case TARGET_NR_ustat:
5236 goto unimplemented;
5237 case TARGET_NR_dup2:
5238 ret = get_errno(dup2(arg1, arg2));
5239 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005240#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5241 case TARGET_NR_dup3:
5242 ret = get_errno(dup3(arg1, arg2, arg3));
5243 break;
5244#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005245#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005246 case TARGET_NR_getppid:
5247 ret = get_errno(getppid());
5248 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005249#endif
bellard31e31b82003-02-18 22:55:36 +00005250 case TARGET_NR_getpgrp:
5251 ret = get_errno(getpgrp());
5252 break;
5253 case TARGET_NR_setsid:
5254 ret = get_errno(setsid());
5255 break;
thse5febef2007-04-01 18:31:35 +00005256#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005257 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005258 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005259#if defined(TARGET_ALPHA)
5260 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005261 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005262 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005263 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5264 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005265 act._sa_handler = old_act->_sa_handler;
5266 target_siginitset(&act.sa_mask, old_act->sa_mask);
5267 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005268 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005269 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005270 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005271 }
5272 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005273 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005274 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5275 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005276 old_act->_sa_handler = oact._sa_handler;
5277 old_act->sa_mask = oact.sa_mask.sig[0];
5278 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005279 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005280 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005281#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005282 struct target_sigaction act, oact, *pact, *old_act;
5283
5284 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005285 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5286 goto efault;
bellard106ec872006-06-27 21:08:10 +00005287 act._sa_handler = old_act->_sa_handler;
5288 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5289 act.sa_flags = old_act->sa_flags;
5290 unlock_user_struct(old_act, arg2, 0);
5291 pact = &act;
5292 } else {
5293 pact = NULL;
5294 }
5295
5296 ret = get_errno(do_sigaction(arg1, pact, &oact));
5297
5298 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005299 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5300 goto efault;
bellard106ec872006-06-27 21:08:10 +00005301 old_act->_sa_handler = oact._sa_handler;
5302 old_act->sa_flags = oact.sa_flags;
5303 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5304 old_act->sa_mask.sig[1] = 0;
5305 old_act->sa_mask.sig[2] = 0;
5306 old_act->sa_mask.sig[3] = 0;
5307 unlock_user_struct(old_act, arg3, 1);
5308 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005309#else
5310 struct target_old_sigaction *old_act;
5311 struct target_sigaction act, oact, *pact;
5312 if (arg2) {
5313 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5314 goto efault;
5315 act._sa_handler = old_act->_sa_handler;
5316 target_siginitset(&act.sa_mask, old_act->sa_mask);
5317 act.sa_flags = old_act->sa_flags;
5318 act.sa_restorer = old_act->sa_restorer;
5319 unlock_user_struct(old_act, arg2, 0);
5320 pact = &act;
5321 } else {
5322 pact = NULL;
5323 }
5324 ret = get_errno(do_sigaction(arg1, pact, &oact));
5325 if (!is_error(ret) && arg3) {
5326 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5327 goto efault;
5328 old_act->_sa_handler = oact._sa_handler;
5329 old_act->sa_mask = oact.sa_mask.sig[0];
5330 old_act->sa_flags = oact.sa_flags;
5331 old_act->sa_restorer = oact.sa_restorer;
5332 unlock_user_struct(old_act, arg3, 1);
5333 }
ths388bb212007-05-13 13:58:00 +00005334#endif
bellard31e31b82003-02-18 22:55:36 +00005335 }
5336 break;
thse5febef2007-04-01 18:31:35 +00005337#endif
bellard66fb9762003-03-23 01:06:05 +00005338 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005339 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005340#if defined(TARGET_ALPHA)
5341 struct target_sigaction act, oact, *pact = 0;
5342 struct target_rt_sigaction *rt_act;
5343 /* ??? arg4 == sizeof(sigset_t). */
5344 if (arg2) {
5345 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5346 goto efault;
5347 act._sa_handler = rt_act->_sa_handler;
5348 act.sa_mask = rt_act->sa_mask;
5349 act.sa_flags = rt_act->sa_flags;
5350 act.sa_restorer = arg5;
5351 unlock_user_struct(rt_act, arg2, 0);
5352 pact = &act;
5353 }
5354 ret = get_errno(do_sigaction(arg1, pact, &oact));
5355 if (!is_error(ret) && arg3) {
5356 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5357 goto efault;
5358 rt_act->_sa_handler = oact._sa_handler;
5359 rt_act->sa_mask = oact.sa_mask;
5360 rt_act->sa_flags = oact.sa_flags;
5361 unlock_user_struct(rt_act, arg3, 1);
5362 }
5363#else
pbrook53a59602006-03-25 19:31:22 +00005364 struct target_sigaction *act;
5365 struct target_sigaction *oact;
5366
bellard579a97f2007-11-11 14:26:47 +00005367 if (arg2) {
5368 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5369 goto efault;
5370 } else
pbrook53a59602006-03-25 19:31:22 +00005371 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005372 if (arg3) {
5373 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5374 ret = -TARGET_EFAULT;
5375 goto rt_sigaction_fail;
5376 }
5377 } else
pbrook53a59602006-03-25 19:31:22 +00005378 oact = NULL;
5379 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005380 rt_sigaction_fail:
5381 if (act)
pbrook53a59602006-03-25 19:31:22 +00005382 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005383 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005384 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005385#endif
pbrook53a59602006-03-25 19:31:22 +00005386 }
bellard66fb9762003-03-23 01:06:05 +00005387 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005388#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005389 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005390 {
5391 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005392 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005393 sigprocmask(0, NULL, &cur_set);
5394 host_to_target_old_sigset(&target_set, &cur_set);
5395 ret = target_set;
5396 }
5397 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005398#endif
5399#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005400 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005401 {
5402 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005403 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005404 sigprocmask(0, NULL, &cur_set);
5405 target_to_host_old_sigset(&set, &target_set);
5406 sigorset(&set, &set, &cur_set);
5407 sigprocmask(SIG_SETMASK, &set, &oset);
5408 host_to_target_old_sigset(&target_set, &oset);
5409 ret = target_set;
5410 }
5411 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005412#endif
thse5febef2007-04-01 18:31:35 +00005413#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005414 case TARGET_NR_sigprocmask:
5415 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005416#if defined(TARGET_ALPHA)
5417 sigset_t set, oldset;
5418 abi_ulong mask;
5419 int how;
5420
5421 switch (arg1) {
5422 case TARGET_SIG_BLOCK:
5423 how = SIG_BLOCK;
5424 break;
5425 case TARGET_SIG_UNBLOCK:
5426 how = SIG_UNBLOCK;
5427 break;
5428 case TARGET_SIG_SETMASK:
5429 how = SIG_SETMASK;
5430 break;
5431 default:
5432 ret = -TARGET_EINVAL;
5433 goto fail;
5434 }
5435 mask = arg2;
5436 target_to_host_old_sigset(&set, &mask);
5437
5438 ret = get_errno(sigprocmask(how, &set, &oldset));
5439
5440 if (!is_error(ret)) {
5441 host_to_target_old_sigset(&mask, &oldset);
5442 ret = mask;
5443 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5444 }
5445#else
bellard66fb9762003-03-23 01:06:05 +00005446 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005447 int how;
ths3b46e622007-09-17 08:09:54 +00005448
pbrook53a59602006-03-25 19:31:22 +00005449 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005450 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005451 case TARGET_SIG_BLOCK:
5452 how = SIG_BLOCK;
5453 break;
5454 case TARGET_SIG_UNBLOCK:
5455 how = SIG_UNBLOCK;
5456 break;
5457 case TARGET_SIG_SETMASK:
5458 how = SIG_SETMASK;
5459 break;
5460 default:
ths0da46a62007-10-20 20:23:07 +00005461 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005462 goto fail;
5463 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005464 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005465 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005466 target_to_host_old_sigset(&set, p);
5467 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005468 set_ptr = &set;
5469 } else {
5470 how = 0;
5471 set_ptr = NULL;
5472 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005473 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005474 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005475 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005476 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005477 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005478 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005479 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005480#endif
bellard66fb9762003-03-23 01:06:05 +00005481 }
5482 break;
thse5febef2007-04-01 18:31:35 +00005483#endif
bellard66fb9762003-03-23 01:06:05 +00005484 case TARGET_NR_rt_sigprocmask:
5485 {
5486 int how = arg1;
5487 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005488
pbrook53a59602006-03-25 19:31:22 +00005489 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005490 switch(how) {
5491 case TARGET_SIG_BLOCK:
5492 how = SIG_BLOCK;
5493 break;
5494 case TARGET_SIG_UNBLOCK:
5495 how = SIG_UNBLOCK;
5496 break;
5497 case TARGET_SIG_SETMASK:
5498 how = SIG_SETMASK;
5499 break;
5500 default:
ths0da46a62007-10-20 20:23:07 +00005501 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005502 goto fail;
5503 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005504 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005505 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005506 target_to_host_sigset(&set, p);
5507 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005508 set_ptr = &set;
5509 } else {
5510 how = 0;
5511 set_ptr = NULL;
5512 }
5513 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005514 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005515 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005516 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005517 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005518 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005519 }
5520 }
5521 break;
thse5febef2007-04-01 18:31:35 +00005522#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005523 case TARGET_NR_sigpending:
5524 {
5525 sigset_t set;
5526 ret = get_errno(sigpending(&set));
5527 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005528 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005529 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005530 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005531 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005532 }
5533 }
5534 break;
thse5febef2007-04-01 18:31:35 +00005535#endif
bellard66fb9762003-03-23 01:06:05 +00005536 case TARGET_NR_rt_sigpending:
5537 {
5538 sigset_t set;
5539 ret = get_errno(sigpending(&set));
5540 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005541 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005542 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005543 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005544 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005545 }
5546 }
5547 break;
thse5febef2007-04-01 18:31:35 +00005548#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005549 case TARGET_NR_sigsuspend:
5550 {
5551 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005552#if defined(TARGET_ALPHA)
5553 abi_ulong mask = arg1;
5554 target_to_host_old_sigset(&set, &mask);
5555#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005556 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005557 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005558 target_to_host_old_sigset(&set, p);
5559 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005560#endif
bellard66fb9762003-03-23 01:06:05 +00005561 ret = get_errno(sigsuspend(&set));
5562 }
5563 break;
thse5febef2007-04-01 18:31:35 +00005564#endif
bellard66fb9762003-03-23 01:06:05 +00005565 case TARGET_NR_rt_sigsuspend:
5566 {
5567 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005568 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005569 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005570 target_to_host_sigset(&set, p);
5571 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005572 ret = get_errno(sigsuspend(&set));
5573 }
5574 break;
5575 case TARGET_NR_rt_sigtimedwait:
5576 {
bellard66fb9762003-03-23 01:06:05 +00005577 sigset_t set;
5578 struct timespec uts, *puts;
5579 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005580
Anthony Liguoric227f092009-10-01 16:12:16 -05005581 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005582 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005583 target_to_host_sigset(&set, p);
5584 unlock_user(p, arg1, 0);
5585 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005586 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005587 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005588 } else {
5589 puts = NULL;
5590 }
5591 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005592 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005593 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005594 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005595 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005596 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005597 }
5598 }
5599 break;
5600 case TARGET_NR_rt_sigqueueinfo:
5601 {
5602 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005603 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005604 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005605 target_to_host_siginfo(&uinfo, p);
5606 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005607 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5608 }
5609 break;
thse5febef2007-04-01 18:31:35 +00005610#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005611 case TARGET_NR_sigreturn:
5612 /* NOTE: ret is eax, so not transcoding must be done */
5613 ret = do_sigreturn(cpu_env);
5614 break;
thse5febef2007-04-01 18:31:35 +00005615#endif
bellard66fb9762003-03-23 01:06:05 +00005616 case TARGET_NR_rt_sigreturn:
5617 /* NOTE: ret is eax, so not transcoding must be done */
5618 ret = do_rt_sigreturn(cpu_env);
5619 break;
bellard31e31b82003-02-18 22:55:36 +00005620 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00005621 if (!(p = lock_user_string(arg1)))
5622 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005623 ret = get_errno(sethostname(p, arg2));
5624 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005625 break;
5626 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00005627 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005628 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005629 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005630 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00005631 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
5632 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005633 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
5634 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005635 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00005636 ret = get_errno(setrlimit(resource, &rlim));
5637 }
5638 break;
bellard31e31b82003-02-18 22:55:36 +00005639 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00005640 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005641 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005642 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005643 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00005644
bellard9de5e442003-03-23 16:49:39 +00005645 ret = get_errno(getrlimit(resource, &rlim));
5646 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005647 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
5648 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005649 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
5650 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005651 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00005652 }
5653 }
5654 break;
bellard31e31b82003-02-18 22:55:36 +00005655 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00005656 {
5657 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00005658 ret = get_errno(getrusage(arg1, &rusage));
5659 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005660 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00005661 }
5662 }
5663 break;
bellard31e31b82003-02-18 22:55:36 +00005664 case TARGET_NR_gettimeofday:
5665 {
bellard31e31b82003-02-18 22:55:36 +00005666 struct timeval tv;
5667 ret = get_errno(gettimeofday(&tv, NULL));
5668 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00005669 if (copy_to_user_timeval(arg1, &tv))
5670 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005671 }
5672 }
5673 break;
5674 case TARGET_NR_settimeofday:
5675 {
bellard31e31b82003-02-18 22:55:36 +00005676 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00005677 if (copy_from_user_timeval(&tv, arg1))
5678 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005679 ret = get_errno(settimeofday(&tv, NULL));
5680 }
5681 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005682#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00005683 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00005684 {
pbrook53a59602006-03-25 19:31:22 +00005685 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00005686 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00005687 long nsel;
5688
bellard579a97f2007-11-11 14:26:47 +00005689 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
5690 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005691 nsel = tswapl(sel->n);
5692 inp = tswapl(sel->inp);
5693 outp = tswapl(sel->outp);
5694 exp = tswapl(sel->exp);
5695 tvp = tswapl(sel->tvp);
5696 unlock_user_struct(sel, arg1, 0);
5697 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00005698 }
5699 break;
bellard048f6b42005-11-26 18:47:20 +00005700#endif
Riku Voipio9e423822010-05-07 12:28:05 +00005701#ifdef TARGET_NR_pselect6
5702 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04005703 {
5704 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
5705 fd_set rfds, wfds, efds;
5706 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
5707 struct timespec ts, *ts_ptr;
5708
5709 /*
5710 * The 6th arg is actually two args smashed together,
5711 * so we cannot use the C library.
5712 */
5713 sigset_t set;
5714 struct {
5715 sigset_t *set;
5716 size_t size;
5717 } sig, *sig_ptr;
5718
5719 abi_ulong arg_sigset, arg_sigsize, *arg7;
5720 target_sigset_t *target_sigset;
5721
5722 n = arg1;
5723 rfd_addr = arg2;
5724 wfd_addr = arg3;
5725 efd_addr = arg4;
5726 ts_addr = arg5;
5727
5728 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
5729 if (ret) {
5730 goto fail;
5731 }
5732 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
5733 if (ret) {
5734 goto fail;
5735 }
5736 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
5737 if (ret) {
5738 goto fail;
5739 }
5740
5741 /*
5742 * This takes a timespec, and not a timeval, so we cannot
5743 * use the do_select() helper ...
5744 */
5745 if (ts_addr) {
5746 if (target_to_host_timespec(&ts, ts_addr)) {
5747 goto efault;
5748 }
5749 ts_ptr = &ts;
5750 } else {
5751 ts_ptr = NULL;
5752 }
5753
5754 /* Extract the two packed args for the sigset */
5755 if (arg6) {
5756 sig_ptr = &sig;
5757 sig.size = _NSIG / 8;
5758
5759 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
5760 if (!arg7) {
5761 goto efault;
5762 }
5763 arg_sigset = tswapl(arg7[0]);
5764 arg_sigsize = tswapl(arg7[1]);
5765 unlock_user(arg7, arg6, 0);
5766
5767 if (arg_sigset) {
5768 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01005769 if (arg_sigsize != sizeof(*target_sigset)) {
5770 /* Like the kernel, we enforce correct size sigsets */
5771 ret = -TARGET_EINVAL;
5772 goto fail;
5773 }
Mike Frysinger055e0902011-06-03 17:01:49 -04005774 target_sigset = lock_user(VERIFY_READ, arg_sigset,
5775 sizeof(*target_sigset), 1);
5776 if (!target_sigset) {
5777 goto efault;
5778 }
5779 target_to_host_sigset(&set, target_sigset);
5780 unlock_user(target_sigset, arg_sigset, 0);
5781 } else {
5782 sig.set = NULL;
5783 }
5784 } else {
5785 sig_ptr = NULL;
5786 }
5787
5788 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
5789 ts_ptr, sig_ptr));
5790
5791 if (!is_error(ret)) {
5792 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
5793 goto efault;
5794 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
5795 goto efault;
5796 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
5797 goto efault;
5798
5799 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
5800 goto efault;
5801 }
5802 }
5803 break;
Riku Voipio9e423822010-05-07 12:28:05 +00005804#endif
bellard31e31b82003-02-18 22:55:36 +00005805 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00005806 {
5807 void *p2;
5808 p = lock_user_string(arg1);
5809 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005810 if (!p || !p2)
5811 ret = -TARGET_EFAULT;
5812 else
5813 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005814 unlock_user(p2, arg2, 0);
5815 unlock_user(p, arg1, 0);
5816 }
bellard31e31b82003-02-18 22:55:36 +00005817 break;
thsf0b62432007-09-24 09:25:40 +00005818#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
5819 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00005820 {
bellard579a97f2007-11-11 14:26:47 +00005821 void *p2;
thsf0b62432007-09-24 09:25:40 +00005822 p = lock_user_string(arg1);
5823 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005824 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005825 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00005826 else
5827 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00005828 unlock_user(p2, arg3, 0);
5829 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00005830 }
5831 break;
5832#endif
bellardebc05482003-09-30 21:08:41 +00005833#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00005834 case TARGET_NR_oldlstat:
5835 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005836#endif
bellard31e31b82003-02-18 22:55:36 +00005837 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00005838 {
aurel32d088d662009-01-30 20:09:01 +00005839 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00005840 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00005841 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
5842 if (!p || !p2)
5843 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00005844 else {
5845 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
5846 char real[PATH_MAX];
5847 temp = realpath(exec_path,real);
5848 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
5849 snprintf((char *)p2, arg3, "%s", real);
5850 }
5851 else
5852 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00005853 }
pbrook53a59602006-03-25 19:31:22 +00005854 unlock_user(p2, arg2, ret);
5855 unlock_user(p, arg1, 0);
5856 }
bellard31e31b82003-02-18 22:55:36 +00005857 break;
ths5e0ccb12007-09-24 09:26:10 +00005858#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
5859 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00005860 {
bellard579a97f2007-11-11 14:26:47 +00005861 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00005862 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005863 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
5864 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005865 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00005866 else
5867 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00005868 unlock_user(p2, arg3, ret);
5869 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00005870 }
5871 break;
5872#endif
thse5febef2007-04-01 18:31:35 +00005873#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00005874 case TARGET_NR_uselib:
5875 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005876#endif
5877#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00005878 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00005879 if (!(p = lock_user_string(arg1)))
5880 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005881 ret = get_errno(swapon(p, arg2));
5882 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005883 break;
thse5febef2007-04-01 18:31:35 +00005884#endif
bellard31e31b82003-02-18 22:55:36 +00005885 case TARGET_NR_reboot:
5886 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005887#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00005888 case TARGET_NR_readdir:
5889 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005890#endif
5891#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00005892 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005893#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
5894 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
5895 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00005896 {
blueswir1992f48a2007-10-14 16:27:31 +00005897 abi_ulong *v;
5898 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00005899 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
5900 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005901 v1 = tswapl(v[0]);
5902 v2 = tswapl(v[1]);
5903 v3 = tswapl(v[2]);
5904 v4 = tswapl(v[3]);
5905 v5 = tswapl(v[4]);
5906 v6 = tswapl(v[5]);
5907 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00005908 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00005909 target_to_host_bitmask(v4, mmap_flags_tbl),
5910 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00005911 }
bellard31e31b82003-02-18 22:55:36 +00005912#else
ths5fafdf22007-09-16 21:08:06 +00005913 ret = get_errno(target_mmap(arg1, arg2, arg3,
5914 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00005915 arg5,
5916 arg6));
bellard31e31b82003-02-18 22:55:36 +00005917#endif
bellard6fb883e2003-07-09 17:12:39 +00005918 break;
thse5febef2007-04-01 18:31:35 +00005919#endif
bellarda315a142005-01-30 22:59:18 +00005920#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00005921 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00005922#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00005923#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00005924#endif
ths5fafdf22007-09-16 21:08:06 +00005925 ret = get_errno(target_mmap(arg1, arg2, arg3,
5926 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00005927 arg5,
bellardc573ff62004-01-04 15:51:36 +00005928 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00005929 break;
bellarda315a142005-01-30 22:59:18 +00005930#endif
bellard31e31b82003-02-18 22:55:36 +00005931 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00005932 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005933 break;
bellard9de5e442003-03-23 16:49:39 +00005934 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01005935 {
5936 TaskState *ts = ((CPUState *)cpu_env)->opaque;
5937 /* Special hack to detect libc making the stack executable. */
5938 if ((arg3 & PROT_GROWSDOWN)
5939 && arg1 >= ts->info->stack_limit
5940 && arg1 <= ts->info->start_stack) {
5941 arg3 &= ~PROT_GROWSDOWN;
5942 arg2 = arg2 + arg1 - ts->info->stack_limit;
5943 arg1 = ts->info->stack_limit;
5944 }
5945 }
bellard54936002003-05-13 00:25:15 +00005946 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005947 break;
thse5febef2007-04-01 18:31:35 +00005948#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00005949 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00005950 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00005951 break;
thse5febef2007-04-01 18:31:35 +00005952#endif
pbrook53a59602006-03-25 19:31:22 +00005953 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00005954#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00005955 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00005956 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005957 break;
thse5febef2007-04-01 18:31:35 +00005958#endif
5959#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00005960 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00005961 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005962 break;
thse5febef2007-04-01 18:31:35 +00005963#endif
5964#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00005965 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00005966 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005967 break;
thse5febef2007-04-01 18:31:35 +00005968#endif
5969#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00005970 case TARGET_NR_mlockall:
5971 ret = get_errno(mlockall(arg1));
5972 break;
thse5febef2007-04-01 18:31:35 +00005973#endif
5974#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00005975 case TARGET_NR_munlockall:
5976 ret = get_errno(munlockall());
5977 break;
thse5febef2007-04-01 18:31:35 +00005978#endif
bellard31e31b82003-02-18 22:55:36 +00005979 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00005980 if (!(p = lock_user_string(arg1)))
5981 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005982 ret = get_errno(truncate(p, arg2));
5983 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005984 break;
5985 case TARGET_NR_ftruncate:
5986 ret = get_errno(ftruncate(arg1, arg2));
5987 break;
5988 case TARGET_NR_fchmod:
5989 ret = get_errno(fchmod(arg1, arg2));
5990 break;
ths814d7972007-09-24 09:26:51 +00005991#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
5992 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00005993 if (!(p = lock_user_string(arg2)))
5994 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005995 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005996 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00005997 break;
5998#endif
bellard31e31b82003-02-18 22:55:36 +00005999 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00006000 /* libc does special remapping of the return value of
6001 * sys_getpriority() so it's just easiest to call
6002 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03006003 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006004 break;
6005 case TARGET_NR_setpriority:
6006 ret = get_errno(setpriority(arg1, arg2, arg3));
6007 break;
bellardebc05482003-09-30 21:08:41 +00006008#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006009 case TARGET_NR_profil:
6010 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006011#endif
bellard31e31b82003-02-18 22:55:36 +00006012 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006013 if (!(p = lock_user_string(arg1)))
6014 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006015 ret = get_errno(statfs(path(p), &stfs));
6016 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006017 convert_statfs:
6018 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006019 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006020
bellard579a97f2007-11-11 14:26:47 +00006021 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6022 goto efault;
6023 __put_user(stfs.f_type, &target_stfs->f_type);
6024 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6025 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6026 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6027 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6028 __put_user(stfs.f_files, &target_stfs->f_files);
6029 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6030 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6031 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6032 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00006033 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006034 }
6035 break;
6036 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006037 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006038 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006039#ifdef TARGET_NR_statfs64
6040 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006041 if (!(p = lock_user_string(arg1)))
6042 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006043 ret = get_errno(statfs(path(p), &stfs));
6044 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006045 convert_statfs64:
6046 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006047 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006048
bellard579a97f2007-11-11 14:26:47 +00006049 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6050 goto efault;
6051 __put_user(stfs.f_type, &target_stfs->f_type);
6052 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6053 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6054 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6055 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6056 __put_user(stfs.f_files, &target_stfs->f_files);
6057 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6058 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6059 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6060 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
6061 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006062 }
6063 break;
6064 case TARGET_NR_fstatfs64:
6065 ret = get_errno(fstatfs(arg1, &stfs));
6066 goto convert_statfs64;
6067#endif
bellardebc05482003-09-30 21:08:41 +00006068#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006069 case TARGET_NR_ioperm:
6070 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006071#endif
thse5febef2007-04-01 18:31:35 +00006072#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006073 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006074 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006075 break;
thse5febef2007-04-01 18:31:35 +00006076#endif
bellard3532fa72006-06-24 15:06:03 +00006077#ifdef TARGET_NR_accept
6078 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006079 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006080 break;
6081#endif
6082#ifdef TARGET_NR_bind
6083 case TARGET_NR_bind:
6084 ret = do_bind(arg1, arg2, arg3);
6085 break;
6086#endif
6087#ifdef TARGET_NR_connect
6088 case TARGET_NR_connect:
6089 ret = do_connect(arg1, arg2, arg3);
6090 break;
6091#endif
6092#ifdef TARGET_NR_getpeername
6093 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006094 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006095 break;
6096#endif
6097#ifdef TARGET_NR_getsockname
6098 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006099 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006100 break;
6101#endif
6102#ifdef TARGET_NR_getsockopt
6103 case TARGET_NR_getsockopt:
6104 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6105 break;
6106#endif
6107#ifdef TARGET_NR_listen
6108 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006109 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006110 break;
6111#endif
6112#ifdef TARGET_NR_recv
6113 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006114 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006115 break;
6116#endif
6117#ifdef TARGET_NR_recvfrom
6118 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006119 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006120 break;
6121#endif
6122#ifdef TARGET_NR_recvmsg
6123 case TARGET_NR_recvmsg:
6124 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6125 break;
6126#endif
6127#ifdef TARGET_NR_send
6128 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006129 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006130 break;
6131#endif
6132#ifdef TARGET_NR_sendmsg
6133 case TARGET_NR_sendmsg:
6134 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6135 break;
6136#endif
6137#ifdef TARGET_NR_sendto
6138 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006139 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006140 break;
6141#endif
6142#ifdef TARGET_NR_shutdown
6143 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006144 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006145 break;
6146#endif
6147#ifdef TARGET_NR_socket
6148 case TARGET_NR_socket:
6149 ret = do_socket(arg1, arg2, arg3);
6150 break;
6151#endif
6152#ifdef TARGET_NR_socketpair
6153 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006154 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006155 break;
6156#endif
6157#ifdef TARGET_NR_setsockopt
6158 case TARGET_NR_setsockopt:
6159 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6160 break;
6161#endif
ths7494b0f2007-02-11 18:26:53 +00006162
bellard31e31b82003-02-18 22:55:36 +00006163 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006164 if (!(p = lock_user_string(arg2)))
6165 goto efault;
thse5574482007-02-11 20:03:13 +00006166 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6167 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006168 break;
6169
bellard31e31b82003-02-18 22:55:36 +00006170 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006171 {
bellard66fb9762003-03-23 01:06:05 +00006172 struct itimerval value, ovalue, *pvalue;
6173
pbrook53a59602006-03-25 19:31:22 +00006174 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006175 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006176 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6177 || copy_from_user_timeval(&pvalue->it_value,
6178 arg2 + sizeof(struct target_timeval)))
6179 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006180 } else {
6181 pvalue = NULL;
6182 }
6183 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006184 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006185 if (copy_to_user_timeval(arg3,
6186 &ovalue.it_interval)
6187 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6188 &ovalue.it_value))
6189 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006190 }
6191 }
6192 break;
bellard31e31b82003-02-18 22:55:36 +00006193 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006194 {
bellard66fb9762003-03-23 01:06:05 +00006195 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006196
bellard66fb9762003-03-23 01:06:05 +00006197 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006198 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006199 if (copy_to_user_timeval(arg2,
6200 &value.it_interval)
6201 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6202 &value.it_value))
6203 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006204 }
6205 }
6206 break;
bellard31e31b82003-02-18 22:55:36 +00006207 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006208 if (!(p = lock_user_string(arg1)))
6209 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006210 ret = get_errno(stat(path(p), &st));
6211 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006212 goto do_stat;
6213 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006214 if (!(p = lock_user_string(arg1)))
6215 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006216 ret = get_errno(lstat(path(p), &st));
6217 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006218 goto do_stat;
6219 case TARGET_NR_fstat:
6220 {
6221 ret = get_errno(fstat(arg1, &st));
6222 do_stat:
6223 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006224 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006225
bellard579a97f2007-11-11 14:26:47 +00006226 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6227 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006228 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006229 __put_user(st.st_dev, &target_st->st_dev);
6230 __put_user(st.st_ino, &target_st->st_ino);
6231 __put_user(st.st_mode, &target_st->st_mode);
6232 __put_user(st.st_uid, &target_st->st_uid);
6233 __put_user(st.st_gid, &target_st->st_gid);
6234 __put_user(st.st_nlink, &target_st->st_nlink);
6235 __put_user(st.st_rdev, &target_st->st_rdev);
6236 __put_user(st.st_size, &target_st->st_size);
6237 __put_user(st.st_blksize, &target_st->st_blksize);
6238 __put_user(st.st_blocks, &target_st->st_blocks);
6239 __put_user(st.st_atime, &target_st->target_st_atime);
6240 __put_user(st.st_mtime, &target_st->target_st_mtime);
6241 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006242 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006243 }
6244 }
6245 break;
bellardebc05482003-09-30 21:08:41 +00006246#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006247 case TARGET_NR_olduname:
6248 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006249#endif
6250#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006251 case TARGET_NR_iopl:
6252 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006253#endif
bellard31e31b82003-02-18 22:55:36 +00006254 case TARGET_NR_vhangup:
6255 ret = get_errno(vhangup());
6256 break;
bellardebc05482003-09-30 21:08:41 +00006257#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006258 case TARGET_NR_idle:
6259 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006260#endif
bellard42ad6ae2005-01-03 22:48:11 +00006261#ifdef TARGET_NR_syscall
6262 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006263 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6264 arg6, arg7, arg8, 0);
6265 break;
bellard42ad6ae2005-01-03 22:48:11 +00006266#endif
bellard31e31b82003-02-18 22:55:36 +00006267 case TARGET_NR_wait4:
6268 {
6269 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006270 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006271 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006272 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006273 if (target_rusage)
6274 rusage_ptr = &rusage;
6275 else
6276 rusage_ptr = NULL;
6277 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6278 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006279 if (status_ptr) {
pbrook1d9d8b52009-04-16 15:17:02 +00006280 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006281 if (put_user_s32(status, status_ptr))
6282 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006283 }
bellard2f619692007-11-16 10:46:05 +00006284 if (target_rusage)
6285 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006286 }
6287 }
6288 break;
thse5febef2007-04-01 18:31:35 +00006289#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006290 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006291 if (!(p = lock_user_string(arg1)))
6292 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006293 ret = get_errno(swapoff(p));
6294 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006295 break;
thse5febef2007-04-01 18:31:35 +00006296#endif
bellard31e31b82003-02-18 22:55:36 +00006297 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006298 {
pbrook53a59602006-03-25 19:31:22 +00006299 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006300 struct sysinfo value;
6301 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006302 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006303 {
bellard579a97f2007-11-11 14:26:47 +00006304 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6305 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006306 __put_user(value.uptime, &target_value->uptime);
6307 __put_user(value.loads[0], &target_value->loads[0]);
6308 __put_user(value.loads[1], &target_value->loads[1]);
6309 __put_user(value.loads[2], &target_value->loads[2]);
6310 __put_user(value.totalram, &target_value->totalram);
6311 __put_user(value.freeram, &target_value->freeram);
6312 __put_user(value.sharedram, &target_value->sharedram);
6313 __put_user(value.bufferram, &target_value->bufferram);
6314 __put_user(value.totalswap, &target_value->totalswap);
6315 __put_user(value.freeswap, &target_value->freeswap);
6316 __put_user(value.procs, &target_value->procs);
6317 __put_user(value.totalhigh, &target_value->totalhigh);
6318 __put_user(value.freehigh, &target_value->freehigh);
6319 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006320 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006321 }
6322 }
6323 break;
thse5febef2007-04-01 18:31:35 +00006324#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006325 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006326 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6327 break;
thse5febef2007-04-01 18:31:35 +00006328#endif
aurel32e5289082009-04-18 16:16:12 +00006329#ifdef TARGET_NR_semget
6330 case TARGET_NR_semget:
6331 ret = get_errno(semget(arg1, arg2, arg3));
6332 break;
6333#endif
6334#ifdef TARGET_NR_semop
6335 case TARGET_NR_semop:
6336 ret = get_errno(do_semop(arg1, arg2, arg3));
6337 break;
6338#endif
6339#ifdef TARGET_NR_semctl
6340 case TARGET_NR_semctl:
6341 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6342 break;
6343#endif
aurel32eeb438c2008-10-13 21:08:55 +00006344#ifdef TARGET_NR_msgctl
6345 case TARGET_NR_msgctl:
6346 ret = do_msgctl(arg1, arg2, arg3);
6347 break;
6348#endif
6349#ifdef TARGET_NR_msgget
6350 case TARGET_NR_msgget:
6351 ret = get_errno(msgget(arg1, arg2));
6352 break;
6353#endif
6354#ifdef TARGET_NR_msgrcv
6355 case TARGET_NR_msgrcv:
6356 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6357 break;
6358#endif
6359#ifdef TARGET_NR_msgsnd
6360 case TARGET_NR_msgsnd:
6361 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6362 break;
6363#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006364#ifdef TARGET_NR_shmget
6365 case TARGET_NR_shmget:
6366 ret = get_errno(shmget(arg1, arg2, arg3));
6367 break;
6368#endif
6369#ifdef TARGET_NR_shmctl
6370 case TARGET_NR_shmctl:
6371 ret = do_shmctl(arg1, arg2, arg3);
6372 break;
6373#endif
6374#ifdef TARGET_NR_shmat
6375 case TARGET_NR_shmat:
6376 ret = do_shmat(arg1, arg2, arg3);
6377 break;
6378#endif
6379#ifdef TARGET_NR_shmdt
6380 case TARGET_NR_shmdt:
6381 ret = do_shmdt(arg1);
6382 break;
6383#endif
bellard31e31b82003-02-18 22:55:36 +00006384 case TARGET_NR_fsync:
6385 ret = get_errno(fsync(arg1));
6386 break;
bellard31e31b82003-02-18 22:55:36 +00006387 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006388#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006389 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006390#elif defined(TARGET_CRIS)
6391 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006392#elif defined(TARGET_S390X)
6393 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006394#else
pbrookd865bab2008-06-07 22:12:17 +00006395 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006396#endif
bellard1b6b0292003-03-22 17:31:38 +00006397 break;
bellardec86b0f2003-04-11 00:15:04 +00006398#ifdef __NR_exit_group
6399 /* new thread calls */
6400 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006401#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006402 _mcleanup();
6403#endif
bellarde9009672005-04-26 20:42:36 +00006404 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006405 ret = get_errno(exit_group(arg1));
6406 break;
6407#endif
bellard31e31b82003-02-18 22:55:36 +00006408 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006409 if (!(p = lock_user_string(arg1)))
6410 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006411 ret = get_errno(setdomainname(p, arg2));
6412 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006413 break;
6414 case TARGET_NR_uname:
6415 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006416 {
6417 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006418
bellard579a97f2007-11-11 14:26:47 +00006419 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6420 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006421 ret = get_errno(sys_uname(buf));
6422 if (!is_error(ret)) {
6423 /* Overrite the native machine name with whatever is being
6424 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006425 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006426 /* Allow the user to override the reported release. */
6427 if (qemu_uname_release && *qemu_uname_release)
6428 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006429 }
pbrook53a59602006-03-25 19:31:22 +00006430 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006431 }
bellard31e31b82003-02-18 22:55:36 +00006432 break;
bellard6dbad632003-03-16 18:05:05 +00006433#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006434 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006435 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006436 break;
j_mayer84409dd2007-04-06 08:56:50 +00006437#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006438 case TARGET_NR_vm86old:
6439 goto unimplemented;
6440 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006441 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006442 break;
6443#endif
j_mayer84409dd2007-04-06 08:56:50 +00006444#endif
bellard31e31b82003-02-18 22:55:36 +00006445 case TARGET_NR_adjtimex:
6446 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006447#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006448 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006449#endif
bellard31e31b82003-02-18 22:55:36 +00006450 case TARGET_NR_init_module:
6451 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006452#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006453 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006454#endif
bellard31e31b82003-02-18 22:55:36 +00006455 goto unimplemented;
6456 case TARGET_NR_quotactl:
6457 goto unimplemented;
6458 case TARGET_NR_getpgid:
6459 ret = get_errno(getpgid(arg1));
6460 break;
6461 case TARGET_NR_fchdir:
6462 ret = get_errno(fchdir(arg1));
6463 break;
j_mayer84409dd2007-04-06 08:56:50 +00006464#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006465 case TARGET_NR_bdflush:
6466 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006467#endif
thse5febef2007-04-01 18:31:35 +00006468#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006469 case TARGET_NR_sysfs:
6470 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006471#endif
bellard31e31b82003-02-18 22:55:36 +00006472 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006473 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006474 break;
thse5febef2007-04-01 18:31:35 +00006475#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006476 case TARGET_NR_afs_syscall:
6477 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006478#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006479#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006480 case TARGET_NR__llseek:
6481 {
6482 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006483#if !defined(__NR_llseek)
6484 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6485 if (res == -1) {
6486 ret = get_errno(res);
6487 } else {
6488 ret = 0;
6489 }
6490#else
bellard31e31b82003-02-18 22:55:36 +00006491 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006492#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006493 if ((ret == 0) && put_user_s64(res, arg4)) {
6494 goto efault;
6495 }
bellard31e31b82003-02-18 22:55:36 +00006496 }
6497 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006498#endif
bellard31e31b82003-02-18 22:55:36 +00006499 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006500#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006501 {
pbrook53a59602006-03-25 19:31:22 +00006502 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006503 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006504 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006505
6506 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006507 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006508 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006509 goto fail;
6510 }
ths3b46e622007-09-17 08:09:54 +00006511
bellard4add45b2003-06-05 01:52:59 +00006512 ret = get_errno(sys_getdents(arg1, dirp, count));
6513 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006514 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006515 struct target_dirent *tde;
6516 int len = ret;
6517 int reclen, treclen;
6518 int count1, tnamelen;
6519
6520 count1 = 0;
6521 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006522 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6523 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006524 tde = target_dirp;
6525 while (len > 0) {
6526 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006527 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006528 tde->d_reclen = tswap16(treclen);
6529 tde->d_ino = tswapl(de->d_ino);
6530 tde->d_off = tswapl(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006531 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006532 if (tnamelen > 256)
6533 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006534 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006535 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006536 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006537 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006538 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006539 count1 += treclen;
6540 }
6541 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006542 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006543 }
6544 free(dirp);
6545 }
6546#else
bellard31e31b82003-02-18 22:55:36 +00006547 {
aurel326556a832008-10-13 21:08:17 +00006548 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006549 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006550
bellard579a97f2007-11-11 14:26:47 +00006551 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6552 goto efault;
bellard72f03902003-02-18 23:33:18 +00006553 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006554 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006555 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006556 int len = ret;
6557 int reclen;
6558 de = dirp;
6559 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006560 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006561 if (reclen > len)
6562 break;
bellard8083a3e2003-03-24 23:12:16 +00006563 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006564 tswapls(&de->d_ino);
6565 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006566 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006567 len -= reclen;
6568 }
6569 }
pbrook53a59602006-03-25 19:31:22 +00006570 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006571 }
bellard4add45b2003-06-05 01:52:59 +00006572#endif
bellard31e31b82003-02-18 22:55:36 +00006573 break;
ths3ae43202007-09-16 21:39:48 +00006574#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006575 case TARGET_NR_getdents64:
6576 {
aurel326556a832008-10-13 21:08:17 +00006577 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006578 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006579 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6580 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006581 ret = get_errno(sys_getdents64(arg1, dirp, count));
6582 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006583 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006584 int len = ret;
6585 int reclen;
6586 de = dirp;
6587 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006588 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006589 if (reclen > len)
6590 break;
bellard8083a3e2003-03-24 23:12:16 +00006591 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006592 tswap64s((uint64_t *)&de->d_ino);
6593 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006594 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006595 len -= reclen;
6596 }
6597 }
pbrook53a59602006-03-25 19:31:22 +00006598 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006599 }
6600 break;
bellarda541f292004-04-12 20:39:29 +00006601#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006602#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
6603#ifdef TARGET_S390X
6604 case TARGET_NR_select:
6605#else
bellard31e31b82003-02-18 22:55:36 +00006606 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006607#endif
pbrook53a59602006-03-25 19:31:22 +00006608 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00006609 break;
thse5febef2007-04-01 18:31:35 +00006610#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05006611#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
6612# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00006613 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05006614# endif
6615# ifdef TARGET_NR_ppoll
6616 case TARGET_NR_ppoll:
6617# endif
bellard9de5e442003-03-23 16:49:39 +00006618 {
pbrook53a59602006-03-25 19:31:22 +00006619 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00006620 unsigned int nfds = arg2;
6621 int timeout = arg3;
6622 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00006623 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00006624
bellard579a97f2007-11-11 14:26:47 +00006625 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
6626 if (!target_pfd)
6627 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05006628
bellard9de5e442003-03-23 16:49:39 +00006629 pfd = alloca(sizeof(struct pollfd) * nfds);
6630 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006631 pfd[i].fd = tswap32(target_pfd[i].fd);
6632 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00006633 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05006634
6635# ifdef TARGET_NR_ppoll
6636 if (num == TARGET_NR_ppoll) {
6637 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
6638 target_sigset_t *target_set;
6639 sigset_t _set, *set = &_set;
6640
6641 if (arg3) {
6642 if (target_to_host_timespec(timeout_ts, arg3)) {
6643 unlock_user(target_pfd, arg1, 0);
6644 goto efault;
6645 }
6646 } else {
6647 timeout_ts = NULL;
6648 }
6649
6650 if (arg4) {
6651 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
6652 if (!target_set) {
6653 unlock_user(target_pfd, arg1, 0);
6654 goto efault;
6655 }
6656 target_to_host_sigset(set, target_set);
6657 } else {
6658 set = NULL;
6659 }
6660
6661 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
6662
6663 if (!is_error(ret) && arg3) {
6664 host_to_target_timespec(arg3, timeout_ts);
6665 }
6666 if (arg4) {
6667 unlock_user(target_set, arg4, 0);
6668 }
6669 } else
6670# endif
6671 ret = get_errno(poll(pfd, nfds, timeout));
6672
bellard9de5e442003-03-23 16:49:39 +00006673 if (!is_error(ret)) {
6674 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006675 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00006676 }
6677 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00006678 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00006679 }
6680 break;
thse5febef2007-04-01 18:31:35 +00006681#endif
bellard31e31b82003-02-18 22:55:36 +00006682 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00006683 /* NOTE: the flock constant seems to be the same for every
6684 Linux platform */
6685 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006686 break;
6687 case TARGET_NR_readv:
6688 {
6689 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006690 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006691
6692 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006693 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
6694 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006695 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006696 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00006697 }
6698 break;
6699 case TARGET_NR_writev:
6700 {
6701 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006702 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006703
6704 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006705 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
6706 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006707 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006708 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00006709 }
6710 break;
6711 case TARGET_NR_getsid:
6712 ret = get_errno(getsid(arg1));
6713 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006714#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00006715 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00006716 ret = get_errno(fdatasync(arg1));
6717 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006718#endif
bellard31e31b82003-02-18 22:55:36 +00006719 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00006720 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00006721 return value. */
ths0da46a62007-10-20 20:23:07 +00006722 ret = -TARGET_ENOTDIR;
6723 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05006724 case TARGET_NR_sched_getaffinity:
6725 {
6726 unsigned int mask_size;
6727 unsigned long *mask;
6728
6729 /*
6730 * sched_getaffinity needs multiples of ulong, so need to take
6731 * care of mismatches between target ulong and host ulong sizes.
6732 */
6733 if (arg2 & (sizeof(abi_ulong) - 1)) {
6734 ret = -TARGET_EINVAL;
6735 break;
6736 }
6737 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6738
6739 mask = alloca(mask_size);
6740 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
6741
6742 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09006743 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05006744 goto efault;
6745 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05006746 }
6747 }
6748 break;
6749 case TARGET_NR_sched_setaffinity:
6750 {
6751 unsigned int mask_size;
6752 unsigned long *mask;
6753
6754 /*
6755 * sched_setaffinity needs multiples of ulong, so need to take
6756 * care of mismatches between target ulong and host ulong sizes.
6757 */
6758 if (arg2 & (sizeof(abi_ulong) - 1)) {
6759 ret = -TARGET_EINVAL;
6760 break;
6761 }
6762 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6763
6764 mask = alloca(mask_size);
6765 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
6766 goto efault;
6767 }
6768 memcpy(mask, p, arg2);
6769 unlock_user_struct(p, arg2, 0);
6770
6771 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
6772 }
6773 break;
bellard31e31b82003-02-18 22:55:36 +00006774 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00006775 {
pbrook53a59602006-03-25 19:31:22 +00006776 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006777 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00006778
bellard579a97f2007-11-11 14:26:47 +00006779 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
6780 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006781 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006782 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00006783 ret = get_errno(sched_setparam(arg1, &schp));
6784 }
6785 break;
bellard31e31b82003-02-18 22:55:36 +00006786 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00006787 {
pbrook53a59602006-03-25 19:31:22 +00006788 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006789 struct sched_param schp;
6790 ret = get_errno(sched_getparam(arg1, &schp));
6791 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006792 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
6793 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006794 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006795 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00006796 }
6797 }
6798 break;
bellard31e31b82003-02-18 22:55:36 +00006799 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00006800 {
pbrook53a59602006-03-25 19:31:22 +00006801 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006802 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00006803 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
6804 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006805 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006806 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00006807 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
6808 }
6809 break;
bellard31e31b82003-02-18 22:55:36 +00006810 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00006811 ret = get_errno(sched_getscheduler(arg1));
6812 break;
bellard31e31b82003-02-18 22:55:36 +00006813 case TARGET_NR_sched_yield:
6814 ret = get_errno(sched_yield());
6815 break;
6816 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00006817 ret = get_errno(sched_get_priority_max(arg1));
6818 break;
bellard31e31b82003-02-18 22:55:36 +00006819 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00006820 ret = get_errno(sched_get_priority_min(arg1));
6821 break;
bellard31e31b82003-02-18 22:55:36 +00006822 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00006823 {
bellard5cd43932003-03-29 16:54:36 +00006824 struct timespec ts;
6825 ret = get_errno(sched_rr_get_interval(arg1, &ts));
6826 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006827 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00006828 }
6829 }
6830 break;
bellard31e31b82003-02-18 22:55:36 +00006831 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00006832 {
bellard1b6b0292003-03-22 17:31:38 +00006833 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00006834 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00006835 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00006836 if (is_error(ret) && arg2) {
6837 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00006838 }
6839 }
6840 break;
thse5febef2007-04-01 18:31:35 +00006841#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00006842 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00006843 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006844#endif
6845#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00006846 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00006847 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006848#endif
bellard31e31b82003-02-18 22:55:36 +00006849 case TARGET_NR_prctl:
thse5574482007-02-11 20:03:13 +00006850 switch (arg1)
6851 {
6852 case PR_GET_PDEATHSIG:
6853 {
6854 int deathsig;
6855 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
bellard2f619692007-11-16 10:46:05 +00006856 if (!is_error(ret) && arg2
6857 && put_user_ual(deathsig, arg2))
6858 goto efault;
thse5574482007-02-11 20:03:13 +00006859 }
6860 break;
6861 default:
6862 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
6863 break;
6864 }
ths39b9aae2007-02-11 18:36:44 +00006865 break;
bellardd2fd1af2007-11-14 18:08:56 +00006866#ifdef TARGET_NR_arch_prctl
6867 case TARGET_NR_arch_prctl:
6868#if defined(TARGET_I386) && !defined(TARGET_ABI32)
6869 ret = do_arch_prctl(cpu_env, arg1, arg2);
6870 break;
6871#else
6872 goto unimplemented;
6873#endif
6874#endif
bellard67867302003-11-23 17:05:30 +00006875#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00006876 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03006877 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006878 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006879 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6880 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006881 ret = get_errno(pread(arg1, p, arg3, arg4));
6882 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00006883 break;
bellard31e31b82003-02-18 22:55:36 +00006884 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03006885 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006886 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006887 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6888 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006889 ret = get_errno(pwrite(arg1, p, arg3, arg4));
6890 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00006891 break;
bellard67867302003-11-23 17:05:30 +00006892#endif
aurel32f2c7ba12008-03-28 22:32:06 +00006893#ifdef TARGET_NR_pread64
6894 case TARGET_NR_pread64:
6895 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6896 goto efault;
6897 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
6898 unlock_user(p, arg2, ret);
6899 break;
6900 case TARGET_NR_pwrite64:
6901 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6902 goto efault;
6903 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
6904 unlock_user(p, arg2, 0);
6905 break;
6906#endif
bellard31e31b82003-02-18 22:55:36 +00006907 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00006908 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
6909 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006910 ret = get_errno(sys_getcwd1(p, arg2));
6911 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00006912 break;
6913 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00006914 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006915 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00006916 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006917 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00006918#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02006919 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006920 defined(TARGET_M68K) || defined(TARGET_S390X)
bellard579a97f2007-11-11 14:26:47 +00006921 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00006922 break;
6923#else
bellard5cd43932003-03-29 16:54:36 +00006924 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00006925#endif
bellard31e31b82003-02-18 22:55:36 +00006926 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00006927 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006928#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00006929 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00006930 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006931#endif
6932#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00006933 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00006934 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006935#endif
bellard048f6b42005-11-26 18:47:20 +00006936#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00006937 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00006938 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
6939 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006940 break;
bellard048f6b42005-11-26 18:47:20 +00006941#endif
bellardebc05482003-09-30 21:08:41 +00006942#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00006943 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00006944 {
6945 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006946 int resource = target_to_host_resource(arg1);
6947 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00006948 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006949 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00006950 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6951 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006952 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6953 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006954 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00006955 }
6956 break;
6957 }
bellardebc05482003-09-30 21:08:41 +00006958#endif
bellarda315a142005-01-30 22:59:18 +00006959#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00006960 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00006961 if (!(p = lock_user_string(arg1)))
6962 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006963 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
6964 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00006965 break;
bellarda315a142005-01-30 22:59:18 +00006966#endif
6967#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00006968 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00006969 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00006970 break;
bellarda315a142005-01-30 22:59:18 +00006971#endif
6972#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00006973 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00006974 if (!(p = lock_user_string(arg1)))
6975 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006976 ret = get_errno(stat(path(p), &st));
6977 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006978 if (!is_error(ret))
6979 ret = host_to_target_stat64(cpu_env, arg2, &st);
6980 break;
bellarda315a142005-01-30 22:59:18 +00006981#endif
6982#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00006983 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00006984 if (!(p = lock_user_string(arg1)))
6985 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006986 ret = get_errno(lstat(path(p), &st));
6987 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006988 if (!is_error(ret))
6989 ret = host_to_target_stat64(cpu_env, arg2, &st);
6990 break;
bellarda315a142005-01-30 22:59:18 +00006991#endif
6992#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00006993 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00006994 ret = get_errno(fstat(arg1, &st));
6995 if (!is_error(ret))
6996 ret = host_to_target_stat64(cpu_env, arg2, &st);
6997 break;
bellardec86b0f2003-04-11 00:15:04 +00006998#endif
aurel329d33b762009-04-08 23:07:05 +00006999#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7000 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7001#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007002 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007003#endif
7004#ifdef TARGET_NR_newfstatat
7005 case TARGET_NR_newfstatat:
7006#endif
balrog6a24a772008-09-20 02:23:36 +00007007 if (!(p = lock_user_string(arg2)))
7008 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007009#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007010 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007011#else
7012 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7013#endif
balrog6a24a772008-09-20 02:23:36 +00007014 if (!is_error(ret))
7015 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007016 break;
bellarda315a142005-01-30 22:59:18 +00007017#endif
bellard67867302003-11-23 17:05:30 +00007018 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007019 if (!(p = lock_user_string(arg1)))
7020 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007021 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7022 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007023 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007024#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007025 case TARGET_NR_getuid:
7026 ret = get_errno(high2lowuid(getuid()));
7027 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007028#endif
7029#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007030 case TARGET_NR_getgid:
7031 ret = get_errno(high2lowgid(getgid()));
7032 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007033#endif
7034#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007035 case TARGET_NR_geteuid:
7036 ret = get_errno(high2lowuid(geteuid()));
7037 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007038#endif
7039#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007040 case TARGET_NR_getegid:
7041 ret = get_errno(high2lowgid(getegid()));
7042 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007043#endif
bellard67867302003-11-23 17:05:30 +00007044 case TARGET_NR_setreuid:
7045 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7046 break;
7047 case TARGET_NR_setregid:
7048 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7049 break;
7050 case TARGET_NR_getgroups:
7051 {
7052 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007053 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007054 gid_t *grouplist;
7055 int i;
7056
7057 grouplist = alloca(gidsetsize * sizeof(gid_t));
7058 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007059 if (gidsetsize == 0)
7060 break;
bellard67867302003-11-23 17:05:30 +00007061 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007062 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7063 if (!target_grouplist)
7064 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007065 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007066 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007067 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007068 }
7069 }
7070 break;
7071 case TARGET_NR_setgroups:
7072 {
7073 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007074 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007075 gid_t *grouplist;
7076 int i;
7077
7078 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007079 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7080 if (!target_grouplist) {
7081 ret = -TARGET_EFAULT;
7082 goto fail;
7083 }
bellard67867302003-11-23 17:05:30 +00007084 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007085 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007086 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007087 ret = get_errno(setgroups(gidsetsize, grouplist));
7088 }
7089 break;
7090 case TARGET_NR_fchown:
7091 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7092 break;
thsccfa72b2007-09-24 09:23:34 +00007093#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7094 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007095 if (!(p = lock_user_string(arg2)))
7096 goto efault;
7097 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7098 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007099 break;
7100#endif
bellard67867302003-11-23 17:05:30 +00007101#ifdef TARGET_NR_setresuid
7102 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007103 ret = get_errno(setresuid(low2highuid(arg1),
7104 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007105 low2highuid(arg3)));
7106 break;
7107#endif
7108#ifdef TARGET_NR_getresuid
7109 case TARGET_NR_getresuid:
7110 {
pbrook53a59602006-03-25 19:31:22 +00007111 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007112 ret = get_errno(getresuid(&ruid, &euid, &suid));
7113 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007114 if (put_user_u16(high2lowuid(ruid), arg1)
7115 || put_user_u16(high2lowuid(euid), arg2)
7116 || put_user_u16(high2lowuid(suid), arg3))
7117 goto efault;
bellard67867302003-11-23 17:05:30 +00007118 }
7119 }
7120 break;
7121#endif
7122#ifdef TARGET_NR_getresgid
7123 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007124 ret = get_errno(setresgid(low2highgid(arg1),
7125 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007126 low2highgid(arg3)));
7127 break;
7128#endif
7129#ifdef TARGET_NR_getresgid
7130 case TARGET_NR_getresgid:
7131 {
pbrook53a59602006-03-25 19:31:22 +00007132 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007133 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7134 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007135 if (put_user_u16(high2lowgid(rgid), arg1)
7136 || put_user_u16(high2lowgid(egid), arg2)
7137 || put_user_u16(high2lowgid(sgid), arg3))
7138 goto efault;
bellard67867302003-11-23 17:05:30 +00007139 }
7140 }
7141 break;
7142#endif
7143 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007144 if (!(p = lock_user_string(arg1)))
7145 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007146 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7147 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007148 break;
7149 case TARGET_NR_setuid:
7150 ret = get_errno(setuid(low2highuid(arg1)));
7151 break;
7152 case TARGET_NR_setgid:
7153 ret = get_errno(setgid(low2highgid(arg1)));
7154 break;
7155 case TARGET_NR_setfsuid:
7156 ret = get_errno(setfsuid(arg1));
7157 break;
7158 case TARGET_NR_setfsgid:
7159 ret = get_errno(setfsgid(arg1));
7160 break;
bellard67867302003-11-23 17:05:30 +00007161
bellarda315a142005-01-30 22:59:18 +00007162#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007163 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007164 if (!(p = lock_user_string(arg1)))
7165 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007166 ret = get_errno(lchown(p, arg2, arg3));
7167 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007168 break;
bellarda315a142005-01-30 22:59:18 +00007169#endif
7170#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007171 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007172 ret = get_errno(getuid());
7173 break;
bellarda315a142005-01-30 22:59:18 +00007174#endif
aurel3264b4d282008-11-14 17:20:15 +00007175
7176#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7177 /* Alpha specific */
7178 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007179 {
7180 uid_t euid;
7181 euid=geteuid();
7182 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7183 }
aurel3264b4d282008-11-14 17:20:15 +00007184 ret = get_errno(getuid());
7185 break;
7186#endif
7187#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7188 /* Alpha specific */
7189 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007190 {
7191 uid_t egid;
7192 egid=getegid();
7193 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7194 }
aurel3264b4d282008-11-14 17:20:15 +00007195 ret = get_errno(getgid());
7196 break;
7197#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007198#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7199 /* Alpha specific */
7200 case TARGET_NR_osf_getsysinfo:
7201 ret = -TARGET_EOPNOTSUPP;
7202 switch (arg1) {
7203 case TARGET_GSI_IEEE_FP_CONTROL:
7204 {
7205 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7206
7207 /* Copied from linux ieee_fpcr_to_swcr. */
7208 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7209 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7210 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7211 | SWCR_TRAP_ENABLE_DZE
7212 | SWCR_TRAP_ENABLE_OVF);
7213 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7214 | SWCR_TRAP_ENABLE_INE);
7215 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7216 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7217
7218 if (put_user_u64 (swcr, arg2))
7219 goto efault;
7220 ret = 0;
7221 }
7222 break;
7223
7224 /* case GSI_IEEE_STATE_AT_SIGNAL:
7225 -- Not implemented in linux kernel.
7226 case GSI_UACPROC:
7227 -- Retrieves current unaligned access state; not much used.
7228 case GSI_PROC_TYPE:
7229 -- Retrieves implver information; surely not used.
7230 case GSI_GET_HWRPB:
7231 -- Grabs a copy of the HWRPB; surely not used.
7232 */
7233 }
7234 break;
7235#endif
7236#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7237 /* Alpha specific */
7238 case TARGET_NR_osf_setsysinfo:
7239 ret = -TARGET_EOPNOTSUPP;
7240 switch (arg1) {
7241 case TARGET_SSI_IEEE_FP_CONTROL:
7242 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7243 {
7244 uint64_t swcr, fpcr, orig_fpcr;
7245
7246 if (get_user_u64 (swcr, arg2))
7247 goto efault;
7248 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7249 fpcr = orig_fpcr & FPCR_DYN_MASK;
7250
7251 /* Copied from linux ieee_swcr_to_fpcr. */
7252 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7253 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7254 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7255 | SWCR_TRAP_ENABLE_DZE
7256 | SWCR_TRAP_ENABLE_OVF)) << 48;
7257 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7258 | SWCR_TRAP_ENABLE_INE)) << 57;
7259 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7260 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7261
7262 cpu_alpha_store_fpcr (cpu_env, fpcr);
7263 ret = 0;
7264
7265 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7266 /* Old exceptions are not signaled. */
7267 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7268
7269 /* If any exceptions set by this call, and are unmasked,
7270 send a signal. */
7271 /* ??? FIXME */
7272 }
7273 }
7274 break;
7275
7276 /* case SSI_NVPAIRS:
7277 -- Used with SSIN_UACPROC to enable unaligned accesses.
7278 case SSI_IEEE_STATE_AT_SIGNAL:
7279 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7280 -- Not implemented in linux kernel
7281 */
7282 }
7283 break;
7284#endif
7285#ifdef TARGET_NR_osf_sigprocmask
7286 /* Alpha specific. */
7287 case TARGET_NR_osf_sigprocmask:
7288 {
7289 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007290 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007291 sigset_t set, oldset;
7292
7293 switch(arg1) {
7294 case TARGET_SIG_BLOCK:
7295 how = SIG_BLOCK;
7296 break;
7297 case TARGET_SIG_UNBLOCK:
7298 how = SIG_UNBLOCK;
7299 break;
7300 case TARGET_SIG_SETMASK:
7301 how = SIG_SETMASK;
7302 break;
7303 default:
7304 ret = -TARGET_EINVAL;
7305 goto fail;
7306 }
7307 mask = arg2;
7308 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007309 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007310 host_to_target_old_sigset(&mask, &oldset);
7311 ret = mask;
7312 }
7313 break;
7314#endif
aurel3264b4d282008-11-14 17:20:15 +00007315
bellarda315a142005-01-30 22:59:18 +00007316#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007317 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007318 ret = get_errno(getgid());
7319 break;
bellarda315a142005-01-30 22:59:18 +00007320#endif
7321#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007322 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007323 ret = get_errno(geteuid());
7324 break;
bellarda315a142005-01-30 22:59:18 +00007325#endif
7326#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007327 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007328 ret = get_errno(getegid());
7329 break;
bellarda315a142005-01-30 22:59:18 +00007330#endif
7331#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007332 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007333 ret = get_errno(setreuid(arg1, arg2));
7334 break;
bellarda315a142005-01-30 22:59:18 +00007335#endif
7336#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007337 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007338 ret = get_errno(setregid(arg1, arg2));
7339 break;
bellarda315a142005-01-30 22:59:18 +00007340#endif
7341#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007342 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007343 {
7344 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007345 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007346 gid_t *grouplist;
7347 int i;
7348
7349 grouplist = alloca(gidsetsize * sizeof(gid_t));
7350 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007351 if (gidsetsize == 0)
7352 break;
bellard99c475a2005-01-31 20:45:13 +00007353 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007354 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7355 if (!target_grouplist) {
7356 ret = -TARGET_EFAULT;
7357 goto fail;
7358 }
balroga2155fc2008-09-20 02:12:08 +00007359 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007360 target_grouplist[i] = tswap32(grouplist[i]);
7361 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007362 }
7363 }
7364 break;
bellarda315a142005-01-30 22:59:18 +00007365#endif
7366#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007367 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007368 {
7369 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007370 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007371 gid_t *grouplist;
7372 int i;
ths3b46e622007-09-17 08:09:54 +00007373
bellard99c475a2005-01-31 20:45:13 +00007374 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007375 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7376 if (!target_grouplist) {
7377 ret = -TARGET_EFAULT;
7378 goto fail;
7379 }
bellard99c475a2005-01-31 20:45:13 +00007380 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007381 grouplist[i] = tswap32(target_grouplist[i]);
7382 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007383 ret = get_errno(setgroups(gidsetsize, grouplist));
7384 }
7385 break;
bellarda315a142005-01-30 22:59:18 +00007386#endif
7387#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007388 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007389 ret = get_errno(fchown(arg1, arg2, arg3));
7390 break;
bellarda315a142005-01-30 22:59:18 +00007391#endif
7392#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007393 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007394 ret = get_errno(setresuid(arg1, arg2, arg3));
7395 break;
bellarda315a142005-01-30 22:59:18 +00007396#endif
7397#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007398 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007399 {
pbrook53a59602006-03-25 19:31:22 +00007400 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007401 ret = get_errno(getresuid(&ruid, &euid, &suid));
7402 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007403 if (put_user_u32(ruid, arg1)
7404 || put_user_u32(euid, arg2)
7405 || put_user_u32(suid, arg3))
7406 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007407 }
7408 }
7409 break;
bellarda315a142005-01-30 22:59:18 +00007410#endif
7411#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007412 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007413 ret = get_errno(setresgid(arg1, arg2, arg3));
7414 break;
bellarda315a142005-01-30 22:59:18 +00007415#endif
7416#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007417 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007418 {
pbrook53a59602006-03-25 19:31:22 +00007419 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007420 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7421 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007422 if (put_user_u32(rgid, arg1)
7423 || put_user_u32(egid, arg2)
7424 || put_user_u32(sgid, arg3))
7425 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007426 }
7427 }
7428 break;
bellarda315a142005-01-30 22:59:18 +00007429#endif
7430#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007431 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007432 if (!(p = lock_user_string(arg1)))
7433 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007434 ret = get_errno(chown(p, arg2, arg3));
7435 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007436 break;
bellarda315a142005-01-30 22:59:18 +00007437#endif
7438#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007439 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007440 ret = get_errno(setuid(arg1));
7441 break;
bellarda315a142005-01-30 22:59:18 +00007442#endif
7443#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007444 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007445 ret = get_errno(setgid(arg1));
7446 break;
bellarda315a142005-01-30 22:59:18 +00007447#endif
7448#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007449 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007450 ret = get_errno(setfsuid(arg1));
7451 break;
bellarda315a142005-01-30 22:59:18 +00007452#endif
7453#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007454 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007455 ret = get_errno(setfsgid(arg1));
7456 break;
bellarda315a142005-01-30 22:59:18 +00007457#endif
bellard67867302003-11-23 17:05:30 +00007458
bellard31e31b82003-02-18 22:55:36 +00007459 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007460 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007461#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007462 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007463 {
7464 void *a;
7465 ret = -TARGET_EFAULT;
7466 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7467 goto efault;
7468 if (!(p = lock_user_string(arg3)))
7469 goto mincore_fail;
7470 ret = get_errno(mincore(a, arg2, p));
7471 unlock_user(p, arg3, ret);
7472 mincore_fail:
7473 unlock_user(a, arg1, 0);
7474 }
7475 break;
bellardffa65c32004-01-04 23:57:22 +00007476#endif
aurel32408321b2008-10-01 21:46:32 +00007477#ifdef TARGET_NR_arm_fadvise64_64
7478 case TARGET_NR_arm_fadvise64_64:
7479 {
7480 /*
7481 * arm_fadvise64_64 looks like fadvise64_64 but
7482 * with different argument order
7483 */
7484 abi_long temp;
7485 temp = arg3;
7486 arg3 = arg4;
7487 arg4 = temp;
7488 }
7489#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007490#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007491#ifdef TARGET_NR_fadvise64_64
7492 case TARGET_NR_fadvise64_64:
7493#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007494#ifdef TARGET_NR_fadvise64
7495 case TARGET_NR_fadvise64:
7496#endif
7497#ifdef TARGET_S390X
7498 switch (arg4) {
7499 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7500 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7501 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7502 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7503 default: break;
7504 }
7505#endif
7506 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007507 break;
7508#endif
bellardffa65c32004-01-04 23:57:22 +00007509#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007510 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007511 /* A straight passthrough may not be safe because qemu sometimes
7512 turns private flie-backed mappings into anonymous mappings.
7513 This will break MADV_DONTNEED.
7514 This is a hint, so ignoring and returning success is ok. */
7515 ret = get_errno(0);
7516 break;
bellardffa65c32004-01-04 23:57:22 +00007517#endif
blueswir1992f48a2007-10-14 16:27:31 +00007518#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007519 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007520 {
thsb1e341e2007-03-20 21:50:52 +00007521 int cmd;
bellard77e46722003-04-29 20:39:06 +00007522 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007523 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007524#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007525 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007526#endif
bellard77e46722003-04-29 20:39:06 +00007527
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007528 cmd = target_to_host_fcntl_cmd(arg2);
7529 if (cmd == -TARGET_EINVAL)
7530 return cmd;
thsb1e341e2007-03-20 21:50:52 +00007531
bellard60cd49d2003-03-16 22:53:56 +00007532 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007533 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007534#ifdef TARGET_ARM
7535 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007536 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7537 goto efault;
ths58134272007-03-31 18:59:32 +00007538 fl.l_type = tswap16(target_efl->l_type);
7539 fl.l_whence = tswap16(target_efl->l_whence);
7540 fl.l_start = tswap64(target_efl->l_start);
7541 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007542 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007543 unlock_user_struct(target_efl, arg3, 0);
7544 } else
7545#endif
7546 {
bellard9ee1fa22007-11-11 15:11:19 +00007547 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7548 goto efault;
ths58134272007-03-31 18:59:32 +00007549 fl.l_type = tswap16(target_fl->l_type);
7550 fl.l_whence = tswap16(target_fl->l_whence);
7551 fl.l_start = tswap64(target_fl->l_start);
7552 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007553 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007554 unlock_user_struct(target_fl, arg3, 0);
7555 }
thsb1e341e2007-03-20 21:50:52 +00007556 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007557 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007558#ifdef TARGET_ARM
7559 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007560 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7561 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007562 target_efl->l_type = tswap16(fl.l_type);
7563 target_efl->l_whence = tswap16(fl.l_whence);
7564 target_efl->l_start = tswap64(fl.l_start);
7565 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007566 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007567 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007568 } else
7569#endif
7570 {
bellard9ee1fa22007-11-11 15:11:19 +00007571 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7572 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007573 target_fl->l_type = tswap16(fl.l_type);
7574 target_fl->l_whence = tswap16(fl.l_whence);
7575 target_fl->l_start = tswap64(fl.l_start);
7576 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007577 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007578 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007579 }
bellard77e46722003-04-29 20:39:06 +00007580 }
7581 break;
7582
thsb1e341e2007-03-20 21:50:52 +00007583 case TARGET_F_SETLK64:
7584 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00007585#ifdef TARGET_ARM
7586 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007587 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7588 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007589 fl.l_type = tswap16(target_efl->l_type);
7590 fl.l_whence = tswap16(target_efl->l_whence);
7591 fl.l_start = tswap64(target_efl->l_start);
7592 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007593 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007594 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007595 } else
7596#endif
7597 {
bellard9ee1fa22007-11-11 15:11:19 +00007598 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7599 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007600 fl.l_type = tswap16(target_fl->l_type);
7601 fl.l_whence = tswap16(target_fl->l_whence);
7602 fl.l_start = tswap64(target_fl->l_start);
7603 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007604 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007605 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007606 }
thsb1e341e2007-03-20 21:50:52 +00007607 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007608 break;
bellard60cd49d2003-03-16 22:53:56 +00007609 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007610 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00007611 break;
7612 }
bellard77e46722003-04-29 20:39:06 +00007613 break;
7614 }
bellard60cd49d2003-03-16 22:53:56 +00007615#endif
ths7d600c82006-12-08 01:32:58 +00007616#ifdef TARGET_NR_cacheflush
7617 case TARGET_NR_cacheflush:
7618 /* self-modifying code is handled automatically, so nothing needed */
7619 ret = 0;
7620 break;
7621#endif
bellardebc05482003-09-30 21:08:41 +00007622#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00007623 case TARGET_NR_security:
7624 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007625#endif
bellardc573ff62004-01-04 15:51:36 +00007626#ifdef TARGET_NR_getpagesize
7627 case TARGET_NR_getpagesize:
7628 ret = TARGET_PAGE_SIZE;
7629 break;
7630#endif
bellard31e31b82003-02-18 22:55:36 +00007631 case TARGET_NR_gettid:
7632 ret = get_errno(gettid());
7633 break;
thse5febef2007-04-01 18:31:35 +00007634#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00007635 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00007636#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03007637 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00007638 arg2 = arg3;
7639 arg3 = arg4;
7640 arg4 = arg5;
7641 }
aurel322054ac92008-10-13 21:08:07 +00007642 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
7643#else
7644 ret = get_errno(readahead(arg1, arg2, arg3));
7645#endif
7646 break;
thse5febef2007-04-01 18:31:35 +00007647#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007648#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00007649#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00007650 case TARGET_NR_lsetxattr:
7651 case TARGET_NR_fsetxattr:
bellard31e31b82003-02-18 22:55:36 +00007652 case TARGET_NR_lgetxattr:
7653 case TARGET_NR_fgetxattr:
7654 case TARGET_NR_listxattr:
7655 case TARGET_NR_llistxattr:
7656 case TARGET_NR_flistxattr:
bellard31e31b82003-02-18 22:55:36 +00007657 case TARGET_NR_lremovexattr:
7658 case TARGET_NR_fremovexattr:
Arnaud Patard6f932f92009-04-21 21:04:18 +03007659 ret = -TARGET_EOPNOTSUPP;
7660 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007661 case TARGET_NR_setxattr:
7662 {
7663 void *p, *n, *v;
7664 p = lock_user_string(arg1);
7665 n = lock_user_string(arg2);
7666 v = lock_user(VERIFY_READ, arg3, arg4, 1);
7667 if (p && n && v) {
7668 ret = get_errno(setxattr(p, n, v, arg4, arg5));
7669 } else {
7670 ret = -TARGET_EFAULT;
7671 }
7672 unlock_user(p, arg1, 0);
7673 unlock_user(n, arg2, 0);
7674 unlock_user(v, arg3, 0);
7675 }
7676 break;
7677 case TARGET_NR_getxattr:
7678 {
7679 void *p, *n, *v;
7680 p = lock_user_string(arg1);
7681 n = lock_user_string(arg2);
7682 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
7683 if (p && n && v) {
7684 ret = get_errno(getxattr(p, n, v, arg4));
7685 } else {
7686 ret = -TARGET_EFAULT;
7687 }
7688 unlock_user(p, arg1, 0);
7689 unlock_user(n, arg2, 0);
7690 unlock_user(v, arg3, arg4);
7691 }
7692 break;
7693 case TARGET_NR_removexattr:
7694 {
7695 void *p, *n;
7696 p = lock_user_string(arg1);
7697 n = lock_user_string(arg2);
7698 if (p && n) {
7699 ret = get_errno(removexattr(p, n));
7700 } else {
7701 ret = -TARGET_EFAULT;
7702 }
7703 unlock_user(p, arg1, 0);
7704 unlock_user(n, arg2, 0);
7705 }
7706 break;
bellardebc05482003-09-30 21:08:41 +00007707#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007708#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00007709#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00007710 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007711#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00007712 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
7713 ret = 0;
7714 break;
edgar_iglef967792009-01-07 14:19:38 +00007715#elif defined(TARGET_CRIS)
7716 if (arg1 & 0xff)
7717 ret = -TARGET_EINVAL;
7718 else {
7719 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
7720 ret = 0;
7721 }
7722 break;
bellard8d18e892007-11-14 15:18:40 +00007723#elif defined(TARGET_I386) && defined(TARGET_ABI32)
7724 ret = do_set_thread_area(cpu_env, arg1);
7725 break;
ths6f5b89a2007-03-02 20:48:00 +00007726#else
7727 goto unimplemented_nowarn;
7728#endif
7729#endif
7730#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00007731 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007732#if defined(TARGET_I386) && defined(TARGET_ABI32)
7733 ret = do_get_thread_area(cpu_env, arg1);
7734#else
bellard5cd43932003-03-29 16:54:36 +00007735 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00007736#endif
bellard8d18e892007-11-14 15:18:40 +00007737#endif
bellard48dc41e2006-06-21 18:15:50 +00007738#ifdef TARGET_NR_getdomainname
7739 case TARGET_NR_getdomainname:
7740 goto unimplemented_nowarn;
7741#endif
ths6f5b89a2007-03-02 20:48:00 +00007742
thsb5906f92007-03-19 13:32:45 +00007743#ifdef TARGET_NR_clock_gettime
7744 case TARGET_NR_clock_gettime:
7745 {
7746 struct timespec ts;
7747 ret = get_errno(clock_gettime(arg1, &ts));
7748 if (!is_error(ret)) {
7749 host_to_target_timespec(arg2, &ts);
7750 }
7751 break;
7752 }
7753#endif
7754#ifdef TARGET_NR_clock_getres
7755 case TARGET_NR_clock_getres:
7756 {
7757 struct timespec ts;
7758 ret = get_errno(clock_getres(arg1, &ts));
7759 if (!is_error(ret)) {
7760 host_to_target_timespec(arg2, &ts);
7761 }
7762 break;
7763 }
7764#endif
pbrook63d76512008-05-29 13:43:29 +00007765#ifdef TARGET_NR_clock_nanosleep
7766 case TARGET_NR_clock_nanosleep:
7767 {
7768 struct timespec ts;
7769 target_to_host_timespec(&ts, arg3);
7770 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
7771 if (arg4)
7772 host_to_target_timespec(arg4, &ts);
7773 break;
7774 }
7775#endif
thsb5906f92007-03-19 13:32:45 +00007776
ths6f5b89a2007-03-02 20:48:00 +00007777#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
7778 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00007779 ret = get_errno(set_tid_address((int *)g2h(arg1)));
7780 break;
ths6f5b89a2007-03-02 20:48:00 +00007781#endif
7782
ths3ae43202007-09-16 21:39:48 +00007783#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00007784 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00007785 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00007786 break;
7787#endif
7788
ths3ae43202007-09-16 21:39:48 +00007789#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00007790 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00007791 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
7792 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00007793 break;
7794#endif
7795
ths4f2b1fe2007-06-21 21:57:12 +00007796#ifdef TARGET_NR_set_robust_list
7797 case TARGET_NR_set_robust_list:
7798 goto unimplemented_nowarn;
7799#endif
7800
ths9007f0e2007-09-25 17:50:37 +00007801#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
7802 case TARGET_NR_utimensat:
7803 {
Riku Voipioebc996f2009-04-21 15:01:51 +03007804 struct timespec *tsp, ts[2];
7805 if (!arg3) {
7806 tsp = NULL;
7807 } else {
7808 target_to_host_timespec(ts, arg3);
7809 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
7810 tsp = ts;
7811 }
ths9007f0e2007-09-25 17:50:37 +00007812 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03007813 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00007814 else {
bellard579a97f2007-11-11 14:26:47 +00007815 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00007816 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00007817 goto fail;
7818 }
Riku Voipioebc996f2009-04-21 15:01:51 +03007819 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00007820 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00007821 }
7822 }
7823 break;
7824#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02007825#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00007826 case TARGET_NR_futex:
7827 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
7828 break;
7829#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007830#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00007831 case TARGET_NR_inotify_init:
7832 ret = get_errno(sys_inotify_init());
7833 break;
7834#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007835#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00007836#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
7837 case TARGET_NR_inotify_init1:
7838 ret = get_errno(sys_inotify_init1(arg1));
7839 break;
7840#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007841#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007842#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00007843 case TARGET_NR_inotify_add_watch:
7844 p = lock_user_string(arg2);
7845 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
7846 unlock_user(p, arg2, 0);
7847 break;
7848#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007849#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00007850 case TARGET_NR_inotify_rm_watch:
7851 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
7852 break;
7853#endif
ths9007f0e2007-09-25 17:50:37 +00007854
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07007855#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00007856 case TARGET_NR_mq_open:
7857 {
7858 struct mq_attr posix_mq_attr;
7859
7860 p = lock_user_string(arg1 - 1);
7861 if (arg4 != 0)
7862 copy_from_user_mq_attr (&posix_mq_attr, arg4);
7863 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
7864 unlock_user (p, arg1, 0);
7865 }
7866 break;
7867
7868 case TARGET_NR_mq_unlink:
7869 p = lock_user_string(arg1 - 1);
7870 ret = get_errno(mq_unlink(p));
7871 unlock_user (p, arg1, 0);
7872 break;
7873
7874 case TARGET_NR_mq_timedsend:
7875 {
7876 struct timespec ts;
7877
7878 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7879 if (arg5 != 0) {
7880 target_to_host_timespec(&ts, arg5);
7881 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
7882 host_to_target_timespec(arg5, &ts);
7883 }
7884 else
7885 ret = get_errno(mq_send(arg1, p, arg3, arg4));
7886 unlock_user (p, arg2, arg3);
7887 }
7888 break;
7889
7890 case TARGET_NR_mq_timedreceive:
7891 {
7892 struct timespec ts;
7893 unsigned int prio;
7894
7895 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7896 if (arg5 != 0) {
7897 target_to_host_timespec(&ts, arg5);
7898 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
7899 host_to_target_timespec(arg5, &ts);
7900 }
7901 else
7902 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
7903 unlock_user (p, arg2, arg3);
7904 if (arg4 != 0)
7905 put_user_u32(prio, arg4);
7906 }
7907 break;
7908
7909 /* Not implemented for now... */
7910/* case TARGET_NR_mq_notify: */
7911/* break; */
7912
7913 case TARGET_NR_mq_getsetattr:
7914 {
7915 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
7916 ret = 0;
7917 if (arg3 != 0) {
7918 ret = mq_getattr(arg1, &posix_mq_attr_out);
7919 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
7920 }
7921 if (arg2 != 0) {
7922 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
7923 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
7924 }
7925
7926 }
7927 break;
7928#endif
7929
vibisreenivasan3ce34df2009-05-16 18:32:41 +05307930#ifdef CONFIG_SPLICE
7931#ifdef TARGET_NR_tee
7932 case TARGET_NR_tee:
7933 {
7934 ret = get_errno(tee(arg1,arg2,arg3,arg4));
7935 }
7936 break;
7937#endif
7938#ifdef TARGET_NR_splice
7939 case TARGET_NR_splice:
7940 {
7941 loff_t loff_in, loff_out;
7942 loff_t *ploff_in = NULL, *ploff_out = NULL;
7943 if(arg2) {
7944 get_user_u64(loff_in, arg2);
7945 ploff_in = &loff_in;
7946 }
7947 if(arg4) {
7948 get_user_u64(loff_out, arg2);
7949 ploff_out = &loff_out;
7950 }
7951 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
7952 }
7953 break;
7954#endif
7955#ifdef TARGET_NR_vmsplice
7956 case TARGET_NR_vmsplice:
7957 {
7958 int count = arg3;
7959 struct iovec *vec;
7960
7961 vec = alloca(count * sizeof(struct iovec));
7962 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7963 goto efault;
7964 ret = get_errno(vmsplice(arg1, vec, count, arg4));
7965 unlock_iovec(vec, arg2, count, 0);
7966 }
7967 break;
7968#endif
7969#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03007970#ifdef CONFIG_EVENTFD
7971#if defined(TARGET_NR_eventfd)
7972 case TARGET_NR_eventfd:
7973 ret = get_errno(eventfd(arg1, 0));
7974 break;
7975#endif
7976#if defined(TARGET_NR_eventfd2)
7977 case TARGET_NR_eventfd2:
7978 ret = get_errno(eventfd(arg1, arg2));
7979 break;
7980#endif
7981#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03007982#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
7983 case TARGET_NR_fallocate:
7984 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
7985 break;
7986#endif
Peter Maydellc727f472011-01-06 11:05:10 +00007987#if defined(CONFIG_SYNC_FILE_RANGE)
7988#if defined(TARGET_NR_sync_file_range)
7989 case TARGET_NR_sync_file_range:
7990#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03007991#if defined(TARGET_MIPS)
7992 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7993 target_offset64(arg5, arg6), arg7));
7994#else
Peter Maydellc727f472011-01-06 11:05:10 +00007995 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
7996 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03007997#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00007998#else
7999 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8000#endif
8001 break;
8002#endif
8003#if defined(TARGET_NR_sync_file_range2)
8004 case TARGET_NR_sync_file_range2:
8005 /* This is like sync_file_range but the arguments are reordered */
8006#if TARGET_ABI_BITS == 32
8007 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8008 target_offset64(arg5, arg6), arg2));
8009#else
8010 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8011#endif
8012 break;
8013#endif
8014#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008015#if defined(CONFIG_EPOLL)
8016#if defined(TARGET_NR_epoll_create)
8017 case TARGET_NR_epoll_create:
8018 ret = get_errno(epoll_create(arg1));
8019 break;
8020#endif
8021#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8022 case TARGET_NR_epoll_create1:
8023 ret = get_errno(epoll_create1(arg1));
8024 break;
8025#endif
8026#if defined(TARGET_NR_epoll_ctl)
8027 case TARGET_NR_epoll_ctl:
8028 {
8029 struct epoll_event ep;
8030 struct epoll_event *epp = 0;
8031 if (arg4) {
8032 struct target_epoll_event *target_ep;
8033 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8034 goto efault;
8035 }
8036 ep.events = tswap32(target_ep->events);
8037 /* The epoll_data_t union is just opaque data to the kernel,
8038 * so we transfer all 64 bits across and need not worry what
8039 * actual data type it is.
8040 */
8041 ep.data.u64 = tswap64(target_ep->data.u64);
8042 unlock_user_struct(target_ep, arg4, 0);
8043 epp = &ep;
8044 }
8045 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8046 break;
8047 }
8048#endif
8049
8050#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8051#define IMPLEMENT_EPOLL_PWAIT
8052#endif
8053#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8054#if defined(TARGET_NR_epoll_wait)
8055 case TARGET_NR_epoll_wait:
8056#endif
8057#if defined(IMPLEMENT_EPOLL_PWAIT)
8058 case TARGET_NR_epoll_pwait:
8059#endif
8060 {
8061 struct target_epoll_event *target_ep;
8062 struct epoll_event *ep;
8063 int epfd = arg1;
8064 int maxevents = arg3;
8065 int timeout = arg4;
8066
8067 target_ep = lock_user(VERIFY_WRITE, arg2,
8068 maxevents * sizeof(struct target_epoll_event), 1);
8069 if (!target_ep) {
8070 goto efault;
8071 }
8072
8073 ep = alloca(maxevents * sizeof(struct epoll_event));
8074
8075 switch (num) {
8076#if defined(IMPLEMENT_EPOLL_PWAIT)
8077 case TARGET_NR_epoll_pwait:
8078 {
8079 target_sigset_t *target_set;
8080 sigset_t _set, *set = &_set;
8081
8082 if (arg5) {
8083 target_set = lock_user(VERIFY_READ, arg5,
8084 sizeof(target_sigset_t), 1);
8085 if (!target_set) {
8086 unlock_user(target_ep, arg2, 0);
8087 goto efault;
8088 }
8089 target_to_host_sigset(set, target_set);
8090 unlock_user(target_set, arg5, 0);
8091 } else {
8092 set = NULL;
8093 }
8094
8095 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8096 break;
8097 }
8098#endif
8099#if defined(TARGET_NR_epoll_wait)
8100 case TARGET_NR_epoll_wait:
8101 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8102 break;
8103#endif
8104 default:
8105 ret = -TARGET_ENOSYS;
8106 }
8107 if (!is_error(ret)) {
8108 int i;
8109 for (i = 0; i < ret; i++) {
8110 target_ep[i].events = tswap32(ep[i].events);
8111 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8112 }
8113 }
8114 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8115 break;
8116 }
8117#endif
8118#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008119#ifdef TARGET_NR_prlimit64
8120 case TARGET_NR_prlimit64:
8121 {
8122 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8123 struct target_rlimit64 *target_rnew, *target_rold;
8124 struct host_rlimit64 rnew, rold, *rnewp = 0;
8125 if (arg3) {
8126 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8127 goto efault;
8128 }
8129 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8130 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8131 unlock_user_struct(target_rnew, arg3, 0);
8132 rnewp = &rnew;
8133 }
8134
8135 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8136 if (!is_error(ret) && arg4) {
8137 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8138 goto efault;
8139 }
8140 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8141 target_rold->rlim_max = tswap64(rold.rlim_max);
8142 unlock_user_struct(target_rold, arg4, 1);
8143 }
8144 break;
8145 }
8146#endif
bellard31e31b82003-02-18 22:55:36 +00008147 default:
8148 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008149 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008150#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 +00008151 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008152#endif
ths0da46a62007-10-20 20:23:07 +00008153 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008154 break;
8155 }
bellard579a97f2007-11-11 14:26:47 +00008156fail:
bellardc573ff62004-01-04 15:51:36 +00008157#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008158 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008159#endif
thsb92c47c2007-11-01 00:07:38 +00008160 if(do_strace)
8161 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008162 return ret;
bellard579a97f2007-11-11 14:26:47 +00008163efault:
8164 ret = -TARGET_EFAULT;
8165 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008166}