blob: 712861829abf812af0ea218c1e4d564e8f88587c [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>
Stefan Weil5a61cb62011-09-08 17:55:32 +020063#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
Avi Kivity4f26f2b2011-11-09 14:44:52 +020074#include "qemu-xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070075#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>
Alexander Graf56e904e2012-01-31 18:42:06 +010098#include <linux/dm-ioctl.h>
pbrookd7e40362008-05-23 16:06:43 +000099#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100100#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000101
bellard3ef693a2003-03-23 20:17:16 +0000102#include "qemu.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);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200252_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
253 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000254
255static bitmask_transtbl fcntl_flags_tbl[] = {
256 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
257 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
258 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
259 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
260 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
261 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
262 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
263 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
264 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
265 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
266 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
267 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
268 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
269#if defined(O_DIRECT)
270 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
271#endif
272 { 0, 0, 0, 0 }
273};
274
275#define COPY_UTSNAME_FIELD(dest, src) \
276 do { \
277 /* __NEW_UTS_LEN doesn't include terminating null */ \
278 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
279 (dest)[__NEW_UTS_LEN] = '\0'; \
280 } while (0)
281
282static int sys_uname(struct new_utsname *buf)
283{
284 struct utsname uts_buf;
285
286 if (uname(&uts_buf) < 0)
287 return (-1);
288
289 /*
290 * Just in case these have some differences, we
291 * translate utsname to new_utsname (which is the
292 * struct linux kernel uses).
293 */
294
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200295 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000296 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
297 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
298 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
299 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
300 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
301#ifdef _GNU_SOURCE
302 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
303#endif
304 return (0);
305
306#undef COPY_UTSNAME_FIELD
307}
308
309static int sys_getcwd1(char *buf, size_t size)
310{
311 if (getcwd(buf, size) == NULL) {
312 /* getcwd() sets errno */
313 return (-1);
314 }
aurel32aaf4ad32009-04-16 14:17:14 +0000315 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000316}
317
318#ifdef CONFIG_ATFILE
319/*
320 * Host system seems to have atfile syscall stubs available. We
321 * now enable them one by one as specified by target syscall_nr.h.
322 */
323
324#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000325static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000326{
aurel32465c9f02009-04-19 08:52:17 +0000327 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000328}
329#endif
330#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000331static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000332{
aurel32465c9f02009-04-19 08:52:17 +0000333 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000334}
335#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300336#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000337static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
338 gid_t group, int flags)
339{
340 return (fchownat(dirfd, pathname, owner, group, flags));
341}
342#endif
343#ifdef __NR_fstatat64
344static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
345 int flags)
346{
347 return (fstatat(dirfd, pathname, buf, flags));
348}
349#endif
350#ifdef __NR_newfstatat
351static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
352 int flags)
353{
354 return (fstatat(dirfd, pathname, buf, flags));
355}
356#endif
357#ifdef TARGET_NR_futimesat
358static int sys_futimesat(int dirfd, const char *pathname,
359 const struct timeval times[2])
360{
361 return (futimesat(dirfd, pathname, times));
362}
363#endif
364#ifdef TARGET_NR_linkat
365static int sys_linkat(int olddirfd, const char *oldpath,
366 int newdirfd, const char *newpath, int flags)
367{
368 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
369}
370#endif
371#ifdef TARGET_NR_mkdirat
372static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
373{
374 return (mkdirat(dirfd, pathname, mode));
375}
376#endif
377#ifdef TARGET_NR_mknodat
378static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
379 dev_t dev)
380{
381 return (mknodat(dirfd, pathname, mode, dev));
382}
383#endif
384#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200385static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000386{
387 /*
388 * open(2) has extra parameter 'mode' when called with
389 * flag O_CREAT.
390 */
391 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000392 return (openat(dirfd, pathname, flags, mode));
393 }
394 return (openat(dirfd, pathname, flags));
395}
396#endif
397#ifdef TARGET_NR_readlinkat
398static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
399{
400 return (readlinkat(dirfd, pathname, buf, bufsiz));
401}
402#endif
403#ifdef TARGET_NR_renameat
404static int sys_renameat(int olddirfd, const char *oldpath,
405 int newdirfd, const char *newpath)
406{
407 return (renameat(olddirfd, oldpath, newdirfd, newpath));
408}
409#endif
410#ifdef TARGET_NR_symlinkat
411static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
412{
413 return (symlinkat(oldpath, newdirfd, newpath));
414}
415#endif
416#ifdef TARGET_NR_unlinkat
417static int sys_unlinkat(int dirfd, const char *pathname, int flags)
418{
419 return (unlinkat(dirfd, pathname, flags));
420}
421#endif
aurel323b3f24a2009-04-15 16:12:13 +0000422#else /* !CONFIG_ATFILE */
423
424/*
425 * Try direct syscalls instead
426 */
ths92a34c12007-09-24 09:27:49 +0000427#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000428_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000429#endif
ths814d7972007-09-24 09:26:51 +0000430#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000431_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000432#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300433#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000434_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
435 uid_t,owner,gid_t,group,int,flags)
436#endif
aurel329d33b762009-04-08 23:07:05 +0000437#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
438 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000439_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
440 struct stat *,buf,int,flags)
441#endif
balrogac8a6552008-09-20 02:25:39 +0000442#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
443_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
444 const struct timeval *,times)
445#endif
aurel323b3f24a2009-04-15 16:12:13 +0000446#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
447 defined(__NR_newfstatat)
448_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
449 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000450#endif
ths64f0ce42007-09-24 09:25:06 +0000451#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
452_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000453 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000454#endif
ths4472ad02007-09-24 09:22:32 +0000455#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
456_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
457#endif
ths75ac37a2007-09-24 09:23:05 +0000458#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
459_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
460 mode_t,mode,dev_t,dev)
461#endif
ths82424832007-09-24 09:21:55 +0000462#if defined(TARGET_NR_openat) && defined(__NR_openat)
463_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
464#endif
ths5e0ccb12007-09-24 09:26:10 +0000465#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
466_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
467 char *,buf,size_t,bufsize)
468#endif
ths722183f2007-09-24 09:24:37 +0000469#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
470_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
471 int,newdirfd,const char *,newpath)
472#endif
thsb51eaa82007-09-25 16:09:22 +0000473#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000474_syscall3(int,sys_symlinkat,const char *,oldpath,
475 int,newdirfd,const char *,newpath)
476#endif
ths8170f562007-09-24 09:24:11 +0000477#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
478_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
479#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300480
481#endif /* CONFIG_ATFILE */
482
483#ifdef CONFIG_UTIMENSAT
484static int sys_utimensat(int dirfd, const char *pathname,
485 const struct timespec times[2], int flags)
486{
487 if (pathname == NULL)
488 return futimens(dirfd, times);
489 else
490 return utimensat(dirfd, pathname, times, flags);
491}
492#else
ths9007f0e2007-09-25 17:50:37 +0000493#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
494_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
495 const struct timespec *,tsp,int,flags)
496#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300497#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000498
499#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000500#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000501
aurel3239b59762008-10-01 21:46:50 +0000502#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000503static int sys_inotify_init(void)
504{
505 return (inotify_init());
506}
aurel3239b59762008-10-01 21:46:50 +0000507#endif
508#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000509static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
510{
511 return (inotify_add_watch(fd, pathname, mask));
512}
aurel3239b59762008-10-01 21:46:50 +0000513#endif
514#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000515static int sys_inotify_rm_watch(int fd, int32_t wd)
516{
aurel328690e422009-04-17 13:50:32 +0000517 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000518}
aurel3239b59762008-10-01 21:46:50 +0000519#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000520#ifdef CONFIG_INOTIFY1
521#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
522static int sys_inotify_init1(int flags)
523{
524 return (inotify_init1(flags));
525}
526#endif
527#endif
aurel323b3f24a2009-04-15 16:12:13 +0000528#else
529/* Userspace can usually survive runtime without inotify */
530#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000531#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000532#undef TARGET_NR_inotify_add_watch
533#undef TARGET_NR_inotify_rm_watch
534#endif /* CONFIG_INOTIFY */
535
Mike Frysingerd8035d42011-02-07 01:05:51 -0500536#if defined(TARGET_NR_ppoll)
537#ifndef __NR_ppoll
538# define __NR_ppoll -1
539#endif
540#define __NR_sys_ppoll __NR_ppoll
541_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
542 struct timespec *, timeout, const __sigset_t *, sigmask,
543 size_t, sigsetsize)
544#endif
bellard66fb9762003-03-23 01:06:05 +0000545
Mike Frysinger055e0902011-06-03 17:01:49 -0400546#if defined(TARGET_NR_pselect6)
547#ifndef __NR_pselect6
548# define __NR_pselect6 -1
549#endif
550#define __NR_sys_pselect6 __NR_pselect6
551_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
552 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
553#endif
554
Peter Maydell163a05a2011-06-27 17:44:52 +0100555#if defined(TARGET_NR_prlimit64)
556#ifndef __NR_prlimit64
557# define __NR_prlimit64 -1
558#endif
559#define __NR_sys_prlimit64 __NR_prlimit64
560/* The glibc rlimit structure may not be that used by the underlying syscall */
561struct host_rlimit64 {
562 uint64_t rlim_cur;
563 uint64_t rlim_max;
564};
565_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
566 const struct host_rlimit64 *, new_limit,
567 struct host_rlimit64 *, old_limit)
568#endif
569
bellard66fb9762003-03-23 01:06:05 +0000570extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000571extern int flock(int, int);
572extern int setfsuid(int);
573extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000574extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000575
Riku Voipio48e515d2011-07-12 15:40:51 +0300576/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
577#ifdef TARGET_ARM
578static inline int regpairs_aligned(void *cpu_env) {
579 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
580}
581#elif defined(TARGET_MIPS)
582static inline int regpairs_aligned(void *cpu_env) { return 1; }
583#else
584static inline int regpairs_aligned(void *cpu_env) { return 0; }
585#endif
586
thsb92c47c2007-11-01 00:07:38 +0000587#define ERRNO_TABLE_SIZE 1200
588
589/* target_to_host_errno_table[] is initialized from
590 * host_to_target_errno_table[] in syscall_init(). */
591static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
592};
593
ths637947f2007-06-01 12:09:19 +0000594/*
thsfe8f0962007-07-12 10:59:21 +0000595 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000596 * minus the errnos that are not actually generic to all archs.
597 */
thsb92c47c2007-11-01 00:07:38 +0000598static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000599 [EIDRM] = TARGET_EIDRM,
600 [ECHRNG] = TARGET_ECHRNG,
601 [EL2NSYNC] = TARGET_EL2NSYNC,
602 [EL3HLT] = TARGET_EL3HLT,
603 [EL3RST] = TARGET_EL3RST,
604 [ELNRNG] = TARGET_ELNRNG,
605 [EUNATCH] = TARGET_EUNATCH,
606 [ENOCSI] = TARGET_ENOCSI,
607 [EL2HLT] = TARGET_EL2HLT,
608 [EDEADLK] = TARGET_EDEADLK,
609 [ENOLCK] = TARGET_ENOLCK,
610 [EBADE] = TARGET_EBADE,
611 [EBADR] = TARGET_EBADR,
612 [EXFULL] = TARGET_EXFULL,
613 [ENOANO] = TARGET_ENOANO,
614 [EBADRQC] = TARGET_EBADRQC,
615 [EBADSLT] = TARGET_EBADSLT,
616 [EBFONT] = TARGET_EBFONT,
617 [ENOSTR] = TARGET_ENOSTR,
618 [ENODATA] = TARGET_ENODATA,
619 [ETIME] = TARGET_ETIME,
620 [ENOSR] = TARGET_ENOSR,
621 [ENONET] = TARGET_ENONET,
622 [ENOPKG] = TARGET_ENOPKG,
623 [EREMOTE] = TARGET_EREMOTE,
624 [ENOLINK] = TARGET_ENOLINK,
625 [EADV] = TARGET_EADV,
626 [ESRMNT] = TARGET_ESRMNT,
627 [ECOMM] = TARGET_ECOMM,
628 [EPROTO] = TARGET_EPROTO,
629 [EDOTDOT] = TARGET_EDOTDOT,
630 [EMULTIHOP] = TARGET_EMULTIHOP,
631 [EBADMSG] = TARGET_EBADMSG,
632 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
633 [EOVERFLOW] = TARGET_EOVERFLOW,
634 [ENOTUNIQ] = TARGET_ENOTUNIQ,
635 [EBADFD] = TARGET_EBADFD,
636 [EREMCHG] = TARGET_EREMCHG,
637 [ELIBACC] = TARGET_ELIBACC,
638 [ELIBBAD] = TARGET_ELIBBAD,
639 [ELIBSCN] = TARGET_ELIBSCN,
640 [ELIBMAX] = TARGET_ELIBMAX,
641 [ELIBEXEC] = TARGET_ELIBEXEC,
642 [EILSEQ] = TARGET_EILSEQ,
643 [ENOSYS] = TARGET_ENOSYS,
644 [ELOOP] = TARGET_ELOOP,
645 [ERESTART] = TARGET_ERESTART,
646 [ESTRPIPE] = TARGET_ESTRPIPE,
647 [ENOTEMPTY] = TARGET_ENOTEMPTY,
648 [EUSERS] = TARGET_EUSERS,
649 [ENOTSOCK] = TARGET_ENOTSOCK,
650 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
651 [EMSGSIZE] = TARGET_EMSGSIZE,
652 [EPROTOTYPE] = TARGET_EPROTOTYPE,
653 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
654 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
655 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
656 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
657 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
658 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
659 [EADDRINUSE] = TARGET_EADDRINUSE,
660 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
661 [ENETDOWN] = TARGET_ENETDOWN,
662 [ENETUNREACH] = TARGET_ENETUNREACH,
663 [ENETRESET] = TARGET_ENETRESET,
664 [ECONNABORTED] = TARGET_ECONNABORTED,
665 [ECONNRESET] = TARGET_ECONNRESET,
666 [ENOBUFS] = TARGET_ENOBUFS,
667 [EISCONN] = TARGET_EISCONN,
668 [ENOTCONN] = TARGET_ENOTCONN,
669 [EUCLEAN] = TARGET_EUCLEAN,
670 [ENOTNAM] = TARGET_ENOTNAM,
671 [ENAVAIL] = TARGET_ENAVAIL,
672 [EISNAM] = TARGET_EISNAM,
673 [EREMOTEIO] = TARGET_EREMOTEIO,
674 [ESHUTDOWN] = TARGET_ESHUTDOWN,
675 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
676 [ETIMEDOUT] = TARGET_ETIMEDOUT,
677 [ECONNREFUSED] = TARGET_ECONNREFUSED,
678 [EHOSTDOWN] = TARGET_EHOSTDOWN,
679 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
680 [EALREADY] = TARGET_EALREADY,
681 [EINPROGRESS] = TARGET_EINPROGRESS,
682 [ESTALE] = TARGET_ESTALE,
683 [ECANCELED] = TARGET_ECANCELED,
684 [ENOMEDIUM] = TARGET_ENOMEDIUM,
685 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000686#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000687 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000688#endif
689#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000690 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000691#endif
692#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000693 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000694#endif
695#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000696 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000697#endif
698#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000699 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000700#endif
701#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000702 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000703#endif
thsb92c47c2007-11-01 00:07:38 +0000704};
ths637947f2007-06-01 12:09:19 +0000705
706static inline int host_to_target_errno(int err)
707{
708 if(host_to_target_errno_table[err])
709 return host_to_target_errno_table[err];
710 return err;
711}
712
thsb92c47c2007-11-01 00:07:38 +0000713static inline int target_to_host_errno(int err)
714{
715 if (target_to_host_errno_table[err])
716 return target_to_host_errno_table[err];
717 return err;
718}
719
blueswir1992f48a2007-10-14 16:27:31 +0000720static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000721{
722 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000723 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000724 else
725 return ret;
726}
727
blueswir1992f48a2007-10-14 16:27:31 +0000728static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000729{
blueswir1992f48a2007-10-14 16:27:31 +0000730 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000731}
732
thsb92c47c2007-11-01 00:07:38 +0000733char *target_strerror(int err)
734{
Alexander Graf962b2892011-11-21 12:04:07 +0100735 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
736 return NULL;
737 }
thsb92c47c2007-11-01 00:07:38 +0000738 return strerror(target_to_host_errno(err));
739}
740
blueswir1992f48a2007-10-14 16:27:31 +0000741static abi_ulong target_brk;
742static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000743static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000744
blueswir1992f48a2007-10-14 16:27:31 +0000745void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000746{
blueswir14c1de732007-07-07 20:45:44 +0000747 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000748 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000749}
750
vincent4d1de872011-06-14 21:56:33 +0000751//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
752#define DEBUGF_BRK(message, args...)
753
ths0da46a62007-10-20 20:23:07 +0000754/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000755abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000756{
blueswir1992f48a2007-10-14 16:27:31 +0000757 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000758 int new_alloc_size;
759
Paul Brook3a0c6c42012-02-09 19:04:27 +0000760 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000761
vincent4d1de872011-06-14 21:56:33 +0000762 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000763 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000764 return target_brk;
765 }
766 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000767 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
768 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000769 return target_brk;
770 }
bellard31e31b82003-02-18 22:55:36 +0000771
vincent4d1de872011-06-14 21:56:33 +0000772 /* If the new brk is less than the highest page reserved to the
773 * target heap allocation, set it and we're almost done... */
774 if (new_brk <= brk_page) {
775 /* Heap contents are initialized to zero, as for anonymous
776 * mapped pages. */
777 if (new_brk > target_brk) {
778 memset(g2h(target_brk), 0, new_brk - target_brk);
779 }
bellard31e31b82003-02-18 22:55:36 +0000780 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000781 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000782 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000783 }
784
Peter Maydell00faf082011-04-18 16:34:24 +0100785 /* We need to allocate more memory after the brk... Note that
786 * we don't use MAP_FIXED because that will map over the top of
787 * any existing mapping (like the one with the host libc or qemu
788 * itself); instead we treat "mapped but at wrong address" as
789 * a failure and unmap again.
790 */
vincent4d1de872011-06-14 21:56:33 +0000791 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000792 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000793 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100794 MAP_ANON|MAP_PRIVATE, 0, 0));
795
796 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200797 /* Heap contents are initialized to zero, as for anonymous
798 * mapped pages. Technically the new pages are already
799 * initialized to zero since they *are* anonymous mapped
800 * pages, however we have to take care with the contents that
801 * come from the remaining part of the previous page: it may
802 * contains garbage data due to a previous heap usage (grown
803 * then shrunken). */
804 memset(g2h(target_brk), 0, brk_page - target_brk);
805
Peter Maydell00faf082011-04-18 16:34:24 +0100806 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000807 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000808 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
809 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100810 return target_brk;
811 } else if (mapped_addr != -1) {
812 /* Mapped but at wrong address, meaning there wasn't actually
813 * enough space for this brk.
814 */
815 target_munmap(mapped_addr, new_alloc_size);
816 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000817 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000818 }
819 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000820 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100821 }
balrog7ab240a2008-04-26 12:17:34 +0000822
Richard Henderson7dd46c02010-05-03 10:07:49 -0700823#if defined(TARGET_ALPHA)
824 /* We (partially) emulate OSF/1 on Alpha, which requires we
825 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100826 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700827#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100828 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000829 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000830}
831
ths26edcf42007-12-09 02:25:24 +0000832static inline abi_long copy_from_user_fdset(fd_set *fds,
833 abi_ulong target_fds_addr,
834 int n)
bellard31e31b82003-02-18 22:55:36 +0000835{
ths26edcf42007-12-09 02:25:24 +0000836 int i, nw, j, k;
837 abi_ulong b, *target_fds;
838
839 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
840 if (!(target_fds = lock_user(VERIFY_READ,
841 target_fds_addr,
842 sizeof(abi_ulong) * nw,
843 1)))
844 return -TARGET_EFAULT;
845
846 FD_ZERO(fds);
847 k = 0;
848 for (i = 0; i < nw; i++) {
849 /* grab the abi_ulong */
850 __get_user(b, &target_fds[i]);
851 for (j = 0; j < TARGET_ABI_BITS; j++) {
852 /* check the bit inside the abi_ulong */
853 if ((b >> j) & 1)
854 FD_SET(k, fds);
855 k++;
bellard31e31b82003-02-18 22:55:36 +0000856 }
bellard31e31b82003-02-18 22:55:36 +0000857 }
ths26edcf42007-12-09 02:25:24 +0000858
859 unlock_user(target_fds, target_fds_addr, 0);
860
861 return 0;
bellard31e31b82003-02-18 22:55:36 +0000862}
863
Mike Frysinger055e0902011-06-03 17:01:49 -0400864static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
865 abi_ulong target_fds_addr,
866 int n)
867{
868 if (target_fds_addr) {
869 if (copy_from_user_fdset(fds, target_fds_addr, n))
870 return -TARGET_EFAULT;
871 *fds_ptr = fds;
872 } else {
873 *fds_ptr = NULL;
874 }
875 return 0;
876}
877
ths26edcf42007-12-09 02:25:24 +0000878static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
879 const fd_set *fds,
880 int n)
bellard31e31b82003-02-18 22:55:36 +0000881{
bellard31e31b82003-02-18 22:55:36 +0000882 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000883 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000884 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000885
ths26edcf42007-12-09 02:25:24 +0000886 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
887 if (!(target_fds = lock_user(VERIFY_WRITE,
888 target_fds_addr,
889 sizeof(abi_ulong) * nw,
890 0)))
891 return -TARGET_EFAULT;
892
893 k = 0;
894 for (i = 0; i < nw; i++) {
895 v = 0;
896 for (j = 0; j < TARGET_ABI_BITS; j++) {
897 v |= ((FD_ISSET(k, fds) != 0) << j);
898 k++;
bellard31e31b82003-02-18 22:55:36 +0000899 }
ths26edcf42007-12-09 02:25:24 +0000900 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000901 }
ths26edcf42007-12-09 02:25:24 +0000902
903 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
904
905 return 0;
bellard31e31b82003-02-18 22:55:36 +0000906}
907
bellardc596ed12003-07-13 17:32:31 +0000908#if defined(__alpha__)
909#define HOST_HZ 1024
910#else
911#define HOST_HZ 100
912#endif
913
blueswir1992f48a2007-10-14 16:27:31 +0000914static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000915{
916#if HOST_HZ == TARGET_HZ
917 return ticks;
918#else
919 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
920#endif
921}
922
bellard579a97f2007-11-11 14:26:47 +0000923static inline abi_long host_to_target_rusage(abi_ulong target_addr,
924 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000925{
pbrook53a59602006-03-25 19:31:22 +0000926 struct target_rusage *target_rusage;
927
bellard579a97f2007-11-11 14:26:47 +0000928 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
929 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200930 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
931 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
932 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
933 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
934 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
935 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
936 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
937 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
938 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
939 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
940 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
941 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
942 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
943 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
944 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
945 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
946 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
947 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000948 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000949
950 return 0;
bellardb4091862003-05-16 15:39:34 +0000951}
952
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200953static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900954{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200955 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300956 rlim_t result;
957
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200958 target_rlim_swap = tswapal(target_rlim);
959 if (target_rlim_swap == TARGET_RLIM_INFINITY)
960 return RLIM_INFINITY;
961
962 result = target_rlim_swap;
963 if (target_rlim_swap != (rlim_t)result)
964 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300965
966 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900967}
968
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200969static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900970{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200971 abi_ulong target_rlim_swap;
972 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300973
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200974 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300975 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900976 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300977 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200978 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300979
980 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900981}
982
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300983static inline int target_to_host_resource(int code)
984{
985 switch (code) {
986 case TARGET_RLIMIT_AS:
987 return RLIMIT_AS;
988 case TARGET_RLIMIT_CORE:
989 return RLIMIT_CORE;
990 case TARGET_RLIMIT_CPU:
991 return RLIMIT_CPU;
992 case TARGET_RLIMIT_DATA:
993 return RLIMIT_DATA;
994 case TARGET_RLIMIT_FSIZE:
995 return RLIMIT_FSIZE;
996 case TARGET_RLIMIT_LOCKS:
997 return RLIMIT_LOCKS;
998 case TARGET_RLIMIT_MEMLOCK:
999 return RLIMIT_MEMLOCK;
1000 case TARGET_RLIMIT_MSGQUEUE:
1001 return RLIMIT_MSGQUEUE;
1002 case TARGET_RLIMIT_NICE:
1003 return RLIMIT_NICE;
1004 case TARGET_RLIMIT_NOFILE:
1005 return RLIMIT_NOFILE;
1006 case TARGET_RLIMIT_NPROC:
1007 return RLIMIT_NPROC;
1008 case TARGET_RLIMIT_RSS:
1009 return RLIMIT_RSS;
1010 case TARGET_RLIMIT_RTPRIO:
1011 return RLIMIT_RTPRIO;
1012 case TARGET_RLIMIT_SIGPENDING:
1013 return RLIMIT_SIGPENDING;
1014 case TARGET_RLIMIT_STACK:
1015 return RLIMIT_STACK;
1016 default:
1017 return code;
1018 }
1019}
1020
ths788f5ec2007-12-09 02:37:05 +00001021static inline abi_long copy_from_user_timeval(struct timeval *tv,
1022 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001023{
pbrook53a59602006-03-25 19:31:22 +00001024 struct target_timeval *target_tv;
1025
ths788f5ec2007-12-09 02:37:05 +00001026 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001027 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001028
1029 __get_user(tv->tv_sec, &target_tv->tv_sec);
1030 __get_user(tv->tv_usec, &target_tv->tv_usec);
1031
1032 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001033
1034 return 0;
bellard31e31b82003-02-18 22:55:36 +00001035}
1036
ths788f5ec2007-12-09 02:37:05 +00001037static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1038 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001039{
pbrook53a59602006-03-25 19:31:22 +00001040 struct target_timeval *target_tv;
1041
ths788f5ec2007-12-09 02:37:05 +00001042 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001043 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001044
1045 __put_user(tv->tv_sec, &target_tv->tv_sec);
1046 __put_user(tv->tv_usec, &target_tv->tv_usec);
1047
1048 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001049
1050 return 0;
bellard31e31b82003-02-18 22:55:36 +00001051}
1052
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001053#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1054#include <mqueue.h>
1055
aurel3224e10032009-04-15 16:11:43 +00001056static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1057 abi_ulong target_mq_attr_addr)
1058{
1059 struct target_mq_attr *target_mq_attr;
1060
1061 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1062 target_mq_attr_addr, 1))
1063 return -TARGET_EFAULT;
1064
1065 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1066 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1067 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1068 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1069
1070 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1071
1072 return 0;
1073}
1074
1075static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1076 const struct mq_attr *attr)
1077{
1078 struct target_mq_attr *target_mq_attr;
1079
1080 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1081 target_mq_attr_addr, 0))
1082 return -TARGET_EFAULT;
1083
1084 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1085 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1086 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1087 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1088
1089 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1090
1091 return 0;
1092}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001093#endif
bellard31e31b82003-02-18 22:55:36 +00001094
Mike Frysinger055e0902011-06-03 17:01:49 -04001095#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001096/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001097static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001098 abi_ulong rfd_addr, abi_ulong wfd_addr,
1099 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001100{
1101 fd_set rfds, wfds, efds;
1102 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1103 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001104 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001105
Mike Frysinger055e0902011-06-03 17:01:49 -04001106 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1107 if (ret) {
1108 return ret;
pbrook53a59602006-03-25 19:31:22 +00001109 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001110 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1111 if (ret) {
1112 return ret;
pbrook53a59602006-03-25 19:31:22 +00001113 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001114 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1115 if (ret) {
1116 return ret;
pbrook53a59602006-03-25 19:31:22 +00001117 }
ths3b46e622007-09-17 08:09:54 +00001118
ths26edcf42007-12-09 02:25:24 +00001119 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001120 if (copy_from_user_timeval(&tv, target_tv_addr))
1121 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001122 tv_ptr = &tv;
1123 } else {
1124 tv_ptr = NULL;
1125 }
ths26edcf42007-12-09 02:25:24 +00001126
bellard31e31b82003-02-18 22:55:36 +00001127 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001128
ths26edcf42007-12-09 02:25:24 +00001129 if (!is_error(ret)) {
1130 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1131 return -TARGET_EFAULT;
1132 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1133 return -TARGET_EFAULT;
1134 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1135 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001136
ths788f5ec2007-12-09 02:37:05 +00001137 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1138 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001139 }
bellard579a97f2007-11-11 14:26:47 +00001140
bellard31e31b82003-02-18 22:55:36 +00001141 return ret;
1142}
Mike Frysinger055e0902011-06-03 17:01:49 -04001143#endif
bellard31e31b82003-02-18 22:55:36 +00001144
Riku Voipio099d6b02009-05-05 12:10:04 +03001145static abi_long do_pipe2(int host_pipe[], int flags)
1146{
1147#ifdef CONFIG_PIPE2
1148 return pipe2(host_pipe, flags);
1149#else
1150 return -ENOSYS;
1151#endif
1152}
1153
Richard Hendersonfb41a662010-05-03 10:07:52 -07001154static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1155 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001156{
1157 int host_pipe[2];
1158 abi_long ret;
1159 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1160
1161 if (is_error(ret))
1162 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001163
1164 /* Several targets have special calling conventions for the original
1165 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1166 if (!is_pipe2) {
1167#if defined(TARGET_ALPHA)
1168 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1169 return host_pipe[0];
1170#elif defined(TARGET_MIPS)
1171 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1172 return host_pipe[0];
1173#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001174 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001175 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001176#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001177 }
1178
Riku Voipio099d6b02009-05-05 12:10:04 +03001179 if (put_user_s32(host_pipe[0], pipedes)
1180 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1181 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001182 return get_errno(ret);
1183}
1184
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001185static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1186 abi_ulong target_addr,
1187 socklen_t len)
1188{
1189 struct target_ip_mreqn *target_smreqn;
1190
1191 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1192 if (!target_smreqn)
1193 return -TARGET_EFAULT;
1194 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1195 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1196 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001197 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001198 unlock_user(target_smreqn, target_addr, 0);
1199
1200 return 0;
1201}
1202
bellard579a97f2007-11-11 14:26:47 +00001203static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1204 abi_ulong target_addr,
1205 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001206{
aurel32607175e2009-04-15 16:11:59 +00001207 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1208 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001209 struct target_sockaddr *target_saddr;
1210
bellard579a97f2007-11-11 14:26:47 +00001211 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1212 if (!target_saddr)
1213 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001214
1215 sa_family = tswap16(target_saddr->sa_family);
1216
1217 /* Oops. The caller might send a incomplete sun_path; sun_path
1218 * must be terminated by \0 (see the manual page), but
1219 * unfortunately it is quite common to specify sockaddr_un
1220 * length as "strlen(x->sun_path)" while it should be
1221 * "strlen(...) + 1". We'll fix that here if needed.
1222 * Linux kernel has a similar feature.
1223 */
1224
1225 if (sa_family == AF_UNIX) {
1226 if (len < unix_maxlen && len > 0) {
1227 char *cp = (char*)target_saddr;
1228
1229 if ( cp[len-1] && !cp[len] )
1230 len++;
1231 }
1232 if (len > unix_maxlen)
1233 len = unix_maxlen;
1234 }
1235
pbrook53a59602006-03-25 19:31:22 +00001236 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001237 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001238 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001239
1240 return 0;
bellard7854b052003-03-29 17:22:23 +00001241}
1242
bellard579a97f2007-11-11 14:26:47 +00001243static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1244 struct sockaddr *addr,
1245 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001246{
pbrook53a59602006-03-25 19:31:22 +00001247 struct target_sockaddr *target_saddr;
1248
bellard579a97f2007-11-11 14:26:47 +00001249 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1250 if (!target_saddr)
1251 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001252 memcpy(target_saddr, addr, len);
1253 target_saddr->sa_family = tswap16(addr->sa_family);
1254 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001255
1256 return 0;
bellard7854b052003-03-29 17:22:23 +00001257}
1258
pbrook53a59602006-03-25 19:31:22 +00001259/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001260static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1261 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001262{
1263 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001264 abi_long msg_controllen;
1265 abi_ulong target_cmsg_addr;
1266 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001267 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001268
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001269 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001270 if (msg_controllen < sizeof (struct target_cmsghdr))
1271 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001272 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001273 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1274 if (!target_cmsg)
1275 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001276
1277 while (cmsg && target_cmsg) {
1278 void *data = CMSG_DATA(cmsg);
1279 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1280
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001281 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001282 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1283
1284 space += CMSG_SPACE(len);
1285 if (space > msgh->msg_controllen) {
1286 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001287 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001288 break;
1289 }
1290
1291 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1292 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1293 cmsg->cmsg_len = CMSG_LEN(len);
1294
bellard3532fa72006-06-24 15:06:03 +00001295 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001296 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1297 memcpy(data, target_data, len);
1298 } else {
1299 int *fd = (int *)data;
1300 int *target_fd = (int *)target_data;
1301 int i, numfds = len / sizeof(int);
1302
1303 for (i = 0; i < numfds; i++)
1304 fd[i] = tswap32(target_fd[i]);
1305 }
1306
1307 cmsg = CMSG_NXTHDR(msgh, cmsg);
1308 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1309 }
bellard5a4a8982007-11-11 17:39:18 +00001310 unlock_user(target_cmsg, target_cmsg_addr, 0);
1311 the_end:
bellard7854b052003-03-29 17:22:23 +00001312 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001313 return 0;
bellard7854b052003-03-29 17:22:23 +00001314}
1315
pbrook53a59602006-03-25 19:31:22 +00001316/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001317static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1318 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001319{
1320 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001321 abi_long msg_controllen;
1322 abi_ulong target_cmsg_addr;
1323 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001324 socklen_t space = 0;
1325
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001326 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001327 if (msg_controllen < sizeof (struct target_cmsghdr))
1328 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001329 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001330 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1331 if (!target_cmsg)
1332 return -TARGET_EFAULT;
1333
bellard7854b052003-03-29 17:22:23 +00001334 while (cmsg && target_cmsg) {
1335 void *data = CMSG_DATA(cmsg);
1336 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1337
1338 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1339
1340 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001341 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001342 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001343 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001344 break;
1345 }
1346
1347 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1348 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001349 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001350
bellard3532fa72006-06-24 15:06:03 +00001351 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001352 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1353 memcpy(target_data, data, len);
1354 } else {
1355 int *fd = (int *)data;
1356 int *target_fd = (int *)target_data;
1357 int i, numfds = len / sizeof(int);
1358
1359 for (i = 0; i < numfds; i++)
1360 target_fd[i] = tswap32(fd[i]);
1361 }
1362
1363 cmsg = CMSG_NXTHDR(msgh, cmsg);
1364 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1365 }
bellard5a4a8982007-11-11 17:39:18 +00001366 unlock_user(target_cmsg, target_cmsg_addr, space);
1367 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001368 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001369 return 0;
bellard7854b052003-03-29 17:22:23 +00001370}
1371
ths0da46a62007-10-20 20:23:07 +00001372/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001373static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001374 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001375{
blueswir1992f48a2007-10-14 16:27:31 +00001376 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001377 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001378 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001379 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001380
bellard8853f862004-02-22 14:57:26 +00001381 switch(level) {
1382 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001383 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001384 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001385 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001386
bellard2f619692007-11-16 10:46:05 +00001387 if (get_user_u32(val, optval_addr))
1388 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001389 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1390 break;
1391 case SOL_IP:
1392 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001393 case IP_TOS:
1394 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001395 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001396 case IP_ROUTER_ALERT:
1397 case IP_RECVOPTS:
1398 case IP_RETOPTS:
1399 case IP_PKTINFO:
1400 case IP_MTU_DISCOVER:
1401 case IP_RECVERR:
1402 case IP_RECVTOS:
1403#ifdef IP_FREEBIND
1404 case IP_FREEBIND:
1405#endif
1406 case IP_MULTICAST_TTL:
1407 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001408 val = 0;
1409 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001410 if (get_user_u32(val, optval_addr))
1411 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001412 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001413 if (get_user_u8(val, optval_addr))
1414 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001415 }
1416 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1417 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001418 case IP_ADD_MEMBERSHIP:
1419 case IP_DROP_MEMBERSHIP:
1420 if (optlen < sizeof (struct target_ip_mreq) ||
1421 optlen > sizeof (struct target_ip_mreqn))
1422 return -TARGET_EINVAL;
1423
1424 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1425 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1426 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1427 break;
1428
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001429 case IP_BLOCK_SOURCE:
1430 case IP_UNBLOCK_SOURCE:
1431 case IP_ADD_SOURCE_MEMBERSHIP:
1432 case IP_DROP_SOURCE_MEMBERSHIP:
1433 if (optlen != sizeof (struct target_ip_mreq_source))
1434 return -TARGET_EINVAL;
1435
1436 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1437 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1438 unlock_user (ip_mreq_source, optval_addr, 0);
1439 break;
1440
bellard8853f862004-02-22 14:57:26 +00001441 default:
1442 goto unimplemented;
1443 }
1444 break;
bellard3532fa72006-06-24 15:06:03 +00001445 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001446 switch (optname) {
1447 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001448 case TARGET_SO_DEBUG:
1449 optname = SO_DEBUG;
1450 break;
1451 case TARGET_SO_REUSEADDR:
1452 optname = SO_REUSEADDR;
1453 break;
1454 case TARGET_SO_TYPE:
1455 optname = SO_TYPE;
1456 break;
1457 case TARGET_SO_ERROR:
1458 optname = SO_ERROR;
1459 break;
1460 case TARGET_SO_DONTROUTE:
1461 optname = SO_DONTROUTE;
1462 break;
1463 case TARGET_SO_BROADCAST:
1464 optname = SO_BROADCAST;
1465 break;
1466 case TARGET_SO_SNDBUF:
1467 optname = SO_SNDBUF;
1468 break;
1469 case TARGET_SO_RCVBUF:
1470 optname = SO_RCVBUF;
1471 break;
1472 case TARGET_SO_KEEPALIVE:
1473 optname = SO_KEEPALIVE;
1474 break;
1475 case TARGET_SO_OOBINLINE:
1476 optname = SO_OOBINLINE;
1477 break;
1478 case TARGET_SO_NO_CHECK:
1479 optname = SO_NO_CHECK;
1480 break;
1481 case TARGET_SO_PRIORITY:
1482 optname = SO_PRIORITY;
1483 break;
bellard5e83e8e2005-03-01 22:32:06 +00001484#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001485 case TARGET_SO_BSDCOMPAT:
1486 optname = SO_BSDCOMPAT;
1487 break;
bellard5e83e8e2005-03-01 22:32:06 +00001488#endif
bellard3532fa72006-06-24 15:06:03 +00001489 case TARGET_SO_PASSCRED:
1490 optname = SO_PASSCRED;
1491 break;
1492 case TARGET_SO_TIMESTAMP:
1493 optname = SO_TIMESTAMP;
1494 break;
1495 case TARGET_SO_RCVLOWAT:
1496 optname = SO_RCVLOWAT;
1497 break;
1498 case TARGET_SO_RCVTIMEO:
1499 optname = SO_RCVTIMEO;
1500 break;
1501 case TARGET_SO_SNDTIMEO:
1502 optname = SO_SNDTIMEO;
1503 break;
bellard8853f862004-02-22 14:57:26 +00001504 break;
1505 default:
1506 goto unimplemented;
1507 }
bellard3532fa72006-06-24 15:06:03 +00001508 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001509 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001510
bellard2f619692007-11-16 10:46:05 +00001511 if (get_user_u32(val, optval_addr))
1512 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001513 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001514 break;
bellard7854b052003-03-29 17:22:23 +00001515 default:
bellard8853f862004-02-22 14:57:26 +00001516 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001517 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001518 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001519 }
bellard8853f862004-02-22 14:57:26 +00001520 return ret;
bellard7854b052003-03-29 17:22:23 +00001521}
1522
ths0da46a62007-10-20 20:23:07 +00001523/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001524static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001525 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001526{
blueswir1992f48a2007-10-14 16:27:31 +00001527 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001528 int len, val;
1529 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001530
1531 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001532 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001533 level = SOL_SOCKET;
1534 switch (optname) {
1535 /* These don't just return a single integer */
1536 case TARGET_SO_LINGER:
1537 case TARGET_SO_RCVTIMEO:
1538 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001539 case TARGET_SO_PEERNAME:
1540 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001541 case TARGET_SO_PEERCRED: {
1542 struct ucred cr;
1543 socklen_t crlen;
1544 struct target_ucred *tcr;
1545
1546 if (get_user_u32(len, optlen)) {
1547 return -TARGET_EFAULT;
1548 }
1549 if (len < 0) {
1550 return -TARGET_EINVAL;
1551 }
1552
1553 crlen = sizeof(cr);
1554 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1555 &cr, &crlen));
1556 if (ret < 0) {
1557 return ret;
1558 }
1559 if (len > crlen) {
1560 len = crlen;
1561 }
1562 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1563 return -TARGET_EFAULT;
1564 }
1565 __put_user(cr.pid, &tcr->pid);
1566 __put_user(cr.uid, &tcr->uid);
1567 __put_user(cr.gid, &tcr->gid);
1568 unlock_user_struct(tcr, optval_addr, 1);
1569 if (put_user_u32(len, optlen)) {
1570 return -TARGET_EFAULT;
1571 }
1572 break;
1573 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001574 /* Options with 'int' argument. */
1575 case TARGET_SO_DEBUG:
1576 optname = SO_DEBUG;
1577 goto int_case;
1578 case TARGET_SO_REUSEADDR:
1579 optname = SO_REUSEADDR;
1580 goto int_case;
1581 case TARGET_SO_TYPE:
1582 optname = SO_TYPE;
1583 goto int_case;
1584 case TARGET_SO_ERROR:
1585 optname = SO_ERROR;
1586 goto int_case;
1587 case TARGET_SO_DONTROUTE:
1588 optname = SO_DONTROUTE;
1589 goto int_case;
1590 case TARGET_SO_BROADCAST:
1591 optname = SO_BROADCAST;
1592 goto int_case;
1593 case TARGET_SO_SNDBUF:
1594 optname = SO_SNDBUF;
1595 goto int_case;
1596 case TARGET_SO_RCVBUF:
1597 optname = SO_RCVBUF;
1598 goto int_case;
1599 case TARGET_SO_KEEPALIVE:
1600 optname = SO_KEEPALIVE;
1601 goto int_case;
1602 case TARGET_SO_OOBINLINE:
1603 optname = SO_OOBINLINE;
1604 goto int_case;
1605 case TARGET_SO_NO_CHECK:
1606 optname = SO_NO_CHECK;
1607 goto int_case;
1608 case TARGET_SO_PRIORITY:
1609 optname = SO_PRIORITY;
1610 goto int_case;
1611#ifdef SO_BSDCOMPAT
1612 case TARGET_SO_BSDCOMPAT:
1613 optname = SO_BSDCOMPAT;
1614 goto int_case;
1615#endif
1616 case TARGET_SO_PASSCRED:
1617 optname = SO_PASSCRED;
1618 goto int_case;
1619 case TARGET_SO_TIMESTAMP:
1620 optname = SO_TIMESTAMP;
1621 goto int_case;
1622 case TARGET_SO_RCVLOWAT:
1623 optname = SO_RCVLOWAT;
1624 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001625 default:
bellard2efbe912005-07-23 15:10:20 +00001626 goto int_case;
1627 }
1628 break;
1629 case SOL_TCP:
1630 /* TCP options all take an 'int' value. */
1631 int_case:
bellard2f619692007-11-16 10:46:05 +00001632 if (get_user_u32(len, optlen))
1633 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001634 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001635 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001636 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001637 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1638 if (ret < 0)
1639 return ret;
bellard2efbe912005-07-23 15:10:20 +00001640 if (len > lv)
1641 len = lv;
bellard2f619692007-11-16 10:46:05 +00001642 if (len == 4) {
1643 if (put_user_u32(val, optval_addr))
1644 return -TARGET_EFAULT;
1645 } else {
1646 if (put_user_u8(val, optval_addr))
1647 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001648 }
bellard2f619692007-11-16 10:46:05 +00001649 if (put_user_u32(len, optlen))
1650 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001651 break;
1652 case SOL_IP:
1653 switch(optname) {
1654 case IP_TOS:
1655 case IP_TTL:
1656 case IP_HDRINCL:
1657 case IP_ROUTER_ALERT:
1658 case IP_RECVOPTS:
1659 case IP_RETOPTS:
1660 case IP_PKTINFO:
1661 case IP_MTU_DISCOVER:
1662 case IP_RECVERR:
1663 case IP_RECVTOS:
1664#ifdef IP_FREEBIND
1665 case IP_FREEBIND:
1666#endif
1667 case IP_MULTICAST_TTL:
1668 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001669 if (get_user_u32(len, optlen))
1670 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001671 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001672 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001673 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001674 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1675 if (ret < 0)
1676 return ret;
bellard2efbe912005-07-23 15:10:20 +00001677 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001678 len = 1;
bellard2f619692007-11-16 10:46:05 +00001679 if (put_user_u32(len, optlen)
1680 || put_user_u8(val, optval_addr))
1681 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001682 } else {
bellard2efbe912005-07-23 15:10:20 +00001683 if (len > sizeof(int))
1684 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001685 if (put_user_u32(len, optlen)
1686 || put_user_u32(val, optval_addr))
1687 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001688 }
bellard8853f862004-02-22 14:57:26 +00001689 break;
bellard2efbe912005-07-23 15:10:20 +00001690 default:
thsc02f4992007-12-18 02:39:59 +00001691 ret = -TARGET_ENOPROTOOPT;
1692 break;
bellard8853f862004-02-22 14:57:26 +00001693 }
1694 break;
1695 default:
1696 unimplemented:
1697 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1698 level, optname);
thsc02f4992007-12-18 02:39:59 +00001699 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001700 break;
1701 }
1702 return ret;
bellard7854b052003-03-29 17:22:23 +00001703}
1704
bellard579a97f2007-11-11 14:26:47 +00001705/* FIXME
1706 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1707 * other lock functions have a return code of 0 for failure.
1708 */
1709static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1710 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001711{
1712 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001713 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001714 int i;
pbrook53a59602006-03-25 19:31:22 +00001715
bellard579a97f2007-11-11 14:26:47 +00001716 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1717 if (!target_vec)
1718 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001719 for(i = 0;i < count; i++) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001720 base = tswapal(target_vec[i].iov_base);
1721 vec[i].iov_len = tswapal(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001722 if (vec[i].iov_len != 0) {
1723 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001724 /* Don't check lock_user return value. We must call writev even
1725 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001726 } else {
1727 /* zero length pointer is ignored */
1728 vec[i].iov_base = NULL;
1729 }
pbrook53a59602006-03-25 19:31:22 +00001730 }
1731 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001732 return 0;
pbrook53a59602006-03-25 19:31:22 +00001733}
1734
bellard579a97f2007-11-11 14:26:47 +00001735static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1736 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001737{
1738 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001739 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001740 int i;
1741
bellard579a97f2007-11-11 14:26:47 +00001742 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1743 if (!target_vec)
1744 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001745 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001746 if (target_vec[i].iov_base) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001747 base = tswapal(target_vec[i].iov_base);
balrogd732dcb2008-10-28 10:21:03 +00001748 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1749 }
pbrook53a59602006-03-25 19:31:22 +00001750 }
1751 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001752
1753 return 0;
pbrook53a59602006-03-25 19:31:22 +00001754}
1755
ths0da46a62007-10-20 20:23:07 +00001756/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001757static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001758{
1759#if defined(TARGET_MIPS)
1760 switch(type) {
1761 case TARGET_SOCK_DGRAM:
1762 type = SOCK_DGRAM;
1763 break;
1764 case TARGET_SOCK_STREAM:
1765 type = SOCK_STREAM;
1766 break;
1767 case TARGET_SOCK_RAW:
1768 type = SOCK_RAW;
1769 break;
1770 case TARGET_SOCK_RDM:
1771 type = SOCK_RDM;
1772 break;
1773 case TARGET_SOCK_SEQPACKET:
1774 type = SOCK_SEQPACKET;
1775 break;
1776 case TARGET_SOCK_PACKET:
1777 type = SOCK_PACKET;
1778 break;
1779 }
1780#endif
balrog12bc92a2007-10-30 21:06:14 +00001781 if (domain == PF_NETLINK)
1782 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001783 return get_errno(socket(domain, type, protocol));
1784}
1785
ths0da46a62007-10-20 20:23:07 +00001786/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001787static abi_long do_bind(int sockfd, abi_ulong target_addr,
1788 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001789{
aurel328f7aeaf2009-01-30 19:47:57 +00001790 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001791 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001792
Blue Swirl38724252010-09-18 05:53:14 +00001793 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001794 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001795 }
aurel328f7aeaf2009-01-30 19:47:57 +00001796
aurel32607175e2009-04-15 16:11:59 +00001797 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001798
Arnaud Patard917507b2009-06-19 10:44:45 +03001799 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1800 if (ret)
1801 return ret;
1802
bellard3532fa72006-06-24 15:06:03 +00001803 return get_errno(bind(sockfd, addr, addrlen));
1804}
1805
ths0da46a62007-10-20 20:23:07 +00001806/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001807static abi_long do_connect(int sockfd, abi_ulong target_addr,
1808 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001809{
aurel328f7aeaf2009-01-30 19:47:57 +00001810 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001811 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001812
Blue Swirl38724252010-09-18 05:53:14 +00001813 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001814 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001815 }
aurel328f7aeaf2009-01-30 19:47:57 +00001816
1817 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001818
Arnaud Patard917507b2009-06-19 10:44:45 +03001819 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1820 if (ret)
1821 return ret;
1822
bellard3532fa72006-06-24 15:06:03 +00001823 return get_errno(connect(sockfd, addr, addrlen));
1824}
1825
ths0da46a62007-10-20 20:23:07 +00001826/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001827static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1828 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001829{
balrog6de645c2008-10-28 10:26:29 +00001830 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001831 struct target_msghdr *msgp;
1832 struct msghdr msg;
1833 int count;
1834 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001835 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001836
bellard579a97f2007-11-11 14:26:47 +00001837 /* FIXME */
1838 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1839 msgp,
1840 target_msg,
1841 send ? 1 : 0))
1842 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001843 if (msgp->msg_name) {
1844 msg.msg_namelen = tswap32(msgp->msg_namelen);
1845 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001846 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001847 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001848 if (ret) {
1849 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1850 return ret;
1851 }
bellard3532fa72006-06-24 15:06:03 +00001852 } else {
1853 msg.msg_name = NULL;
1854 msg.msg_namelen = 0;
1855 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001856 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001857 msg.msg_control = alloca(msg.msg_controllen);
1858 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001859
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001860 count = tswapal(msgp->msg_iovlen);
bellard3532fa72006-06-24 15:06:03 +00001861 vec = alloca(count * sizeof(struct iovec));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001862 target_vec = tswapal(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001863 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001864 msg.msg_iovlen = count;
1865 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001866
bellard3532fa72006-06-24 15:06:03 +00001867 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001868 ret = target_to_host_cmsg(&msg, msgp);
1869 if (ret == 0)
1870 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001871 } else {
1872 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001873 if (!is_error(ret)) {
1874 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001875 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001876 if (!is_error(ret))
1877 ret = len;
1878 }
bellard3532fa72006-06-24 15:06:03 +00001879 }
1880 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001881 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001882 return ret;
1883}
1884
ths0da46a62007-10-20 20:23:07 +00001885/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001886static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001887 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001888{
bellard2f619692007-11-16 10:46:05 +00001889 socklen_t addrlen;
1890 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001891 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001892
Arnaud Patard917507b2009-06-19 10:44:45 +03001893 if (target_addr == 0)
1894 return get_errno(accept(fd, NULL, NULL));
1895
1896 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001897 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001898 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001899
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_EINVAL;
1906
bellard2f619692007-11-16 10:46:05 +00001907 addr = alloca(addrlen);
1908
pbrook1be9e1d2006-11-19 15:26:04 +00001909 ret = get_errno(accept(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_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001919static abi_long do_getpeername(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(getpeername(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_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001948static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001949 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001950{
bellard2f619692007-11-16 10:46:05 +00001951 socklen_t addrlen;
1952 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001953 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001954
bellard2f619692007-11-16 10:46:05 +00001955 if (get_user_u32(addrlen, target_addrlen_addr))
1956 return -TARGET_EFAULT;
1957
Blue Swirl38724252010-09-18 05:53:14 +00001958 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001959 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001960 }
aurel328f7aeaf2009-01-30 19:47:57 +00001961
Arnaud Patard917507b2009-06-19 10:44:45 +03001962 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1963 return -TARGET_EFAULT;
1964
bellard2f619692007-11-16 10:46:05 +00001965 addr = alloca(addrlen);
1966
pbrook1be9e1d2006-11-19 15:26:04 +00001967 ret = get_errno(getsockname(fd, addr, &addrlen));
1968 if (!is_error(ret)) {
1969 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001970 if (put_user_u32(addrlen, target_addrlen_addr))
1971 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001972 }
1973 return ret;
1974}
1975
ths0da46a62007-10-20 20:23:07 +00001976/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001977static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001978 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001979{
1980 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001981 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001982
1983 ret = get_errno(socketpair(domain, type, protocol, tab));
1984 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001985 if (put_user_s32(tab[0], target_tab_addr)
1986 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1987 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001988 }
1989 return ret;
1990}
1991
ths0da46a62007-10-20 20:23:07 +00001992/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001993static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1994 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001995{
1996 void *addr;
1997 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001998 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001999
Blue Swirl38724252010-09-18 05:53:14 +00002000 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002001 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002002 }
aurel328f7aeaf2009-01-30 19:47:57 +00002003
bellard579a97f2007-11-11 14:26:47 +00002004 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2005 if (!host_msg)
2006 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002007 if (target_addr) {
2008 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002009 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2010 if (ret) {
2011 unlock_user(host_msg, msg, 0);
2012 return ret;
2013 }
pbrook1be9e1d2006-11-19 15:26:04 +00002014 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2015 } else {
2016 ret = get_errno(send(fd, host_msg, len, flags));
2017 }
2018 unlock_user(host_msg, msg, 0);
2019 return ret;
2020}
2021
ths0da46a62007-10-20 20:23:07 +00002022/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002023static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2024 abi_ulong target_addr,
2025 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002026{
2027 socklen_t addrlen;
2028 void *addr;
2029 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002030 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002031
bellard579a97f2007-11-11 14:26:47 +00002032 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2033 if (!host_msg)
2034 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002035 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002036 if (get_user_u32(addrlen, target_addrlen)) {
2037 ret = -TARGET_EFAULT;
2038 goto fail;
2039 }
Blue Swirl38724252010-09-18 05:53:14 +00002040 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002041 ret = -TARGET_EINVAL;
2042 goto fail;
2043 }
pbrook1be9e1d2006-11-19 15:26:04 +00002044 addr = alloca(addrlen);
2045 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2046 } else {
2047 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002048 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002049 }
2050 if (!is_error(ret)) {
2051 if (target_addr) {
2052 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002053 if (put_user_u32(addrlen, target_addrlen)) {
2054 ret = -TARGET_EFAULT;
2055 goto fail;
2056 }
pbrook1be9e1d2006-11-19 15:26:04 +00002057 }
2058 unlock_user(host_msg, msg, len);
2059 } else {
bellard2f619692007-11-16 10:46:05 +00002060fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002061 unlock_user(host_msg, msg, 0);
2062 }
2063 return ret;
2064}
2065
j_mayer32407102007-09-26 23:01:49 +00002066#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002067/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002068static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002069{
blueswir1992f48a2007-10-14 16:27:31 +00002070 abi_long ret;
2071 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002072
2073 switch(num) {
2074 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002075 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002076 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002077
Ulrich Hecht98818182009-07-03 17:09:28 +02002078 if (get_user_ual(domain, vptr)
2079 || get_user_ual(type, vptr + n)
2080 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002081 return -TARGET_EFAULT;
2082
bellard3532fa72006-06-24 15:06:03 +00002083 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002084 }
bellard31e31b82003-02-18 22:55:36 +00002085 break;
2086 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002087 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002088 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002089 abi_ulong target_addr;
2090 socklen_t addrlen;
2091
Ulrich Hecht98818182009-07-03 17:09:28 +02002092 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002093 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002094 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002095 return -TARGET_EFAULT;
2096
bellard3532fa72006-06-24 15:06:03 +00002097 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002098 }
bellard31e31b82003-02-18 22:55:36 +00002099 break;
2100 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002101 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002102 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002103 abi_ulong target_addr;
2104 socklen_t addrlen;
2105
Ulrich Hecht98818182009-07-03 17:09:28 +02002106 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002107 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002108 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002109 return -TARGET_EFAULT;
2110
bellard3532fa72006-06-24 15:06:03 +00002111 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002112 }
bellard31e31b82003-02-18 22:55:36 +00002113 break;
2114 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002115 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002116 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002117
Ulrich Hecht98818182009-07-03 17:09:28 +02002118 if (get_user_ual(sockfd, vptr)
2119 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002120 return -TARGET_EFAULT;
2121
bellard7854b052003-03-29 17:22:23 +00002122 ret = get_errno(listen(sockfd, backlog));
2123 }
bellard31e31b82003-02-18 22:55:36 +00002124 break;
2125 case SOCKOP_accept:
2126 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002127 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002128 abi_ulong target_addr, target_addrlen;
2129
Ulrich Hecht98818182009-07-03 17:09:28 +02002130 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002131 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002132 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002133 return -TARGET_EFAULT;
2134
pbrook1be9e1d2006-11-19 15:26:04 +00002135 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002136 }
2137 break;
2138 case SOCKOP_getsockname:
2139 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002140 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002141 abi_ulong target_addr, target_addrlen;
2142
Ulrich Hecht98818182009-07-03 17:09:28 +02002143 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002144 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002145 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002146 return -TARGET_EFAULT;
2147
pbrook1be9e1d2006-11-19 15:26:04 +00002148 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002149 }
2150 break;
2151 case SOCKOP_getpeername:
2152 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002153 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002154 abi_ulong target_addr, target_addrlen;
2155
Ulrich Hecht98818182009-07-03 17:09:28 +02002156 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002157 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002158 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002159 return -TARGET_EFAULT;
2160
pbrook1be9e1d2006-11-19 15:26:04 +00002161 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002162 }
2163 break;
2164 case SOCKOP_socketpair:
2165 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002166 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002167 abi_ulong tab;
2168
Ulrich Hecht98818182009-07-03 17:09:28 +02002169 if (get_user_ual(domain, vptr)
2170 || get_user_ual(type, vptr + n)
2171 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002172 || get_user_ual(tab, vptr + 3 * n))
2173 return -TARGET_EFAULT;
2174
pbrook1be9e1d2006-11-19 15:26:04 +00002175 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002176 }
2177 break;
2178 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002179 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002180 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002181 abi_ulong msg;
2182 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002183 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002184
Ulrich Hecht98818182009-07-03 17:09:28 +02002185 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002186 || get_user_ual(msg, vptr + n)
2187 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002188 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002189 return -TARGET_EFAULT;
2190
pbrook1be9e1d2006-11-19 15:26:04 +00002191 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002192 }
bellard31e31b82003-02-18 22:55:36 +00002193 break;
2194 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002195 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002196 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002197 abi_ulong msg;
2198 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002199 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002200
Ulrich Hecht98818182009-07-03 17:09:28 +02002201 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002202 || get_user_ual(msg, vptr + n)
2203 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002204 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002205 return -TARGET_EFAULT;
2206
pbrook1be9e1d2006-11-19 15:26:04 +00002207 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002208 }
bellard31e31b82003-02-18 22:55:36 +00002209 break;
2210 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002211 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002212 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002213 abi_ulong msg;
2214 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002215 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002216 abi_ulong addr;
2217 socklen_t addrlen;
2218
Ulrich Hecht98818182009-07-03 17:09:28 +02002219 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002220 || get_user_ual(msg, vptr + n)
2221 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002222 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002223 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002224 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002225 return -TARGET_EFAULT;
2226
pbrook1be9e1d2006-11-19 15:26:04 +00002227 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002228 }
bellard31e31b82003-02-18 22:55:36 +00002229 break;
2230 case SOCKOP_recvfrom:
2231 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002232 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002233 abi_ulong msg;
2234 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002235 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002236 abi_ulong addr;
2237 socklen_t addrlen;
2238
Ulrich Hecht98818182009-07-03 17:09:28 +02002239 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002240 || get_user_ual(msg, vptr + n)
2241 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002242 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002243 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002244 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002245 return -TARGET_EFAULT;
2246
pbrook1be9e1d2006-11-19 15:26:04 +00002247 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002248 }
2249 break;
2250 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002251 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002252 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002253
Ulrich Hecht98818182009-07-03 17:09:28 +02002254 if (get_user_ual(sockfd, vptr)
2255 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002256 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002257
2258 ret = get_errno(shutdown(sockfd, how));
2259 }
bellard31e31b82003-02-18 22:55:36 +00002260 break;
2261 case SOCKOP_sendmsg:
2262 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002263 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002264 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002265 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002266 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002267
Ulrich Hecht98818182009-07-03 17:09:28 +02002268 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002269 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002270 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002271 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002272
ths5fafdf22007-09-16 21:08:06 +00002273 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002274 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002275 }
2276 break;
bellard31e31b82003-02-18 22:55:36 +00002277 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002278 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002279 abi_ulong sockfd;
2280 abi_ulong level;
2281 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002282 abi_ulong optval;
2283 socklen_t optlen;
2284
Ulrich Hecht98818182009-07-03 17:09:28 +02002285 if (get_user_ual(sockfd, vptr)
2286 || get_user_ual(level, vptr + n)
2287 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002288 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002289 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002290 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002291
2292 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2293 }
2294 break;
bellard31e31b82003-02-18 22:55:36 +00002295 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002296 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002297 abi_ulong sockfd;
2298 abi_ulong level;
2299 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002300 abi_ulong optval;
2301 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002302
Ulrich Hecht98818182009-07-03 17:09:28 +02002303 if (get_user_ual(sockfd, vptr)
2304 || get_user_ual(level, vptr + n)
2305 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002306 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002307 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002308 return -TARGET_EFAULT;
2309
2310 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002311 }
2312 break;
bellard31e31b82003-02-18 22:55:36 +00002313 default:
2314 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002315 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002316 break;
2317 }
2318 return ret;
2319}
j_mayer32407102007-09-26 23:01:49 +00002320#endif
bellard31e31b82003-02-18 22:55:36 +00002321
bellard8853f862004-02-22 14:57:26 +00002322#define N_SHM_REGIONS 32
2323
2324static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002325 abi_ulong start;
2326 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002327} shm_regions[N_SHM_REGIONS];
2328
ths3eb6b042007-06-03 14:26:27 +00002329struct target_ipc_perm
2330{
blueswir1992f48a2007-10-14 16:27:31 +00002331 abi_long __key;
2332 abi_ulong uid;
2333 abi_ulong gid;
2334 abi_ulong cuid;
2335 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002336 unsigned short int mode;
2337 unsigned short int __pad1;
2338 unsigned short int __seq;
2339 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002340 abi_ulong __unused1;
2341 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002342};
2343
2344struct target_semid_ds
2345{
2346 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002347 abi_ulong sem_otime;
2348 abi_ulong __unused1;
2349 abi_ulong sem_ctime;
2350 abi_ulong __unused2;
2351 abi_ulong sem_nsems;
2352 abi_ulong __unused3;
2353 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002354};
2355
bellard579a97f2007-11-11 14:26:47 +00002356static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2357 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002358{
2359 struct target_ipc_perm *target_ip;
2360 struct target_semid_ds *target_sd;
2361
bellard579a97f2007-11-11 14:26:47 +00002362 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2363 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002364 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002365 host_ip->__key = tswapal(target_ip->__key);
2366 host_ip->uid = tswapal(target_ip->uid);
2367 host_ip->gid = tswapal(target_ip->gid);
2368 host_ip->cuid = tswapal(target_ip->cuid);
2369 host_ip->cgid = tswapal(target_ip->cgid);
2370 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002371 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002372 return 0;
ths3eb6b042007-06-03 14:26:27 +00002373}
2374
bellard579a97f2007-11-11 14:26:47 +00002375static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2376 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002377{
2378 struct target_ipc_perm *target_ip;
2379 struct target_semid_ds *target_sd;
2380
bellard579a97f2007-11-11 14:26:47 +00002381 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2382 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002383 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002384 target_ip->__key = tswapal(host_ip->__key);
2385 target_ip->uid = tswapal(host_ip->uid);
2386 target_ip->gid = tswapal(host_ip->gid);
2387 target_ip->cuid = tswapal(host_ip->cuid);
2388 target_ip->cgid = tswapal(host_ip->cgid);
2389 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002390 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002391 return 0;
ths3eb6b042007-06-03 14:26:27 +00002392}
2393
bellard579a97f2007-11-11 14:26:47 +00002394static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2395 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002396{
2397 struct target_semid_ds *target_sd;
2398
bellard579a97f2007-11-11 14:26:47 +00002399 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2400 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002401 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2402 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002403 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2404 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2405 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002406 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002407 return 0;
ths3eb6b042007-06-03 14:26:27 +00002408}
2409
bellard579a97f2007-11-11 14:26:47 +00002410static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2411 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002412{
2413 struct target_semid_ds *target_sd;
2414
bellard579a97f2007-11-11 14:26:47 +00002415 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2416 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002417 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002418 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002419 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2420 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2421 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002422 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002423 return 0;
ths3eb6b042007-06-03 14:26:27 +00002424}
2425
aurel32e5289082009-04-18 16:16:12 +00002426struct target_seminfo {
2427 int semmap;
2428 int semmni;
2429 int semmns;
2430 int semmnu;
2431 int semmsl;
2432 int semopm;
2433 int semume;
2434 int semusz;
2435 int semvmx;
2436 int semaem;
2437};
2438
2439static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2440 struct seminfo *host_seminfo)
2441{
2442 struct target_seminfo *target_seminfo;
2443 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2444 return -TARGET_EFAULT;
2445 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2446 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2447 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2448 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2449 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2450 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2451 __put_user(host_seminfo->semume, &target_seminfo->semume);
2452 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2453 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2454 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2455 unlock_user_struct(target_seminfo, target_addr, 1);
2456 return 0;
2457}
2458
thsfa294812007-02-02 22:05:00 +00002459union semun {
2460 int val;
ths3eb6b042007-06-03 14:26:27 +00002461 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002462 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002463 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002464};
2465
ths3eb6b042007-06-03 14:26:27 +00002466union target_semun {
2467 int val;
aurel32e5289082009-04-18 16:16:12 +00002468 abi_ulong buf;
2469 abi_ulong array;
2470 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002471};
2472
aurel32e5289082009-04-18 16:16:12 +00002473static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2474 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002475{
aurel32e5289082009-04-18 16:16:12 +00002476 int nsems;
2477 unsigned short *array;
2478 union semun semun;
2479 struct semid_ds semid_ds;
2480 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002481
aurel32e5289082009-04-18 16:16:12 +00002482 semun.buf = &semid_ds;
2483
2484 ret = semctl(semid, 0, IPC_STAT, semun);
2485 if (ret == -1)
2486 return get_errno(ret);
2487
2488 nsems = semid_ds.sem_nsems;
2489
2490 *host_array = malloc(nsems*sizeof(unsigned short));
2491 array = lock_user(VERIFY_READ, target_addr,
2492 nsems*sizeof(unsigned short), 1);
2493 if (!array)
2494 return -TARGET_EFAULT;
2495
2496 for(i=0; i<nsems; i++) {
2497 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002498 }
aurel32e5289082009-04-18 16:16:12 +00002499 unlock_user(array, target_addr, 0);
2500
bellard579a97f2007-11-11 14:26:47 +00002501 return 0;
ths3eb6b042007-06-03 14:26:27 +00002502}
2503
aurel32e5289082009-04-18 16:16:12 +00002504static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2505 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002506{
aurel32e5289082009-04-18 16:16:12 +00002507 int nsems;
2508 unsigned short *array;
2509 union semun semun;
2510 struct semid_ds semid_ds;
2511 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002512
aurel32e5289082009-04-18 16:16:12 +00002513 semun.buf = &semid_ds;
2514
2515 ret = semctl(semid, 0, IPC_STAT, semun);
2516 if (ret == -1)
2517 return get_errno(ret);
2518
2519 nsems = semid_ds.sem_nsems;
2520
2521 array = lock_user(VERIFY_WRITE, target_addr,
2522 nsems*sizeof(unsigned short), 0);
2523 if (!array)
2524 return -TARGET_EFAULT;
2525
2526 for(i=0; i<nsems; i++) {
2527 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002528 }
aurel32e5289082009-04-18 16:16:12 +00002529 free(*host_array);
2530 unlock_user(array, target_addr, 1);
2531
bellard579a97f2007-11-11 14:26:47 +00002532 return 0;
ths3eb6b042007-06-03 14:26:27 +00002533}
2534
aurel32e5289082009-04-18 16:16:12 +00002535static inline abi_long do_semctl(int semid, int semnum, int cmd,
2536 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002537{
2538 union semun arg;
2539 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302540 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002541 struct seminfo seminfo;
2542 abi_long ret = -TARGET_EINVAL;
2543 abi_long err;
2544 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002545
2546 switch( cmd ) {
2547 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002548 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002549 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002550 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002551 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002552 break;
2553 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002554 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002555 err = target_to_host_semarray(semid, &array, target_su.array);
2556 if (err)
2557 return err;
2558 arg.array = array;
2559 ret = get_errno(semctl(semid, semnum, cmd, arg));
2560 err = host_to_target_semarray(semid, target_su.array, &array);
2561 if (err)
2562 return err;
ths3eb6b042007-06-03 14:26:27 +00002563 break;
2564 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002565 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002566 case SEM_STAT:
2567 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2568 if (err)
2569 return err;
2570 arg.buf = &dsarg;
2571 ret = get_errno(semctl(semid, semnum, cmd, arg));
2572 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2573 if (err)
2574 return err;
ths3eb6b042007-06-03 14:26:27 +00002575 break;
aurel32e5289082009-04-18 16:16:12 +00002576 case IPC_INFO:
2577 case SEM_INFO:
2578 arg.__buf = &seminfo;
2579 ret = get_errno(semctl(semid, semnum, cmd, arg));
2580 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2581 if (err)
2582 return err;
2583 break;
2584 case IPC_RMID:
2585 case GETPID:
2586 case GETNCNT:
2587 case GETZCNT:
2588 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2589 break;
ths3eb6b042007-06-03 14:26:27 +00002590 }
2591
2592 return ret;
2593}
2594
aurel32e5289082009-04-18 16:16:12 +00002595struct target_sembuf {
2596 unsigned short sem_num;
2597 short sem_op;
2598 short sem_flg;
2599};
2600
2601static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2602 abi_ulong target_addr,
2603 unsigned nsops)
2604{
2605 struct target_sembuf *target_sembuf;
2606 int i;
2607
2608 target_sembuf = lock_user(VERIFY_READ, target_addr,
2609 nsops*sizeof(struct target_sembuf), 1);
2610 if (!target_sembuf)
2611 return -TARGET_EFAULT;
2612
2613 for(i=0; i<nsops; i++) {
2614 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2615 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2616 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2617 }
2618
2619 unlock_user(target_sembuf, target_addr, 0);
2620
2621 return 0;
2622}
2623
2624static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2625{
2626 struct sembuf sops[nsops];
2627
2628 if (target_to_host_sembuf(sops, ptr, nsops))
2629 return -TARGET_EFAULT;
2630
2631 return semop(semid, sops, nsops);
2632}
2633
ths1bc012f2007-06-03 14:27:49 +00002634struct target_msqid_ds
2635{
aurel321c54ff92008-10-13 21:08:44 +00002636 struct target_ipc_perm msg_perm;
2637 abi_ulong msg_stime;
2638#if TARGET_ABI_BITS == 32
2639 abi_ulong __unused1;
2640#endif
2641 abi_ulong msg_rtime;
2642#if TARGET_ABI_BITS == 32
2643 abi_ulong __unused2;
2644#endif
2645 abi_ulong msg_ctime;
2646#if TARGET_ABI_BITS == 32
2647 abi_ulong __unused3;
2648#endif
2649 abi_ulong __msg_cbytes;
2650 abi_ulong msg_qnum;
2651 abi_ulong msg_qbytes;
2652 abi_ulong msg_lspid;
2653 abi_ulong msg_lrpid;
2654 abi_ulong __unused4;
2655 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002656};
2657
bellard579a97f2007-11-11 14:26:47 +00002658static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2659 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002660{
2661 struct target_msqid_ds *target_md;
2662
bellard579a97f2007-11-11 14:26:47 +00002663 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2664 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002665 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2666 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002667 host_md->msg_stime = tswapal(target_md->msg_stime);
2668 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2669 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2670 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2671 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2672 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2673 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2674 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002675 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002676 return 0;
ths1bc012f2007-06-03 14:27:49 +00002677}
2678
bellard579a97f2007-11-11 14:26:47 +00002679static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2680 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002681{
2682 struct target_msqid_ds *target_md;
2683
bellard579a97f2007-11-11 14:26:47 +00002684 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2685 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002686 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2687 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002688 target_md->msg_stime = tswapal(host_md->msg_stime);
2689 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2690 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2691 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2692 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2693 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2694 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2695 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002696 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002697 return 0;
ths1bc012f2007-06-03 14:27:49 +00002698}
2699
aurel321c54ff92008-10-13 21:08:44 +00002700struct target_msginfo {
2701 int msgpool;
2702 int msgmap;
2703 int msgmax;
2704 int msgmnb;
2705 int msgmni;
2706 int msgssz;
2707 int msgtql;
2708 unsigned short int msgseg;
2709};
2710
2711static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2712 struct msginfo *host_msginfo)
2713{
2714 struct target_msginfo *target_msginfo;
2715 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2716 return -TARGET_EFAULT;
2717 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2718 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2719 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2720 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2721 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2722 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2723 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2724 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2725 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002726 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002727}
2728
2729static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002730{
2731 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002732 struct msginfo msginfo;
2733 abi_long ret = -TARGET_EINVAL;
2734
2735 cmd &= 0xff;
2736
2737 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002738 case IPC_STAT:
2739 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002740 case MSG_STAT:
2741 if (target_to_host_msqid_ds(&dsarg,ptr))
2742 return -TARGET_EFAULT;
2743 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2744 if (host_to_target_msqid_ds(ptr,&dsarg))
2745 return -TARGET_EFAULT;
2746 break;
2747 case IPC_RMID:
2748 ret = get_errno(msgctl(msgid, cmd, NULL));
2749 break;
2750 case IPC_INFO:
2751 case MSG_INFO:
2752 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2753 if (host_to_target_msginfo(ptr, &msginfo))
2754 return -TARGET_EFAULT;
2755 break;
ths1bc012f2007-06-03 14:27:49 +00002756 }
aurel321c54ff92008-10-13 21:08:44 +00002757
ths1bc012f2007-06-03 14:27:49 +00002758 return ret;
2759}
2760
2761struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002762 abi_long mtype;
2763 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002764};
2765
blueswir1992f48a2007-10-14 16:27:31 +00002766static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2767 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002768{
2769 struct target_msgbuf *target_mb;
2770 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002771 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002772
bellard579a97f2007-11-11 14:26:47 +00002773 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2774 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002775 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002776 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002777 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002778 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2779 free(host_mb);
2780 unlock_user_struct(target_mb, msgp, 0);
2781
2782 return ret;
2783}
2784
blueswir1992f48a2007-10-14 16:27:31 +00002785static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002786 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002787 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002788{
2789 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002790 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002791 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002792 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002793
bellard579a97f2007-11-11 14:26:47 +00002794 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2795 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002796
ths1bc012f2007-06-03 14:27:49 +00002797 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002798 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002799
bellard579a97f2007-11-11 14:26:47 +00002800 if (ret > 0) {
2801 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2802 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2803 if (!target_mtext) {
2804 ret = -TARGET_EFAULT;
2805 goto end;
2806 }
aurel321c54ff92008-10-13 21:08:44 +00002807 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002808 unlock_user(target_mtext, target_mtext_addr, ret);
2809 }
aurel321c54ff92008-10-13 21:08:44 +00002810
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002811 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002812 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002813
bellard579a97f2007-11-11 14:26:47 +00002814end:
2815 if (target_mb)
2816 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002817 return ret;
2818}
2819
Riku Voipio88a8c982009-04-03 10:42:00 +03002820struct target_shmid_ds
2821{
2822 struct target_ipc_perm shm_perm;
2823 abi_ulong shm_segsz;
2824 abi_ulong shm_atime;
2825#if TARGET_ABI_BITS == 32
2826 abi_ulong __unused1;
2827#endif
2828 abi_ulong shm_dtime;
2829#if TARGET_ABI_BITS == 32
2830 abi_ulong __unused2;
2831#endif
2832 abi_ulong shm_ctime;
2833#if TARGET_ABI_BITS == 32
2834 abi_ulong __unused3;
2835#endif
2836 int shm_cpid;
2837 int shm_lpid;
2838 abi_ulong shm_nattch;
2839 unsigned long int __unused4;
2840 unsigned long int __unused5;
2841};
2842
2843static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2844 abi_ulong target_addr)
2845{
2846 struct target_shmid_ds *target_sd;
2847
2848 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2849 return -TARGET_EFAULT;
2850 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2851 return -TARGET_EFAULT;
2852 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2853 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2854 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2855 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2856 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2857 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2858 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2859 unlock_user_struct(target_sd, target_addr, 0);
2860 return 0;
2861}
2862
2863static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2864 struct shmid_ds *host_sd)
2865{
2866 struct target_shmid_ds *target_sd;
2867
2868 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2869 return -TARGET_EFAULT;
2870 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2871 return -TARGET_EFAULT;
2872 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2873 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2874 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2875 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2876 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2877 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2878 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2879 unlock_user_struct(target_sd, target_addr, 1);
2880 return 0;
2881}
2882
2883struct target_shminfo {
2884 abi_ulong shmmax;
2885 abi_ulong shmmin;
2886 abi_ulong shmmni;
2887 abi_ulong shmseg;
2888 abi_ulong shmall;
2889};
2890
2891static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2892 struct shminfo *host_shminfo)
2893{
2894 struct target_shminfo *target_shminfo;
2895 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2896 return -TARGET_EFAULT;
2897 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2898 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2899 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2900 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2901 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2902 unlock_user_struct(target_shminfo, target_addr, 1);
2903 return 0;
2904}
2905
2906struct target_shm_info {
2907 int used_ids;
2908 abi_ulong shm_tot;
2909 abi_ulong shm_rss;
2910 abi_ulong shm_swp;
2911 abi_ulong swap_attempts;
2912 abi_ulong swap_successes;
2913};
2914
2915static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2916 struct shm_info *host_shm_info)
2917{
2918 struct target_shm_info *target_shm_info;
2919 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2920 return -TARGET_EFAULT;
2921 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2922 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2923 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2924 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2925 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2926 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2927 unlock_user_struct(target_shm_info, target_addr, 1);
2928 return 0;
2929}
2930
2931static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2932{
2933 struct shmid_ds dsarg;
2934 struct shminfo shminfo;
2935 struct shm_info shm_info;
2936 abi_long ret = -TARGET_EINVAL;
2937
2938 cmd &= 0xff;
2939
2940 switch(cmd) {
2941 case IPC_STAT:
2942 case IPC_SET:
2943 case SHM_STAT:
2944 if (target_to_host_shmid_ds(&dsarg, buf))
2945 return -TARGET_EFAULT;
2946 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2947 if (host_to_target_shmid_ds(buf, &dsarg))
2948 return -TARGET_EFAULT;
2949 break;
2950 case IPC_INFO:
2951 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2952 if (host_to_target_shminfo(buf, &shminfo))
2953 return -TARGET_EFAULT;
2954 break;
2955 case SHM_INFO:
2956 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2957 if (host_to_target_shm_info(buf, &shm_info))
2958 return -TARGET_EFAULT;
2959 break;
2960 case IPC_RMID:
2961 case SHM_LOCK:
2962 case SHM_UNLOCK:
2963 ret = get_errno(shmctl(shmid, cmd, NULL));
2964 break;
2965 }
2966
2967 return ret;
2968}
2969
2970static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2971{
2972 abi_long raddr;
2973 void *host_raddr;
2974 struct shmid_ds shm_info;
2975 int i,ret;
2976
2977 /* find out the length of the shared memory segment */
2978 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2979 if (is_error(ret)) {
2980 /* can't get length, bail out */
2981 return ret;
2982 }
2983
2984 mmap_lock();
2985
2986 if (shmaddr)
2987 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2988 else {
2989 abi_ulong mmap_start;
2990
2991 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2992
2993 if (mmap_start == -1) {
2994 errno = ENOMEM;
2995 host_raddr = (void *)-1;
2996 } else
2997 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2998 }
2999
3000 if (host_raddr == (void *)-1) {
3001 mmap_unlock();
3002 return get_errno((long)host_raddr);
3003 }
3004 raddr=h2g((unsigned long)host_raddr);
3005
3006 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3007 PAGE_VALID | PAGE_READ |
3008 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3009
3010 for (i = 0; i < N_SHM_REGIONS; i++) {
3011 if (shm_regions[i].start == 0) {
3012 shm_regions[i].start = raddr;
3013 shm_regions[i].size = shm_info.shm_segsz;
3014 break;
3015 }
3016 }
3017
3018 mmap_unlock();
3019 return raddr;
3020
3021}
3022
3023static inline abi_long do_shmdt(abi_ulong shmaddr)
3024{
3025 int i;
3026
3027 for (i = 0; i < N_SHM_REGIONS; ++i) {
3028 if (shm_regions[i].start == shmaddr) {
3029 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003030 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003031 break;
3032 }
3033 }
3034
3035 return get_errno(shmdt(g2h(shmaddr)));
3036}
3037
aurel321c54ff92008-10-13 21:08:44 +00003038#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003039/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003040/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003041static abi_long do_ipc(unsigned int call, int first,
3042 int second, int third,
3043 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003044{
3045 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003046 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003047
3048 version = call >> 16;
3049 call &= 0xffff;
3050
3051 switch (call) {
thsfa294812007-02-02 22:05:00 +00003052 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003053 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003054 break;
3055
3056 case IPCOP_semget:
3057 ret = get_errno(semget(first, second, third));
3058 break;
3059
3060 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003061 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003062 break;
thsd96372e2007-02-02 22:05:44 +00003063
aurel321c54ff92008-10-13 21:08:44 +00003064 case IPCOP_msgget:
3065 ret = get_errno(msgget(first, second));
3066 break;
thsd96372e2007-02-02 22:05:44 +00003067
aurel321c54ff92008-10-13 21:08:44 +00003068 case IPCOP_msgsnd:
3069 ret = do_msgsnd(first, ptr, second, third);
3070 break;
thsd96372e2007-02-02 22:05:44 +00003071
aurel321c54ff92008-10-13 21:08:44 +00003072 case IPCOP_msgctl:
3073 ret = do_msgctl(first, second, ptr);
3074 break;
thsd96372e2007-02-02 22:05:44 +00003075
aurel321c54ff92008-10-13 21:08:44 +00003076 case IPCOP_msgrcv:
3077 switch (version) {
3078 case 0:
3079 {
3080 struct target_ipc_kludge {
3081 abi_long msgp;
3082 abi_long msgtyp;
3083 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003084
aurel321c54ff92008-10-13 21:08:44 +00003085 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3086 ret = -TARGET_EFAULT;
3087 break;
ths1bc012f2007-06-03 14:27:49 +00003088 }
aurel321c54ff92008-10-13 21:08:44 +00003089
3090 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3091
3092 unlock_user_struct(tmp, ptr, 0);
3093 break;
3094 }
3095 default:
3096 ret = do_msgrcv(first, ptr, second, fifth, third);
3097 }
3098 break;
thsd96372e2007-02-02 22:05:44 +00003099
bellard8853f862004-02-22 14:57:26 +00003100 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003101 switch (version) {
3102 default:
bellard5a4a8982007-11-11 17:39:18 +00003103 {
3104 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003105 raddr = do_shmat(first, ptr, second);
3106 if (is_error(raddr))
3107 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003108 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003109 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003110 break;
3111 }
3112 case 1:
3113 ret = -TARGET_EINVAL;
3114 break;
bellard5a4a8982007-11-11 17:39:18 +00003115 }
bellard8853f862004-02-22 14:57:26 +00003116 break;
3117 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003118 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003119 break;
3120
3121 case IPCOP_shmget:
3122 /* IPC_* flag values are the same on all linux platforms */
3123 ret = get_errno(shmget(first, second, third));
3124 break;
3125
3126 /* IPC_* and SHM_* command values are the same on all linux platforms */
3127 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003128 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003129 break;
3130 default:
j_mayer32407102007-09-26 23:01:49 +00003131 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003132 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003133 break;
3134 }
3135 return ret;
3136}
j_mayer32407102007-09-26 23:01:49 +00003137#endif
bellard8853f862004-02-22 14:57:26 +00003138
bellard31e31b82003-02-18 22:55:36 +00003139/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003140
Blue Swirl001faf32009-05-13 17:53:17 +00003141#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003142#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3143enum {
3144#include "syscall_types.h"
3145};
3146#undef STRUCT
3147#undef STRUCT_SPECIAL
3148
Blue Swirl001faf32009-05-13 17:53:17 +00003149#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003150#define STRUCT_SPECIAL(name)
3151#include "syscall_types.h"
3152#undef STRUCT
3153#undef STRUCT_SPECIAL
3154
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003155typedef struct IOCTLEntry IOCTLEntry;
3156
3157typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3158 int fd, abi_long cmd, abi_long arg);
3159
3160struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003161 unsigned int target_cmd;
3162 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003163 const char *name;
3164 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003165 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003166 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003167};
bellard31e31b82003-02-18 22:55:36 +00003168
3169#define IOC_R 0x0001
3170#define IOC_W 0x0002
3171#define IOC_RW (IOC_R | IOC_W)
3172
3173#define MAX_STRUCT_SIZE 4096
3174
Peter Maydelldace20d2011-01-10 13:11:24 +00003175#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003176/* So fiemap access checks don't overflow on 32 bit systems.
3177 * This is very slightly smaller than the limit imposed by
3178 * the underlying kernel.
3179 */
3180#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3181 / sizeof(struct fiemap_extent))
3182
3183static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3184 int fd, abi_long cmd, abi_long arg)
3185{
3186 /* The parameter for this ioctl is a struct fiemap followed
3187 * by an array of struct fiemap_extent whose size is set
3188 * in fiemap->fm_extent_count. The array is filled in by the
3189 * ioctl.
3190 */
3191 int target_size_in, target_size_out;
3192 struct fiemap *fm;
3193 const argtype *arg_type = ie->arg_type;
3194 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3195 void *argptr, *p;
3196 abi_long ret;
3197 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3198 uint32_t outbufsz;
3199 int free_fm = 0;
3200
3201 assert(arg_type[0] == TYPE_PTR);
3202 assert(ie->access == IOC_RW);
3203 arg_type++;
3204 target_size_in = thunk_type_size(arg_type, 0);
3205 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3206 if (!argptr) {
3207 return -TARGET_EFAULT;
3208 }
3209 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3210 unlock_user(argptr, arg, 0);
3211 fm = (struct fiemap *)buf_temp;
3212 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3213 return -TARGET_EINVAL;
3214 }
3215
3216 outbufsz = sizeof (*fm) +
3217 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3218
3219 if (outbufsz > MAX_STRUCT_SIZE) {
3220 /* We can't fit all the extents into the fixed size buffer.
3221 * Allocate one that is large enough and use it instead.
3222 */
3223 fm = malloc(outbufsz);
3224 if (!fm) {
3225 return -TARGET_ENOMEM;
3226 }
3227 memcpy(fm, buf_temp, sizeof(struct fiemap));
3228 free_fm = 1;
3229 }
3230 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3231 if (!is_error(ret)) {
3232 target_size_out = target_size_in;
3233 /* An extent_count of 0 means we were only counting the extents
3234 * so there are no structs to copy
3235 */
3236 if (fm->fm_extent_count != 0) {
3237 target_size_out += fm->fm_mapped_extents * extent_size;
3238 }
3239 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3240 if (!argptr) {
3241 ret = -TARGET_EFAULT;
3242 } else {
3243 /* Convert the struct fiemap */
3244 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3245 if (fm->fm_extent_count != 0) {
3246 p = argptr + target_size_in;
3247 /* ...and then all the struct fiemap_extents */
3248 for (i = 0; i < fm->fm_mapped_extents; i++) {
3249 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3250 THUNK_TARGET);
3251 p += extent_size;
3252 }
3253 }
3254 unlock_user(argptr, arg, target_size_out);
3255 }
3256 }
3257 if (free_fm) {
3258 free(fm);
3259 }
3260 return ret;
3261}
Peter Maydelldace20d2011-01-10 13:11:24 +00003262#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003263
Laurent Vivier059c2f22011-03-30 00:12:12 +02003264static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3265 int fd, abi_long cmd, abi_long arg)
3266{
3267 const argtype *arg_type = ie->arg_type;
3268 int target_size;
3269 void *argptr;
3270 int ret;
3271 struct ifconf *host_ifconf;
3272 uint32_t outbufsz;
3273 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3274 int target_ifreq_size;
3275 int nb_ifreq;
3276 int free_buf = 0;
3277 int i;
3278 int target_ifc_len;
3279 abi_long target_ifc_buf;
3280 int host_ifc_len;
3281 char *host_ifc_buf;
3282
3283 assert(arg_type[0] == TYPE_PTR);
3284 assert(ie->access == IOC_RW);
3285
3286 arg_type++;
3287 target_size = thunk_type_size(arg_type, 0);
3288
3289 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3290 if (!argptr)
3291 return -TARGET_EFAULT;
3292 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3293 unlock_user(argptr, arg, 0);
3294
3295 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3296 target_ifc_len = host_ifconf->ifc_len;
3297 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3298
3299 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3300 nb_ifreq = target_ifc_len / target_ifreq_size;
3301 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3302
3303 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3304 if (outbufsz > MAX_STRUCT_SIZE) {
3305 /* We can't fit all the extents into the fixed size buffer.
3306 * Allocate one that is large enough and use it instead.
3307 */
3308 host_ifconf = malloc(outbufsz);
3309 if (!host_ifconf) {
3310 return -TARGET_ENOMEM;
3311 }
3312 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3313 free_buf = 1;
3314 }
3315 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3316
3317 host_ifconf->ifc_len = host_ifc_len;
3318 host_ifconf->ifc_buf = host_ifc_buf;
3319
3320 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3321 if (!is_error(ret)) {
3322 /* convert host ifc_len to target ifc_len */
3323
3324 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3325 target_ifc_len = nb_ifreq * target_ifreq_size;
3326 host_ifconf->ifc_len = target_ifc_len;
3327
3328 /* restore target ifc_buf */
3329
3330 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3331
3332 /* copy struct ifconf to target user */
3333
3334 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3335 if (!argptr)
3336 return -TARGET_EFAULT;
3337 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3338 unlock_user(argptr, arg, target_size);
3339
3340 /* copy ifreq[] to target user */
3341
3342 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3343 for (i = 0; i < nb_ifreq ; i++) {
3344 thunk_convert(argptr + i * target_ifreq_size,
3345 host_ifc_buf + i * sizeof(struct ifreq),
3346 ifreq_arg_type, THUNK_TARGET);
3347 }
3348 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3349 }
3350
3351 if (free_buf) {
3352 free(host_ifconf);
3353 }
3354
3355 return ret;
3356}
3357
Alexander Graf56e904e2012-01-31 18:42:06 +01003358static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3359 abi_long cmd, abi_long arg)
3360{
3361 void *argptr;
3362 struct dm_ioctl *host_dm;
3363 abi_long guest_data;
3364 uint32_t guest_data_size;
3365 int target_size;
3366 const argtype *arg_type = ie->arg_type;
3367 abi_long ret;
3368 void *big_buf = NULL;
3369 char *host_data;
3370
3371 arg_type++;
3372 target_size = thunk_type_size(arg_type, 0);
3373 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3374 if (!argptr) {
3375 ret = -TARGET_EFAULT;
3376 goto out;
3377 }
3378 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3379 unlock_user(argptr, arg, 0);
3380
3381 /* buf_temp is too small, so fetch things into a bigger buffer */
3382 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3383 memcpy(big_buf, buf_temp, target_size);
3384 buf_temp = big_buf;
3385 host_dm = big_buf;
3386
3387 guest_data = arg + host_dm->data_start;
3388 if ((guest_data - arg) < 0) {
3389 ret = -EINVAL;
3390 goto out;
3391 }
3392 guest_data_size = host_dm->data_size - host_dm->data_start;
3393 host_data = (char*)host_dm + host_dm->data_start;
3394
3395 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3396 switch (ie->host_cmd) {
3397 case DM_REMOVE_ALL:
3398 case DM_LIST_DEVICES:
3399 case DM_DEV_CREATE:
3400 case DM_DEV_REMOVE:
3401 case DM_DEV_SUSPEND:
3402 case DM_DEV_STATUS:
3403 case DM_DEV_WAIT:
3404 case DM_TABLE_STATUS:
3405 case DM_TABLE_CLEAR:
3406 case DM_TABLE_DEPS:
3407 case DM_LIST_VERSIONS:
3408 /* no input data */
3409 break;
3410 case DM_DEV_RENAME:
3411 case DM_DEV_SET_GEOMETRY:
3412 /* data contains only strings */
3413 memcpy(host_data, argptr, guest_data_size);
3414 break;
3415 case DM_TARGET_MSG:
3416 memcpy(host_data, argptr, guest_data_size);
3417 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3418 break;
3419 case DM_TABLE_LOAD:
3420 {
3421 void *gspec = argptr;
3422 void *cur_data = host_data;
3423 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3424 int spec_size = thunk_type_size(arg_type, 0);
3425 int i;
3426
3427 for (i = 0; i < host_dm->target_count; i++) {
3428 struct dm_target_spec *spec = cur_data;
3429 uint32_t next;
3430 int slen;
3431
3432 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3433 slen = strlen((char*)gspec + spec_size) + 1;
3434 next = spec->next;
3435 spec->next = sizeof(*spec) + slen;
3436 strcpy((char*)&spec[1], gspec + spec_size);
3437 gspec += next;
3438 cur_data += spec->next;
3439 }
3440 break;
3441 }
3442 default:
3443 ret = -TARGET_EINVAL;
3444 goto out;
3445 }
3446 unlock_user(argptr, guest_data, 0);
3447
3448 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3449 if (!is_error(ret)) {
3450 guest_data = arg + host_dm->data_start;
3451 guest_data_size = host_dm->data_size - host_dm->data_start;
3452 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3453 switch (ie->host_cmd) {
3454 case DM_REMOVE_ALL:
3455 case DM_DEV_CREATE:
3456 case DM_DEV_REMOVE:
3457 case DM_DEV_RENAME:
3458 case DM_DEV_SUSPEND:
3459 case DM_DEV_STATUS:
3460 case DM_TABLE_LOAD:
3461 case DM_TABLE_CLEAR:
3462 case DM_TARGET_MSG:
3463 case DM_DEV_SET_GEOMETRY:
3464 /* no return data */
3465 break;
3466 case DM_LIST_DEVICES:
3467 {
3468 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3469 uint32_t remaining_data = guest_data_size;
3470 void *cur_data = argptr;
3471 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3472 int nl_size = 12; /* can't use thunk_size due to alignment */
3473
3474 while (1) {
3475 uint32_t next = nl->next;
3476 if (next) {
3477 nl->next = nl_size + (strlen(nl->name) + 1);
3478 }
3479 if (remaining_data < nl->next) {
3480 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3481 break;
3482 }
3483 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3484 strcpy(cur_data + nl_size, nl->name);
3485 cur_data += nl->next;
3486 remaining_data -= nl->next;
3487 if (!next) {
3488 break;
3489 }
3490 nl = (void*)nl + next;
3491 }
3492 break;
3493 }
3494 case DM_DEV_WAIT:
3495 case DM_TABLE_STATUS:
3496 {
3497 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3498 void *cur_data = argptr;
3499 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3500 int spec_size = thunk_type_size(arg_type, 0);
3501 int i;
3502
3503 for (i = 0; i < host_dm->target_count; i++) {
3504 uint32_t next = spec->next;
3505 int slen = strlen((char*)&spec[1]) + 1;
3506 spec->next = (cur_data - argptr) + spec_size + slen;
3507 if (guest_data_size < spec->next) {
3508 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3509 break;
3510 }
3511 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3512 strcpy(cur_data + spec_size, (char*)&spec[1]);
3513 cur_data = argptr + spec->next;
3514 spec = (void*)host_dm + host_dm->data_start + next;
3515 }
3516 break;
3517 }
3518 case DM_TABLE_DEPS:
3519 {
3520 void *hdata = (void*)host_dm + host_dm->data_start;
3521 int count = *(uint32_t*)hdata;
3522 uint64_t *hdev = hdata + 8;
3523 uint64_t *gdev = argptr + 8;
3524 int i;
3525
3526 *(uint32_t*)argptr = tswap32(count);
3527 for (i = 0; i < count; i++) {
3528 *gdev = tswap64(*hdev);
3529 gdev++;
3530 hdev++;
3531 }
3532 break;
3533 }
3534 case DM_LIST_VERSIONS:
3535 {
3536 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3537 uint32_t remaining_data = guest_data_size;
3538 void *cur_data = argptr;
3539 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3540 int vers_size = thunk_type_size(arg_type, 0);
3541
3542 while (1) {
3543 uint32_t next = vers->next;
3544 if (next) {
3545 vers->next = vers_size + (strlen(vers->name) + 1);
3546 }
3547 if (remaining_data < vers->next) {
3548 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3549 break;
3550 }
3551 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3552 strcpy(cur_data + vers_size, vers->name);
3553 cur_data += vers->next;
3554 remaining_data -= vers->next;
3555 if (!next) {
3556 break;
3557 }
3558 vers = (void*)vers + next;
3559 }
3560 break;
3561 }
3562 default:
3563 ret = -TARGET_EINVAL;
3564 goto out;
3565 }
3566 unlock_user(argptr, guest_data, guest_data_size);
3567
3568 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3569 if (!argptr) {
3570 ret = -TARGET_EFAULT;
3571 goto out;
3572 }
3573 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3574 unlock_user(argptr, arg, target_size);
3575 }
3576out:
3577 if (big_buf) {
3578 free(big_buf);
3579 }
3580 return ret;
3581}
3582
blueswir19f106a72008-10-05 10:52:52 +00003583static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003584#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003585 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3586#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3587 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003588#include "ioctls.h"
3589 { 0, 0, },
3590};
3591
pbrook53a59602006-03-25 19:31:22 +00003592/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003593/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003594static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003595{
3596 const IOCTLEntry *ie;
3597 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003598 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003599 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003600 int target_size;
3601 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003602
3603 ie = ioctl_entries;
3604 for(;;) {
3605 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003606 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003607 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003608 }
3609 if (ie->target_cmd == cmd)
3610 break;
3611 ie++;
3612 }
3613 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003614#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003615 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003616#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003617 if (ie->do_ioctl) {
3618 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3619 }
3620
bellard31e31b82003-02-18 22:55:36 +00003621 switch(arg_type[0]) {
3622 case TYPE_NULL:
3623 /* no argument */
3624 ret = get_errno(ioctl(fd, ie->host_cmd));
3625 break;
3626 case TYPE_PTRVOID:
3627 case TYPE_INT:
3628 /* int argment */
3629 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3630 break;
3631 case TYPE_PTR:
3632 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003633 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003634 switch(ie->access) {
3635 case IOC_R:
3636 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3637 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003638 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3639 if (!argptr)
3640 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003641 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3642 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003643 }
3644 break;
3645 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003646 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3647 if (!argptr)
3648 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003649 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3650 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003651 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3652 break;
3653 default:
3654 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003655 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3656 if (!argptr)
3657 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003658 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3659 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003660 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3661 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003662 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3663 if (!argptr)
3664 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003665 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3666 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003667 }
3668 break;
3669 }
3670 break;
3671 default:
j_mayer32407102007-09-26 23:01:49 +00003672 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3673 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003674 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003675 break;
3676 }
3677 return ret;
3678}
3679
blueswir1b39bc502008-10-05 10:51:10 +00003680static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003681 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3682 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3683 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3684 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3685 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3686 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3687 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3688 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3689 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3690 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3691 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3692 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3693 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3694 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3695 { 0, 0, 0, 0 }
3696};
3697
blueswir1b39bc502008-10-05 10:51:10 +00003698static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003699 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3700 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3701 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3702 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3703 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3704 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3705 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3706 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3707 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3708 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3709 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3710 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3711 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3712 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3713 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3714 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3715 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3716 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3717 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3718 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3719 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3720 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3721 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3722 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3723 { 0, 0, 0, 0 }
3724};
3725
blueswir1b39bc502008-10-05 10:51:10 +00003726static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003727 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3728 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3729 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3730 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3731 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3732 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3733 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3734 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3735 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3736 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3737 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3738 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3739 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3740 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3741 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3742 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3743 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3744 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3745 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3746 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3747 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3748 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3749 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3750 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3751 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3752 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3753 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3754 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3755 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3756 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3757 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3758 { 0, 0, 0, 0 }
3759};
3760
blueswir1b39bc502008-10-05 10:51:10 +00003761static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003762 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3763 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3764 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3765 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3766 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3767 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3768 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3769 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3770 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3771 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3772 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3773 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3774 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3775 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3776 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3777 { 0, 0, 0, 0 }
3778};
3779
3780static void target_to_host_termios (void *dst, const void *src)
3781{
3782 struct host_termios *host = dst;
3783 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003784
ths5fafdf22007-09-16 21:08:06 +00003785 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003786 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003787 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003788 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003789 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003790 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003791 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003792 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3793 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003794
Arnaud Patard44607122009-04-21 17:39:08 +03003795 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003796 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3797 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003798 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003799 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003800 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003801 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003802 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003803 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003804 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003805 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3806 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003807 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3808 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3809 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3810 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3811 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003812 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003813}
ths3b46e622007-09-17 08:09:54 +00003814
bellard31e31b82003-02-18 22:55:36 +00003815static void host_to_target_termios (void *dst, const void *src)
3816{
3817 struct target_termios *target = dst;
3818 const struct host_termios *host = src;
3819
ths5fafdf22007-09-16 21:08:06 +00003820 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003821 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003822 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003823 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003824 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003825 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003826 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003827 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3828 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003829
Arnaud Patard44607122009-04-21 17:39:08 +03003830 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003831 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3832 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3833 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3834 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3835 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3836 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3837 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3838 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3839 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3840 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3841 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3842 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3843 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3844 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3845 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3846 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3847 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3848}
3849
blueswir18e853dc2008-10-05 10:49:32 +00003850static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003851 .convert = { host_to_target_termios, target_to_host_termios },
3852 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3853 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3854};
3855
bellard5286db72003-06-05 00:57:30 +00003856static bitmask_transtbl mmap_flags_tbl[] = {
3857 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3858 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3859 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3860 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3861 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3862 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3863 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3864 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3865 { 0, 0, 0, 0 }
3866};
3867
bellard2ab83ea2003-06-15 19:56:46 +00003868#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003869
3870/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003871static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003872
bellard03acab62007-11-11 14:57:14 +00003873static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003874{
3875 int size;
pbrook53a59602006-03-25 19:31:22 +00003876 void *p;
bellard6dbad632003-03-16 18:05:05 +00003877
3878 if (!ldt_table)
3879 return 0;
3880 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3881 if (size > bytecount)
3882 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003883 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3884 if (!p)
bellard03acab62007-11-11 14:57:14 +00003885 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003886 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003887 memcpy(p, ldt_table, size);
3888 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003889 return size;
3890}
3891
3892/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003893static abi_long write_ldt(CPUX86State *env,
3894 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003895{
3896 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003897 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003898 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003899 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003900 uint32_t *lp, entry_1, entry_2;
3901
3902 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003903 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003904 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003905 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003906 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003907 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003908 ldt_info.limit = tswap32(target_ldt_info->limit);
3909 ldt_info.flags = tswap32(target_ldt_info->flags);
3910 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003911
bellard6dbad632003-03-16 18:05:05 +00003912 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003913 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003914 seg_32bit = ldt_info.flags & 1;
3915 contents = (ldt_info.flags >> 1) & 3;
3916 read_exec_only = (ldt_info.flags >> 3) & 1;
3917 limit_in_pages = (ldt_info.flags >> 4) & 1;
3918 seg_not_present = (ldt_info.flags >> 5) & 1;
3919 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003920#ifdef TARGET_ABI32
3921 lm = 0;
3922#else
3923 lm = (ldt_info.flags >> 7) & 1;
3924#endif
bellard6dbad632003-03-16 18:05:05 +00003925 if (contents == 3) {
3926 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003927 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003928 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003929 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003930 }
3931 /* allocate the LDT */
3932 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003933 env->ldt.base = target_mmap(0,
3934 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3935 PROT_READ|PROT_WRITE,
3936 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3937 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003938 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003939 memset(g2h(env->ldt.base), 0,
3940 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003941 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003942 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003943 }
3944
3945 /* NOTE: same code as Linux kernel */
3946 /* Allow LDTs to be cleared by the user. */
3947 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3948 if (oldmode ||
3949 (contents == 0 &&
3950 read_exec_only == 1 &&
3951 seg_32bit == 0 &&
3952 limit_in_pages == 0 &&
3953 seg_not_present == 1 &&
3954 useable == 0 )) {
3955 entry_1 = 0;
3956 entry_2 = 0;
3957 goto install;
3958 }
3959 }
ths3b46e622007-09-17 08:09:54 +00003960
bellard6dbad632003-03-16 18:05:05 +00003961 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3962 (ldt_info.limit & 0x0ffff);
3963 entry_2 = (ldt_info.base_addr & 0xff000000) |
3964 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3965 (ldt_info.limit & 0xf0000) |
3966 ((read_exec_only ^ 1) << 9) |
3967 (contents << 10) |
3968 ((seg_not_present ^ 1) << 15) |
3969 (seg_32bit << 22) |
3970 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003971 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003972 0x7000;
3973 if (!oldmode)
3974 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003975
bellard6dbad632003-03-16 18:05:05 +00003976 /* Install the new entry ... */
3977install:
3978 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3979 lp[0] = tswap32(entry_1);
3980 lp[1] = tswap32(entry_2);
3981 return 0;
3982}
3983
3984/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003985static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3986 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003987{
bellard03acab62007-11-11 14:57:14 +00003988 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003989
bellard6dbad632003-03-16 18:05:05 +00003990 switch (func) {
3991 case 0:
3992 ret = read_ldt(ptr, bytecount);
3993 break;
3994 case 1:
3995 ret = write_ldt(env, ptr, bytecount, 1);
3996 break;
3997 case 0x11:
3998 ret = write_ldt(env, ptr, bytecount, 0);
3999 break;
bellard03acab62007-11-11 14:57:14 +00004000 default:
4001 ret = -TARGET_ENOSYS;
4002 break;
bellard6dbad632003-03-16 18:05:05 +00004003 }
4004 return ret;
4005}
bellard1b6b0292003-03-22 17:31:38 +00004006
blueswir14583f582008-08-24 10:35:55 +00004007#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00004008static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004009{
4010 uint64_t *gdt_table = g2h(env->gdt.base);
4011 struct target_modify_ldt_ldt_s ldt_info;
4012 struct target_modify_ldt_ldt_s *target_ldt_info;
4013 int seg_32bit, contents, read_exec_only, limit_in_pages;
4014 int seg_not_present, useable, lm;
4015 uint32_t *lp, entry_1, entry_2;
4016 int i;
4017
4018 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4019 if (!target_ldt_info)
4020 return -TARGET_EFAULT;
4021 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004022 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004023 ldt_info.limit = tswap32(target_ldt_info->limit);
4024 ldt_info.flags = tswap32(target_ldt_info->flags);
4025 if (ldt_info.entry_number == -1) {
4026 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4027 if (gdt_table[i] == 0) {
4028 ldt_info.entry_number = i;
4029 target_ldt_info->entry_number = tswap32(i);
4030 break;
4031 }
4032 }
4033 }
4034 unlock_user_struct(target_ldt_info, ptr, 1);
4035
4036 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4037 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4038 return -TARGET_EINVAL;
4039 seg_32bit = ldt_info.flags & 1;
4040 contents = (ldt_info.flags >> 1) & 3;
4041 read_exec_only = (ldt_info.flags >> 3) & 1;
4042 limit_in_pages = (ldt_info.flags >> 4) & 1;
4043 seg_not_present = (ldt_info.flags >> 5) & 1;
4044 useable = (ldt_info.flags >> 6) & 1;
4045#ifdef TARGET_ABI32
4046 lm = 0;
4047#else
4048 lm = (ldt_info.flags >> 7) & 1;
4049#endif
4050
4051 if (contents == 3) {
4052 if (seg_not_present == 0)
4053 return -TARGET_EINVAL;
4054 }
4055
4056 /* NOTE: same code as Linux kernel */
4057 /* Allow LDTs to be cleared by the user. */
4058 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4059 if ((contents == 0 &&
4060 read_exec_only == 1 &&
4061 seg_32bit == 0 &&
4062 limit_in_pages == 0 &&
4063 seg_not_present == 1 &&
4064 useable == 0 )) {
4065 entry_1 = 0;
4066 entry_2 = 0;
4067 goto install;
4068 }
4069 }
4070
4071 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4072 (ldt_info.limit & 0x0ffff);
4073 entry_2 = (ldt_info.base_addr & 0xff000000) |
4074 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4075 (ldt_info.limit & 0xf0000) |
4076 ((read_exec_only ^ 1) << 9) |
4077 (contents << 10) |
4078 ((seg_not_present ^ 1) << 15) |
4079 (seg_32bit << 22) |
4080 (limit_in_pages << 23) |
4081 (useable << 20) |
4082 (lm << 21) |
4083 0x7000;
4084
4085 /* Install the new entry ... */
4086install:
4087 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4088 lp[0] = tswap32(entry_1);
4089 lp[1] = tswap32(entry_2);
4090 return 0;
4091}
4092
blueswir18fcd3692008-08-17 20:26:25 +00004093static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004094{
4095 struct target_modify_ldt_ldt_s *target_ldt_info;
4096 uint64_t *gdt_table = g2h(env->gdt.base);
4097 uint32_t base_addr, limit, flags;
4098 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4099 int seg_not_present, useable, lm;
4100 uint32_t *lp, entry_1, entry_2;
4101
4102 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4103 if (!target_ldt_info)
4104 return -TARGET_EFAULT;
4105 idx = tswap32(target_ldt_info->entry_number);
4106 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4107 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4108 unlock_user_struct(target_ldt_info, ptr, 1);
4109 return -TARGET_EINVAL;
4110 }
4111 lp = (uint32_t *)(gdt_table + idx);
4112 entry_1 = tswap32(lp[0]);
4113 entry_2 = tswap32(lp[1]);
4114
4115 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4116 contents = (entry_2 >> 10) & 3;
4117 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4118 seg_32bit = (entry_2 >> 22) & 1;
4119 limit_in_pages = (entry_2 >> 23) & 1;
4120 useable = (entry_2 >> 20) & 1;
4121#ifdef TARGET_ABI32
4122 lm = 0;
4123#else
4124 lm = (entry_2 >> 21) & 1;
4125#endif
4126 flags = (seg_32bit << 0) | (contents << 1) |
4127 (read_exec_only << 3) | (limit_in_pages << 4) |
4128 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4129 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4130 base_addr = (entry_1 >> 16) |
4131 (entry_2 & 0xff000000) |
4132 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004133 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004134 target_ldt_info->limit = tswap32(limit);
4135 target_ldt_info->flags = tswap32(flags);
4136 unlock_user_struct(target_ldt_info, ptr, 1);
4137 return 0;
4138}
blueswir14583f582008-08-24 10:35:55 +00004139#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004140
bellardd2fd1af2007-11-14 18:08:56 +00004141#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004142static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004143{
Juan Quintela1add8692011-06-16 17:37:09 +01004144 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004145 abi_ulong val;
4146 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004147
bellardd2fd1af2007-11-14 18:08:56 +00004148 switch(code) {
4149 case TARGET_ARCH_SET_GS:
4150 case TARGET_ARCH_SET_FS:
4151 if (code == TARGET_ARCH_SET_GS)
4152 idx = R_GS;
4153 else
4154 idx = R_FS;
4155 cpu_x86_load_seg(env, idx, 0);
4156 env->segs[idx].base = addr;
4157 break;
4158 case TARGET_ARCH_GET_GS:
4159 case TARGET_ARCH_GET_FS:
4160 if (code == TARGET_ARCH_GET_GS)
4161 idx = R_GS;
4162 else
4163 idx = R_FS;
4164 val = env->segs[idx].base;
4165 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004166 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004167 break;
4168 default:
4169 ret = -TARGET_EINVAL;
4170 break;
4171 }
Juan Quintela1add8692011-06-16 17:37:09 +01004172 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004173}
4174#endif
4175
bellard2ab83ea2003-06-15 19:56:46 +00004176#endif /* defined(TARGET_I386) */
4177
Riku Voipio05098a92011-03-04 15:27:29 +02004178#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004179
Riku Voipio05098a92011-03-04 15:27:29 +02004180#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004181
4182static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4183typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004184 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004185 pthread_mutex_t mutex;
4186 pthread_cond_t cond;
4187 pthread_t thread;
4188 uint32_t tid;
4189 abi_ulong child_tidptr;
4190 abi_ulong parent_tidptr;
4191 sigset_t sigmask;
4192} new_thread_info;
4193
4194static void *clone_func(void *arg)
4195{
4196 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004197 CPUArchState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004198 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004199
4200 env = info->env;
4201 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004202 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004203 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004204 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004205 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004206 if (info->child_tidptr)
4207 put_user_u32(info->tid, info->child_tidptr);
4208 if (info->parent_tidptr)
4209 put_user_u32(info->tid, info->parent_tidptr);
4210 /* Enable signals. */
4211 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4212 /* Signal to the parent that we're ready. */
4213 pthread_mutex_lock(&info->mutex);
4214 pthread_cond_broadcast(&info->cond);
4215 pthread_mutex_unlock(&info->mutex);
4216 /* Wait until the parent has finshed initializing the tls state. */
4217 pthread_mutex_lock(&clone_lock);
4218 pthread_mutex_unlock(&clone_lock);
4219 cpu_loop(env);
4220 /* never exits */
4221 return NULL;
4222}
4223#else
bellard1b6b0292003-03-22 17:31:38 +00004224
4225static int clone_func(void *arg)
4226{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004227 CPUArchState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00004228 cpu_loop(env);
4229 /* never exits */
4230 return 0;
4231}
pbrookd865bab2008-06-07 22:12:17 +00004232#endif
bellard1b6b0292003-03-22 17:31:38 +00004233
ths0da46a62007-10-20 20:23:07 +00004234/* do_fork() Must return host values and target errnos (unlike most
4235 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004236static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004237 abi_ulong parent_tidptr, target_ulong newtls,
4238 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004239{
4240 int ret;
bellard5cd43932003-03-29 16:54:36 +00004241 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004242 CPUArchState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004243#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004244 unsigned int nptl_flags;
4245 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02004246#else
4247 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00004248#endif
ths3b46e622007-09-17 08:09:54 +00004249
balrog436d1242008-09-21 02:39:45 +00004250 /* Emulate vfork() with fork() */
4251 if (flags & CLONE_VFORK)
4252 flags &= ~(CLONE_VFORK | CLONE_VM);
4253
bellard1b6b0292003-03-22 17:31:38 +00004254 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004255 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004256#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004257 new_thread_info info;
4258 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004259#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004260 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004261 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004262 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004263 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004264#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färber1bba0dc2012-02-08 03:03:33 +01004265 cpu_state_reset(new_env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004266#endif
pbrook6e68e072008-05-30 17:22:15 +00004267 /* Init regs that differ from the parent. */
4268 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004269 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004270 ts->bprm = parent_ts->bprm;
4271 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004272#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004273 nptl_flags = flags;
4274 flags &= ~CLONE_NPTL_FLAGS2;
4275
pbrookc2764712009-03-07 15:24:59 +00004276 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4277 ts->child_tidptr = child_tidptr;
4278 }
4279
pbrookd865bab2008-06-07 22:12:17 +00004280 if (nptl_flags & CLONE_SETTLS)
4281 cpu_set_tls (new_env, newtls);
4282
4283 /* Grab a mutex so that thread setup appears atomic. */
4284 pthread_mutex_lock(&clone_lock);
4285
4286 memset(&info, 0, sizeof(info));
4287 pthread_mutex_init(&info.mutex, NULL);
4288 pthread_mutex_lock(&info.mutex);
4289 pthread_cond_init(&info.cond, NULL);
4290 info.env = new_env;
4291 if (nptl_flags & CLONE_CHILD_SETTID)
4292 info.child_tidptr = child_tidptr;
4293 if (nptl_flags & CLONE_PARENT_SETTID)
4294 info.parent_tidptr = parent_tidptr;
4295
4296 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004297 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4298 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004299 /* It is not safe to deliver signals until the child has finished
4300 initializing, so temporarily block all signals. */
4301 sigfillset(&sigmask);
4302 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4303
4304 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004305 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004306
4307 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4308 pthread_attr_destroy(&attr);
4309 if (ret == 0) {
4310 /* Wait for the child to initialize. */
4311 pthread_cond_wait(&info.cond, &info.mutex);
4312 ret = info.tid;
4313 if (flags & CLONE_PARENT_SETTID)
4314 put_user_u32(ret, parent_tidptr);
4315 } else {
4316 ret = -1;
4317 }
4318 pthread_mutex_unlock(&info.mutex);
4319 pthread_cond_destroy(&info.cond);
4320 pthread_mutex_destroy(&info.mutex);
4321 pthread_mutex_unlock(&clone_lock);
4322#else
4323 if (flags & CLONE_NPTL_FLAGS2)
4324 return -EINVAL;
4325 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004326 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004327#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004328 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004329#else
4330 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4331#endif
pbrookd865bab2008-06-07 22:12:17 +00004332#endif
bellard1b6b0292003-03-22 17:31:38 +00004333 } else {
4334 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004335 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004336 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004337 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004338 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004339 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004340 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004341 cpu_clone_regs(env, newsp);
4342 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004343#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004344 /* There is a race condition here. The parent process could
4345 theoretically read the TID in the child process before the child
4346 tid is set. This would require using either ptrace
4347 (not implemented) or having *_tidptr to point at a shared memory
4348 mapping. We can't repeat the spinlock hack used above because
4349 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004350 if (flags & CLONE_CHILD_SETTID)
4351 put_user_u32(gettid(), child_tidptr);
4352 if (flags & CLONE_PARENT_SETTID)
4353 put_user_u32(gettid(), parent_tidptr);
4354 ts = (TaskState *)env->opaque;
4355 if (flags & CLONE_SETTLS)
4356 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004357 if (flags & CLONE_CHILD_CLEARTID)
4358 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004359#endif
pbrookd865bab2008-06-07 22:12:17 +00004360 } else {
4361 fork_end(0);
4362 }
bellard1b6b0292003-03-22 17:31:38 +00004363 }
4364 return ret;
4365}
4366
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004367/* warning : doesn't handle linux specific flags... */
4368static int target_to_host_fcntl_cmd(int cmd)
4369{
4370 switch(cmd) {
4371 case TARGET_F_DUPFD:
4372 case TARGET_F_GETFD:
4373 case TARGET_F_SETFD:
4374 case TARGET_F_GETFL:
4375 case TARGET_F_SETFL:
4376 return cmd;
4377 case TARGET_F_GETLK:
4378 return F_GETLK;
4379 case TARGET_F_SETLK:
4380 return F_SETLK;
4381 case TARGET_F_SETLKW:
4382 return F_SETLKW;
4383 case TARGET_F_GETOWN:
4384 return F_GETOWN;
4385 case TARGET_F_SETOWN:
4386 return F_SETOWN;
4387 case TARGET_F_GETSIG:
4388 return F_GETSIG;
4389 case TARGET_F_SETSIG:
4390 return F_SETSIG;
4391#if TARGET_ABI_BITS == 32
4392 case TARGET_F_GETLK64:
4393 return F_GETLK64;
4394 case TARGET_F_SETLK64:
4395 return F_SETLK64;
4396 case TARGET_F_SETLKW64:
4397 return F_SETLKW64;
4398#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004399 case TARGET_F_SETLEASE:
4400 return F_SETLEASE;
4401 case TARGET_F_GETLEASE:
4402 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004403#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004404 case TARGET_F_DUPFD_CLOEXEC:
4405 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004406#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004407 case TARGET_F_NOTIFY:
4408 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004409 default:
4410 return -TARGET_EINVAL;
4411 }
4412 return -TARGET_EINVAL;
4413}
4414
blueswir1992f48a2007-10-14 16:27:31 +00004415static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004416{
4417 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004418 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004419 struct flock64 fl64;
4420 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004421 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004422 int host_cmd = target_to_host_fcntl_cmd(cmd);
4423
4424 if (host_cmd == -TARGET_EINVAL)
4425 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004426
bellard7775e9e2003-05-14 22:46:48 +00004427 switch(cmd) {
4428 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004429 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4430 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004431 fl.l_type = tswap16(target_fl->l_type);
4432 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004433 fl.l_start = tswapal(target_fl->l_start);
4434 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004435 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004436 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004437 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004438 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004439 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4440 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004441 target_fl->l_type = tswap16(fl.l_type);
4442 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004443 target_fl->l_start = tswapal(fl.l_start);
4444 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004445 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004446 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004447 }
4448 break;
ths3b46e622007-09-17 08:09:54 +00004449
bellard7775e9e2003-05-14 22:46:48 +00004450 case TARGET_F_SETLK:
4451 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004452 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4453 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004454 fl.l_type = tswap16(target_fl->l_type);
4455 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004456 fl.l_start = tswapal(target_fl->l_start);
4457 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004458 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004459 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004460 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004461 break;
ths3b46e622007-09-17 08:09:54 +00004462
bellard7775e9e2003-05-14 22:46:48 +00004463 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004464 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4465 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004466 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4467 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004468 fl64.l_start = tswap64(target_fl64->l_start);
4469 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004470 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004471 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004472 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004473 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004474 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4475 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004476 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4477 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004478 target_fl64->l_start = tswap64(fl64.l_start);
4479 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004480 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004481 unlock_user_struct(target_fl64, arg, 1);
4482 }
bellard9ee1fa22007-11-11 15:11:19 +00004483 break;
bellard7775e9e2003-05-14 22:46:48 +00004484 case TARGET_F_SETLK64:
4485 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004486 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4487 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004488 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4489 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004490 fl64.l_start = tswap64(target_fl64->l_start);
4491 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004492 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004493 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004494 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004495 break;
4496
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004497 case TARGET_F_GETFL:
4498 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004499 if (ret >= 0) {
4500 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4501 }
bellardffa65c32004-01-04 23:57:22 +00004502 break;
4503
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004504 case TARGET_F_SETFL:
4505 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4506 break;
4507
4508 case TARGET_F_SETOWN:
4509 case TARGET_F_GETOWN:
4510 case TARGET_F_SETSIG:
4511 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004512 case TARGET_F_SETLEASE:
4513 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004514 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004515 break;
4516
bellard7775e9e2003-05-14 22:46:48 +00004517 default:
bellard9ee1fa22007-11-11 15:11:19 +00004518 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004519 break;
4520 }
4521 return ret;
4522}
4523
bellard67867302003-11-23 17:05:30 +00004524#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004525
bellard67867302003-11-23 17:05:30 +00004526static inline int high2lowuid(int uid)
4527{
4528 if (uid > 65535)
4529 return 65534;
4530 else
4531 return uid;
4532}
4533
4534static inline int high2lowgid(int gid)
4535{
4536 if (gid > 65535)
4537 return 65534;
4538 else
4539 return gid;
4540}
4541
4542static inline int low2highuid(int uid)
4543{
4544 if ((int16_t)uid == -1)
4545 return -1;
4546 else
4547 return uid;
4548}
4549
4550static inline int low2highgid(int gid)
4551{
4552 if ((int16_t)gid == -1)
4553 return -1;
4554 else
4555 return gid;
4556}
Riku Voipio0c866a72011-04-18 15:23:06 +03004557static inline int tswapid(int id)
4558{
4559 return tswap16(id);
4560}
4561#else /* !USE_UID16 */
4562static inline int high2lowuid(int uid)
4563{
4564 return uid;
4565}
4566static inline int high2lowgid(int gid)
4567{
4568 return gid;
4569}
4570static inline int low2highuid(int uid)
4571{
4572 return uid;
4573}
4574static inline int low2highgid(int gid)
4575{
4576 return gid;
4577}
4578static inline int tswapid(int id)
4579{
4580 return tswap32(id);
4581}
bellard67867302003-11-23 17:05:30 +00004582#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004583
bellard31e31b82003-02-18 22:55:36 +00004584void syscall_init(void)
4585{
bellard2ab83ea2003-06-15 19:56:46 +00004586 IOCTLEntry *ie;
4587 const argtype *arg_type;
4588 int size;
thsb92c47c2007-11-01 00:07:38 +00004589 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004590
Blue Swirl001faf32009-05-13 17:53:17 +00004591#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004592#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004593#include "syscall_types.h"
4594#undef STRUCT
4595#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004596
4597 /* we patch the ioctl size if necessary. We rely on the fact that
4598 no ioctl has all the bits at '1' in the size field */
4599 ie = ioctl_entries;
4600 while (ie->target_cmd != 0) {
4601 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4602 TARGET_IOC_SIZEMASK) {
4603 arg_type = ie->arg_type;
4604 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004605 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004606 ie->target_cmd);
4607 exit(1);
4608 }
4609 arg_type++;
4610 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004611 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004612 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4613 (size << TARGET_IOC_SIZESHIFT);
4614 }
thsb92c47c2007-11-01 00:07:38 +00004615
4616 /* Build target_to_host_errno_table[] table from
4617 * host_to_target_errno_table[]. */
4618 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4619 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4620
bellard2ab83ea2003-06-15 19:56:46 +00004621 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004622#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4623 (defined(__x86_64__) && defined(TARGET_X86_64))
4624 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4625 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4626 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004627 }
4628#endif
4629 ie++;
4630 }
bellard31e31b82003-02-18 22:55:36 +00004631}
bellardc573ff62004-01-04 15:51:36 +00004632
blueswir1992f48a2007-10-14 16:27:31 +00004633#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004634static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4635{
thsaf325d32008-06-10 15:29:15 +00004636#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004637 return ((uint64_t)word0 << 32) | word1;
4638#else
4639 return ((uint64_t)word1 << 32) | word0;
4640#endif
4641}
blueswir1992f48a2007-10-14 16:27:31 +00004642#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004643static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4644{
4645 return word0;
4646}
blueswir1992f48a2007-10-14 16:27:31 +00004647#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004648
4649#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004650static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4651 abi_long arg2,
4652 abi_long arg3,
4653 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004654{
Riku Voipio48e515d2011-07-12 15:40:51 +03004655 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004656 arg2 = arg3;
4657 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004658 }
pbrookce4defa2006-02-09 16:49:55 +00004659 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4660}
4661#endif
4662
4663#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004664static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4665 abi_long arg2,
4666 abi_long arg3,
4667 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004668{
Riku Voipio48e515d2011-07-12 15:40:51 +03004669 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004670 arg2 = arg3;
4671 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004672 }
pbrookce4defa2006-02-09 16:49:55 +00004673 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4674}
4675#endif
4676
bellard579a97f2007-11-11 14:26:47 +00004677static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4678 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004679{
4680 struct target_timespec *target_ts;
4681
bellard579a97f2007-11-11 14:26:47 +00004682 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4683 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004684 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4685 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004686 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004687 return 0;
pbrook53a59602006-03-25 19:31:22 +00004688}
4689
bellard579a97f2007-11-11 14:26:47 +00004690static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4691 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004692{
4693 struct target_timespec *target_ts;
4694
bellard579a97f2007-11-11 14:26:47 +00004695 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4696 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004697 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4698 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004699 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004700 return 0;
pbrook53a59602006-03-25 19:31:22 +00004701}
4702
aurel329d33b762009-04-08 23:07:05 +00004703#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004704static inline abi_long host_to_target_stat64(void *cpu_env,
4705 abi_ulong target_addr,
4706 struct stat *host_st)
4707{
4708#ifdef TARGET_ARM
4709 if (((CPUARMState *)cpu_env)->eabi) {
4710 struct target_eabi_stat64 *target_st;
4711
4712 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4713 return -TARGET_EFAULT;
4714 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4715 __put_user(host_st->st_dev, &target_st->st_dev);
4716 __put_user(host_st->st_ino, &target_st->st_ino);
4717#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4718 __put_user(host_st->st_ino, &target_st->__st_ino);
4719#endif
4720 __put_user(host_st->st_mode, &target_st->st_mode);
4721 __put_user(host_st->st_nlink, &target_st->st_nlink);
4722 __put_user(host_st->st_uid, &target_st->st_uid);
4723 __put_user(host_st->st_gid, &target_st->st_gid);
4724 __put_user(host_st->st_rdev, &target_st->st_rdev);
4725 __put_user(host_st->st_size, &target_st->st_size);
4726 __put_user(host_st->st_blksize, &target_st->st_blksize);
4727 __put_user(host_st->st_blocks, &target_st->st_blocks);
4728 __put_user(host_st->st_atime, &target_st->target_st_atime);
4729 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4730 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4731 unlock_user_struct(target_st, target_addr, 1);
4732 } else
4733#endif
4734 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004735#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004736 struct target_stat *target_st;
4737#else
balrog6a24a772008-09-20 02:23:36 +00004738 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004739#endif
balrog6a24a772008-09-20 02:23:36 +00004740
4741 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4742 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004743 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004744 __put_user(host_st->st_dev, &target_st->st_dev);
4745 __put_user(host_st->st_ino, &target_st->st_ino);
4746#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4747 __put_user(host_st->st_ino, &target_st->__st_ino);
4748#endif
4749 __put_user(host_st->st_mode, &target_st->st_mode);
4750 __put_user(host_st->st_nlink, &target_st->st_nlink);
4751 __put_user(host_st->st_uid, &target_st->st_uid);
4752 __put_user(host_st->st_gid, &target_st->st_gid);
4753 __put_user(host_st->st_rdev, &target_st->st_rdev);
4754 /* XXX: better use of kernel struct */
4755 __put_user(host_st->st_size, &target_st->st_size);
4756 __put_user(host_st->st_blksize, &target_st->st_blksize);
4757 __put_user(host_st->st_blocks, &target_st->st_blocks);
4758 __put_user(host_st->st_atime, &target_st->target_st_atime);
4759 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4760 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4761 unlock_user_struct(target_st, target_addr, 1);
4762 }
4763
4764 return 0;
4765}
4766#endif
4767
Juan Quintela2f7bb872009-07-27 16:13:24 +02004768#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004769/* ??? Using host futex calls even when target atomic operations
4770 are not really atomic probably breaks things. However implementing
4771 futexes locally would make futexes shared between multiple processes
4772 tricky. However they're probably useless because guest atomic
4773 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004774static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4775 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004776{
4777 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004778 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004779
4780 /* ??? We assume FUTEX_* constants are the same on both host
4781 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004782#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004783 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004784#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004785 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004786#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004787 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004788 case FUTEX_WAIT:
4789 if (timeout) {
4790 pts = &ts;
4791 target_to_host_timespec(pts, timeout);
4792 } else {
4793 pts = NULL;
4794 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004795 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004796 pts, NULL, 0));
4797 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004798 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004799 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004800 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004801 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004802 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004803 case FUTEX_WAKE_OP:
4804 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4805 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4806 But the prototype takes a `struct timespec *'; insert casts
4807 to satisfy the compiler. We do not need to tswap TIMEOUT
4808 since it's not compared to guest memory. */
4809 pts = (struct timespec *)(uintptr_t) timeout;
4810 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4811 g2h(uaddr2),
4812 (base_op == FUTEX_CMP_REQUEUE
4813 ? tswap32(val3)
4814 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004815 default:
4816 return -TARGET_ENOSYS;
4817 }
4818}
4819#endif
4820
pbrook1d9d8b52009-04-16 15:17:02 +00004821/* Map host to target signal numbers for the wait family of syscalls.
4822 Assume all other status bits are the same. */
4823static int host_to_target_waitstatus(int status)
4824{
4825 if (WIFSIGNALED(status)) {
4826 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4827 }
4828 if (WIFSTOPPED(status)) {
4829 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4830 | (status & 0xff);
4831 }
4832 return status;
4833}
4834
pbrooka745ec62008-05-06 15:36:17 +00004835int get_osversion(void)
4836{
4837 static int osversion;
4838 struct new_utsname buf;
4839 const char *s;
4840 int i, n, tmp;
4841 if (osversion)
4842 return osversion;
4843 if (qemu_uname_release && *qemu_uname_release) {
4844 s = qemu_uname_release;
4845 } else {
4846 if (sys_uname(&buf))
4847 return 0;
4848 s = buf.release;
4849 }
4850 tmp = 0;
4851 for (i = 0; i < 3; i++) {
4852 n = 0;
4853 while (*s >= '0' && *s <= '9') {
4854 n *= 10;
4855 n += *s - '0';
4856 s++;
4857 }
4858 tmp = (tmp << 8) + n;
4859 if (*s == '.')
4860 s++;
4861 }
4862 osversion = tmp;
4863 return osversion;
4864}
4865
Alexander Graf36c08d42011-11-02 20:23:24 +01004866
4867static int open_self_maps(void *cpu_env, int fd)
4868{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004869 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf36c08d42011-11-02 20:23:24 +01004870
4871 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4872 (unsigned long long)ts->info->stack_limit,
4873 (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
4874 & TARGET_PAGE_MASK,
4875 (unsigned long long)ts->stack_base);
4876
4877 return 0;
4878}
4879
Alexander Graf480b8e72011-11-02 20:23:25 +01004880static int open_self_stat(void *cpu_env, int fd)
4881{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004882 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01004883 abi_ulong start_stack = ts->info->start_stack;
4884 int i;
4885
4886 for (i = 0; i < 44; i++) {
4887 char buf[128];
4888 int len;
4889 uint64_t val = 0;
4890
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004891 if (i == 0) {
4892 /* pid */
4893 val = getpid();
4894 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4895 } else if (i == 1) {
4896 /* app name */
4897 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
4898 } else if (i == 27) {
4899 /* stack bottom */
4900 val = start_stack;
4901 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
4902 } else {
4903 /* for the rest, there is MasterCard */
4904 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01004905 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00004906
Alexander Graf480b8e72011-11-02 20:23:25 +01004907 len = strlen(buf);
4908 if (write(fd, buf, len) != len) {
4909 return -1;
4910 }
4911 }
4912
4913 return 0;
4914}
4915
Alexander Graf257450e2011-11-02 20:23:26 +01004916static int open_self_auxv(void *cpu_env, int fd)
4917{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004918 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01004919 abi_ulong auxv = ts->info->saved_auxv;
4920 abi_ulong len = ts->info->auxv_len;
4921 char *ptr;
4922
4923 /*
4924 * Auxiliary vector is stored in target process stack.
4925 * read in whole auxv vector and copy it to file
4926 */
4927 ptr = lock_user(VERIFY_READ, auxv, len, 0);
4928 if (ptr != NULL) {
4929 while (len > 0) {
4930 ssize_t r;
4931 r = write(fd, ptr, len);
4932 if (r <= 0) {
4933 break;
4934 }
4935 len -= r;
4936 ptr += r;
4937 }
4938 lseek(fd, 0, SEEK_SET);
4939 unlock_user(ptr, auxv, len);
4940 }
4941
4942 return 0;
4943}
4944
Alexander Graf3be14d02011-11-02 20:23:23 +01004945static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
4946{
4947 struct fake_open {
4948 const char *filename;
4949 int (*fill)(void *cpu_env, int fd);
4950 };
4951 const struct fake_open *fake_open;
4952 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01004953 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01004954 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01004955 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01004956 { NULL, NULL }
4957 };
4958
4959 for (fake_open = fakes; fake_open->filename; fake_open++) {
4960 if (!strncmp(pathname, fake_open->filename,
4961 strlen(fake_open->filename))) {
4962 break;
4963 }
4964 }
4965
4966 if (fake_open->filename) {
4967 const char *tmpdir;
4968 char filename[PATH_MAX];
4969 int fd, r;
4970
4971 /* create temporary file to map stat to */
4972 tmpdir = getenv("TMPDIR");
4973 if (!tmpdir)
4974 tmpdir = "/tmp";
4975 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
4976 fd = mkstemp(filename);
4977 if (fd < 0) {
4978 return fd;
4979 }
4980 unlink(filename);
4981
4982 if ((r = fake_open->fill(cpu_env, fd))) {
4983 close(fd);
4984 return r;
4985 }
4986 lseek(fd, 0, SEEK_SET);
4987
4988 return fd;
4989 }
4990
4991 return get_errno(open(path(pathname), flags, mode));
4992}
4993
ths0da46a62007-10-20 20:23:07 +00004994/* do_syscall() should always have a single exit point at the end so
4995 that actions, such as logging of syscall results, can be performed.
4996 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004997abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4998 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004999 abi_long arg5, abi_long arg6, abi_long arg7,
5000 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005001{
blueswir1992f48a2007-10-14 16:27:31 +00005002 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005003 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005004 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005005 void *p;
ths3b46e622007-09-17 08:09:54 +00005006
bellard72f03902003-02-18 23:33:18 +00005007#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005008 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005009#endif
thsb92c47c2007-11-01 00:07:38 +00005010 if(do_strace)
5011 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5012
bellard31e31b82003-02-18 22:55:36 +00005013 switch(num) {
5014 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02005015#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00005016 /* In old applications this may be used to implement _exit(2).
5017 However in threaded applictions it is used for thread termination,
5018 and _exit_group is used for application termination.
5019 Do thread termination if we have more then one thread. */
5020 /* FIXME: This probably breaks if a signal arrives. We should probably
5021 be disabling signals. */
5022 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07005023 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005024 CPUArchState **lastp;
5025 CPUArchState *p;
pbrookc2764712009-03-07 15:24:59 +00005026
5027 cpu_list_lock();
5028 lastp = &first_cpu;
5029 p = first_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005030 while (p && p != (CPUArchState *)cpu_env) {
pbrookc2764712009-03-07 15:24:59 +00005031 lastp = &p->next_cpu;
5032 p = p->next_cpu;
5033 }
5034 /* If we didn't find the CPU for this thread then something is
5035 horribly wrong. */
5036 if (!p)
5037 abort();
5038 /* Remove the CPU from the list. */
5039 *lastp = p->next_cpu;
5040 cpu_list_unlock();
Andreas Färber9349b4f2012-03-14 01:38:32 +01005041 ts = ((CPUArchState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00005042 if (ts->child_tidptr) {
5043 put_user_u32(0, ts->child_tidptr);
5044 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5045 NULL, NULL, 0);
5046 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005047 thread_env = NULL;
Andreas Färber11ea4092012-04-15 18:51:01 +02005048#ifdef ENV_GET_CPU
5049 object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
5050#else
Anthony Liguori7267c092011-08-20 22:09:37 -05005051 g_free(cpu_env);
Andreas Färber11ea4092012-04-15 18:51:01 +02005052#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05005053 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00005054 pthread_exit(NULL);
5055 }
5056#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02005057#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005058 _mcleanup();
5059#endif
bellarde9009672005-04-26 20:42:36 +00005060 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005061 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005062 ret = 0; /* avoid warning */
5063 break;
5064 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005065 if (arg3 == 0)
5066 ret = 0;
5067 else {
5068 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5069 goto efault;
5070 ret = get_errno(read(arg1, p, arg3));
5071 unlock_user(p, arg2, ret);
5072 }
bellard31e31b82003-02-18 22:55:36 +00005073 break;
5074 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005075 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5076 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005077 ret = get_errno(write(arg1, p, arg3));
5078 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005079 break;
5080 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005081 if (!(p = lock_user_string(arg1)))
5082 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005083 ret = get_errno(do_open(cpu_env, p,
5084 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5085 arg3));
pbrook53a59602006-03-25 19:31:22 +00005086 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005087 break;
ths82424832007-09-24 09:21:55 +00005088#if defined(TARGET_NR_openat) && defined(__NR_openat)
5089 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005090 if (!(p = lock_user_string(arg2)))
5091 goto efault;
5092 ret = get_errno(sys_openat(arg1,
5093 path(p),
5094 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5095 arg4));
5096 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005097 break;
5098#endif
bellard31e31b82003-02-18 22:55:36 +00005099 case TARGET_NR_close:
5100 ret = get_errno(close(arg1));
5101 break;
5102 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005103 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005104 break;
5105 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005106 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005107 break;
thse5febef2007-04-01 18:31:35 +00005108#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005109 case TARGET_NR_waitpid:
5110 {
pbrook53a59602006-03-25 19:31:22 +00005111 int status;
5112 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005113 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005114 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005115 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005116 }
5117 break;
thse5febef2007-04-01 18:31:35 +00005118#endif
pbrookf0cbb612008-05-30 18:20:05 +00005119#ifdef TARGET_NR_waitid
5120 case TARGET_NR_waitid:
5121 {
5122 siginfo_t info;
5123 info.si_pid = 0;
5124 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5125 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005126 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005127 goto efault;
5128 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005129 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005130 }
5131 }
5132 break;
5133#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005134#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005135 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005136 if (!(p = lock_user_string(arg1)))
5137 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005138 ret = get_errno(creat(p, arg2));
5139 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005140 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005141#endif
bellard31e31b82003-02-18 22:55:36 +00005142 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005143 {
5144 void * p2;
5145 p = lock_user_string(arg1);
5146 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005147 if (!p || !p2)
5148 ret = -TARGET_EFAULT;
5149 else
5150 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005151 unlock_user(p2, arg2, 0);
5152 unlock_user(p, arg1, 0);
5153 }
bellard31e31b82003-02-18 22:55:36 +00005154 break;
ths64f0ce42007-09-24 09:25:06 +00005155#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
5156 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005157 {
5158 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005159 if (!arg2 || !arg4)
5160 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005161 p = lock_user_string(arg2);
5162 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005163 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005164 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005165 else
5166 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005167 unlock_user(p, arg2, 0);
5168 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005169 }
5170 break;
5171#endif
bellard31e31b82003-02-18 22:55:36 +00005172 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005173 if (!(p = lock_user_string(arg1)))
5174 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005175 ret = get_errno(unlink(p));
5176 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005177 break;
ths8170f562007-09-24 09:24:11 +00005178#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
5179 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005180 if (!(p = lock_user_string(arg2)))
5181 goto efault;
5182 ret = get_errno(sys_unlinkat(arg1, p, arg3));
5183 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005184 break;
balrogb7d35e62007-12-12 00:40:24 +00005185#endif
bellard31e31b82003-02-18 22:55:36 +00005186 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005187 {
5188 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005189 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005190 abi_ulong gp;
5191 abi_ulong guest_argp;
5192 abi_ulong guest_envp;
5193 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005194 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005195 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005196
bellardf7341ff2003-03-30 21:00:25 +00005197 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005198 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005199 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005200 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005201 goto efault;
ths03aa1972007-12-02 06:28:08 +00005202 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005203 break;
bellard7854b052003-03-29 17:22:23 +00005204 argc++;
bellard2f619692007-11-16 10:46:05 +00005205 }
bellardf7341ff2003-03-30 21:00:25 +00005206 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005207 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005208 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005209 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005210 goto efault;
ths03aa1972007-12-02 06:28:08 +00005211 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005212 break;
bellard7854b052003-03-29 17:22:23 +00005213 envc++;
bellard2f619692007-11-16 10:46:05 +00005214 }
bellard7854b052003-03-29 17:22:23 +00005215
bellardf7341ff2003-03-30 21:00:25 +00005216 argp = alloca((argc + 1) * sizeof(void *));
5217 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005218
pbrookda94d262008-05-30 18:24:00 +00005219 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005220 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005221 if (get_user_ual(addr, gp))
5222 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005223 if (!addr)
5224 break;
bellard2f619692007-11-16 10:46:05 +00005225 if (!(*q = lock_user_string(addr)))
5226 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005227 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005228 }
bellardf7341ff2003-03-30 21:00:25 +00005229 *q = NULL;
5230
pbrookda94d262008-05-30 18:24:00 +00005231 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005232 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005233 if (get_user_ual(addr, gp))
5234 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005235 if (!addr)
5236 break;
bellard2f619692007-11-16 10:46:05 +00005237 if (!(*q = lock_user_string(addr)))
5238 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005239 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005240 }
bellardf7341ff2003-03-30 21:00:25 +00005241 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005242
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005243 /* This case will not be caught by the host's execve() if its
5244 page size is bigger than the target's. */
5245 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5246 ret = -TARGET_E2BIG;
5247 goto execve_end;
5248 }
bellard2f619692007-11-16 10:46:05 +00005249 if (!(p = lock_user_string(arg1)))
5250 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005251 ret = get_errno(execve(p, argp, envp));
5252 unlock_user(p, arg1, 0);
5253
bellard2f619692007-11-16 10:46:05 +00005254 goto execve_end;
5255
5256 execve_efault:
5257 ret = -TARGET_EFAULT;
5258
5259 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005260 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005261 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005262 if (get_user_ual(addr, gp)
5263 || !addr)
5264 break;
pbrook53a59602006-03-25 19:31:22 +00005265 unlock_user(*q, addr, 0);
5266 }
5267 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005268 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005269 if (get_user_ual(addr, gp)
5270 || !addr)
5271 break;
pbrook53a59602006-03-25 19:31:22 +00005272 unlock_user(*q, addr, 0);
5273 }
bellard7854b052003-03-29 17:22:23 +00005274 }
bellard31e31b82003-02-18 22:55:36 +00005275 break;
5276 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005277 if (!(p = lock_user_string(arg1)))
5278 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005279 ret = get_errno(chdir(p));
5280 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005281 break;
bellarda315a142005-01-30 22:59:18 +00005282#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005283 case TARGET_NR_time:
5284 {
pbrook53a59602006-03-25 19:31:22 +00005285 time_t host_time;
5286 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005287 if (!is_error(ret)
5288 && arg1
5289 && put_user_sal(host_time, arg1))
5290 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005291 }
5292 break;
bellarda315a142005-01-30 22:59:18 +00005293#endif
bellard31e31b82003-02-18 22:55:36 +00005294 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005295 if (!(p = lock_user_string(arg1)))
5296 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005297 ret = get_errno(mknod(p, arg2, arg3));
5298 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005299 break;
ths75ac37a2007-09-24 09:23:05 +00005300#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
5301 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005302 if (!(p = lock_user_string(arg2)))
5303 goto efault;
5304 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
5305 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005306 break;
5307#endif
bellard31e31b82003-02-18 22:55:36 +00005308 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005309 if (!(p = lock_user_string(arg1)))
5310 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005311 ret = get_errno(chmod(p, arg2));
5312 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005313 break;
bellardebc05482003-09-30 21:08:41 +00005314#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005315 case TARGET_NR_break:
5316 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005317#endif
5318#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005319 case TARGET_NR_oldstat:
5320 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005321#endif
bellard31e31b82003-02-18 22:55:36 +00005322 case TARGET_NR_lseek:
5323 ret = get_errno(lseek(arg1, arg2, arg3));
5324 break;
Richard Henderson92317332010-05-03 10:07:53 -07005325#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5326 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005327 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005328 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005329 ret = get_errno(getpid());
5330 break;
Richard Henderson92317332010-05-03 10:07:53 -07005331#endif
5332#ifdef TARGET_NR_getpid
5333 case TARGET_NR_getpid:
5334 ret = get_errno(getpid());
5335 break;
5336#endif
bellard31e31b82003-02-18 22:55:36 +00005337 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005338 {
5339 /* need to look at the data field */
5340 void *p2, *p3;
5341 p = lock_user_string(arg1);
5342 p2 = lock_user_string(arg2);
5343 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005344 if (!p || !p2 || !p3)
5345 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005346 else {
bellard579a97f2007-11-11 14:26:47 +00005347 /* FIXME - arg5 should be locked, but it isn't clear how to
5348 * do that since it's not guaranteed to be a NULL-terminated
5349 * string.
5350 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005351 if ( ! arg5 )
5352 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5353 else
5354 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5355 }
bellard579a97f2007-11-11 14:26:47 +00005356 unlock_user(p, arg1, 0);
5357 unlock_user(p2, arg2, 0);
5358 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005359 break;
5360 }
thse5febef2007-04-01 18:31:35 +00005361#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005362 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005363 if (!(p = lock_user_string(arg1)))
5364 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005365 ret = get_errno(umount(p));
5366 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005367 break;
thse5febef2007-04-01 18:31:35 +00005368#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005369#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005370 case TARGET_NR_stime:
5371 {
pbrook53a59602006-03-25 19:31:22 +00005372 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005373 if (get_user_sal(host_time, arg1))
5374 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005375 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005376 }
5377 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005378#endif
bellard31e31b82003-02-18 22:55:36 +00005379 case TARGET_NR_ptrace:
5380 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005381#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005382 case TARGET_NR_alarm:
5383 ret = alarm(arg1);
5384 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005385#endif
bellardebc05482003-09-30 21:08:41 +00005386#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005387 case TARGET_NR_oldfstat:
5388 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005389#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005390#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005391 case TARGET_NR_pause:
5392 ret = get_errno(pause());
5393 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005394#endif
thse5febef2007-04-01 18:31:35 +00005395#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005396 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005397 {
pbrook53a59602006-03-25 19:31:22 +00005398 struct utimbuf tbuf, *host_tbuf;
5399 struct target_utimbuf *target_tbuf;
5400 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005401 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5402 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005403 tbuf.actime = tswapal(target_tbuf->actime);
5404 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005405 unlock_user_struct(target_tbuf, arg2, 0);
5406 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005407 } else {
pbrook53a59602006-03-25 19:31:22 +00005408 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005409 }
bellard579a97f2007-11-11 14:26:47 +00005410 if (!(p = lock_user_string(arg1)))
5411 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005412 ret = get_errno(utime(p, host_tbuf));
5413 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005414 }
5415 break;
thse5febef2007-04-01 18:31:35 +00005416#endif
bellard978a66f2004-12-06 22:58:05 +00005417 case TARGET_NR_utimes:
5418 {
bellard978a66f2004-12-06 22:58:05 +00005419 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005420 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005421 if (copy_from_user_timeval(&tv[0], arg2)
5422 || copy_from_user_timeval(&tv[1],
5423 arg2 + sizeof(struct target_timeval)))
5424 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005425 tvp = tv;
5426 } else {
5427 tvp = NULL;
5428 }
bellard579a97f2007-11-11 14:26:47 +00005429 if (!(p = lock_user_string(arg1)))
5430 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005431 ret = get_errno(utimes(p, tvp));
5432 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005433 }
5434 break;
balrogac8a6552008-09-20 02:25:39 +00005435#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5436 case TARGET_NR_futimesat:
5437 {
5438 struct timeval *tvp, tv[2];
5439 if (arg3) {
5440 if (copy_from_user_timeval(&tv[0], arg3)
5441 || copy_from_user_timeval(&tv[1],
5442 arg3 + sizeof(struct target_timeval)))
5443 goto efault;
5444 tvp = tv;
5445 } else {
5446 tvp = NULL;
5447 }
5448 if (!(p = lock_user_string(arg2)))
5449 goto efault;
5450 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5451 unlock_user(p, arg2, 0);
5452 }
5453 break;
5454#endif
bellardebc05482003-09-30 21:08:41 +00005455#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005456 case TARGET_NR_stty:
5457 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005458#endif
5459#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005460 case TARGET_NR_gtty:
5461 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005462#endif
bellard31e31b82003-02-18 22:55:36 +00005463 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005464 if (!(p = lock_user_string(arg1)))
5465 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005466 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005467 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005468 break;
ths92a34c12007-09-24 09:27:49 +00005469#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5470 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005471 if (!(p = lock_user_string(arg2)))
5472 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005473 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005474 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005475 break;
5476#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005477#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005478 case TARGET_NR_nice:
5479 ret = get_errno(nice(arg1));
5480 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005481#endif
bellardebc05482003-09-30 21:08:41 +00005482#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005483 case TARGET_NR_ftime:
5484 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005485#endif
bellard31e31b82003-02-18 22:55:36 +00005486 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005487 sync();
5488 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005489 break;
5490 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005491 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005492 break;
5493 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005494 {
5495 void *p2;
5496 p = lock_user_string(arg1);
5497 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005498 if (!p || !p2)
5499 ret = -TARGET_EFAULT;
5500 else
5501 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005502 unlock_user(p2, arg2, 0);
5503 unlock_user(p, arg1, 0);
5504 }
bellard31e31b82003-02-18 22:55:36 +00005505 break;
ths722183f2007-09-24 09:24:37 +00005506#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5507 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005508 {
bellard579a97f2007-11-11 14:26:47 +00005509 void *p2;
ths722183f2007-09-24 09:24:37 +00005510 p = lock_user_string(arg2);
5511 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005512 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005513 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005514 else
5515 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005516 unlock_user(p2, arg4, 0);
5517 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005518 }
5519 break;
5520#endif
bellard31e31b82003-02-18 22:55:36 +00005521 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005522 if (!(p = lock_user_string(arg1)))
5523 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005524 ret = get_errno(mkdir(p, arg2));
5525 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005526 break;
ths4472ad02007-09-24 09:22:32 +00005527#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5528 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005529 if (!(p = lock_user_string(arg2)))
5530 goto efault;
5531 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5532 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005533 break;
5534#endif
bellard31e31b82003-02-18 22:55:36 +00005535 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005536 if (!(p = lock_user_string(arg1)))
5537 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005538 ret = get_errno(rmdir(p));
5539 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005540 break;
5541 case TARGET_NR_dup:
5542 ret = get_errno(dup(arg1));
5543 break;
5544 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005545 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005546 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005547#ifdef TARGET_NR_pipe2
5548 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005549 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005550 break;
5551#endif
bellard31e31b82003-02-18 22:55:36 +00005552 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005553 {
pbrook53a59602006-03-25 19:31:22 +00005554 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005555 struct tms tms;
5556 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005557 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005558 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5559 if (!tmsp)
5560 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005561 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5562 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5563 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5564 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005565 }
bellardc596ed12003-07-13 17:32:31 +00005566 if (!is_error(ret))
5567 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005568 }
5569 break;
bellardebc05482003-09-30 21:08:41 +00005570#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005571 case TARGET_NR_prof:
5572 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005573#endif
thse5febef2007-04-01 18:31:35 +00005574#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005575 case TARGET_NR_signal:
5576 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005577#endif
bellard31e31b82003-02-18 22:55:36 +00005578 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005579 if (arg1 == 0) {
5580 ret = get_errno(acct(NULL));
5581 } else {
5582 if (!(p = lock_user_string(arg1)))
5583 goto efault;
5584 ret = get_errno(acct(path(p)));
5585 unlock_user(p, arg1, 0);
5586 }
pbrook24836682006-04-16 14:14:53 +00005587 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005588#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005589 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005590 if (!(p = lock_user_string(arg1)))
5591 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005592 ret = get_errno(umount2(p, arg2));
5593 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005594 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005595#endif
bellardebc05482003-09-30 21:08:41 +00005596#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005597 case TARGET_NR_lock:
5598 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005599#endif
bellard31e31b82003-02-18 22:55:36 +00005600 case TARGET_NR_ioctl:
5601 ret = do_ioctl(arg1, arg2, arg3);
5602 break;
5603 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005604 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005605 break;
bellardebc05482003-09-30 21:08:41 +00005606#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005607 case TARGET_NR_mpx:
5608 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005609#endif
bellard31e31b82003-02-18 22:55:36 +00005610 case TARGET_NR_setpgid:
5611 ret = get_errno(setpgid(arg1, arg2));
5612 break;
bellardebc05482003-09-30 21:08:41 +00005613#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005614 case TARGET_NR_ulimit:
5615 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005616#endif
5617#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005618 case TARGET_NR_oldolduname:
5619 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005620#endif
bellard31e31b82003-02-18 22:55:36 +00005621 case TARGET_NR_umask:
5622 ret = get_errno(umask(arg1));
5623 break;
5624 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005625 if (!(p = lock_user_string(arg1)))
5626 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005627 ret = get_errno(chroot(p));
5628 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005629 break;
5630 case TARGET_NR_ustat:
5631 goto unimplemented;
5632 case TARGET_NR_dup2:
5633 ret = get_errno(dup2(arg1, arg2));
5634 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005635#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5636 case TARGET_NR_dup3:
5637 ret = get_errno(dup3(arg1, arg2, arg3));
5638 break;
5639#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005640#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005641 case TARGET_NR_getppid:
5642 ret = get_errno(getppid());
5643 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005644#endif
bellard31e31b82003-02-18 22:55:36 +00005645 case TARGET_NR_getpgrp:
5646 ret = get_errno(getpgrp());
5647 break;
5648 case TARGET_NR_setsid:
5649 ret = get_errno(setsid());
5650 break;
thse5febef2007-04-01 18:31:35 +00005651#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005652 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005653 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005654#if defined(TARGET_ALPHA)
5655 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005656 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005657 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005658 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5659 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005660 act._sa_handler = old_act->_sa_handler;
5661 target_siginitset(&act.sa_mask, old_act->sa_mask);
5662 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005663 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005664 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005665 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005666 }
5667 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005668 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005669 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5670 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005671 old_act->_sa_handler = oact._sa_handler;
5672 old_act->sa_mask = oact.sa_mask.sig[0];
5673 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005674 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005675 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005676#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005677 struct target_sigaction act, oact, *pact, *old_act;
5678
5679 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005680 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5681 goto efault;
bellard106ec872006-06-27 21:08:10 +00005682 act._sa_handler = old_act->_sa_handler;
5683 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5684 act.sa_flags = old_act->sa_flags;
5685 unlock_user_struct(old_act, arg2, 0);
5686 pact = &act;
5687 } else {
5688 pact = NULL;
5689 }
5690
5691 ret = get_errno(do_sigaction(arg1, pact, &oact));
5692
5693 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005694 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5695 goto efault;
bellard106ec872006-06-27 21:08:10 +00005696 old_act->_sa_handler = oact._sa_handler;
5697 old_act->sa_flags = oact.sa_flags;
5698 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5699 old_act->sa_mask.sig[1] = 0;
5700 old_act->sa_mask.sig[2] = 0;
5701 old_act->sa_mask.sig[3] = 0;
5702 unlock_user_struct(old_act, arg3, 1);
5703 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005704#else
5705 struct target_old_sigaction *old_act;
5706 struct target_sigaction act, oact, *pact;
5707 if (arg2) {
5708 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5709 goto efault;
5710 act._sa_handler = old_act->_sa_handler;
5711 target_siginitset(&act.sa_mask, old_act->sa_mask);
5712 act.sa_flags = old_act->sa_flags;
5713 act.sa_restorer = old_act->sa_restorer;
5714 unlock_user_struct(old_act, arg2, 0);
5715 pact = &act;
5716 } else {
5717 pact = NULL;
5718 }
5719 ret = get_errno(do_sigaction(arg1, pact, &oact));
5720 if (!is_error(ret) && arg3) {
5721 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5722 goto efault;
5723 old_act->_sa_handler = oact._sa_handler;
5724 old_act->sa_mask = oact.sa_mask.sig[0];
5725 old_act->sa_flags = oact.sa_flags;
5726 old_act->sa_restorer = oact.sa_restorer;
5727 unlock_user_struct(old_act, arg3, 1);
5728 }
ths388bb212007-05-13 13:58:00 +00005729#endif
bellard31e31b82003-02-18 22:55:36 +00005730 }
5731 break;
thse5febef2007-04-01 18:31:35 +00005732#endif
bellard66fb9762003-03-23 01:06:05 +00005733 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005734 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005735#if defined(TARGET_ALPHA)
5736 struct target_sigaction act, oact, *pact = 0;
5737 struct target_rt_sigaction *rt_act;
5738 /* ??? arg4 == sizeof(sigset_t). */
5739 if (arg2) {
5740 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5741 goto efault;
5742 act._sa_handler = rt_act->_sa_handler;
5743 act.sa_mask = rt_act->sa_mask;
5744 act.sa_flags = rt_act->sa_flags;
5745 act.sa_restorer = arg5;
5746 unlock_user_struct(rt_act, arg2, 0);
5747 pact = &act;
5748 }
5749 ret = get_errno(do_sigaction(arg1, pact, &oact));
5750 if (!is_error(ret) && arg3) {
5751 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5752 goto efault;
5753 rt_act->_sa_handler = oact._sa_handler;
5754 rt_act->sa_mask = oact.sa_mask;
5755 rt_act->sa_flags = oact.sa_flags;
5756 unlock_user_struct(rt_act, arg3, 1);
5757 }
5758#else
pbrook53a59602006-03-25 19:31:22 +00005759 struct target_sigaction *act;
5760 struct target_sigaction *oact;
5761
bellard579a97f2007-11-11 14:26:47 +00005762 if (arg2) {
5763 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5764 goto efault;
5765 } else
pbrook53a59602006-03-25 19:31:22 +00005766 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005767 if (arg3) {
5768 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5769 ret = -TARGET_EFAULT;
5770 goto rt_sigaction_fail;
5771 }
5772 } else
pbrook53a59602006-03-25 19:31:22 +00005773 oact = NULL;
5774 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005775 rt_sigaction_fail:
5776 if (act)
pbrook53a59602006-03-25 19:31:22 +00005777 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005778 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005779 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005780#endif
pbrook53a59602006-03-25 19:31:22 +00005781 }
bellard66fb9762003-03-23 01:06:05 +00005782 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005783#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005784 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005785 {
5786 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005787 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005788 sigprocmask(0, NULL, &cur_set);
5789 host_to_target_old_sigset(&target_set, &cur_set);
5790 ret = target_set;
5791 }
5792 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005793#endif
5794#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005795 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005796 {
5797 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005798 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005799 sigprocmask(0, NULL, &cur_set);
5800 target_to_host_old_sigset(&set, &target_set);
5801 sigorset(&set, &set, &cur_set);
5802 sigprocmask(SIG_SETMASK, &set, &oset);
5803 host_to_target_old_sigset(&target_set, &oset);
5804 ret = target_set;
5805 }
5806 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005807#endif
thse5febef2007-04-01 18:31:35 +00005808#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005809 case TARGET_NR_sigprocmask:
5810 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005811#if defined(TARGET_ALPHA)
5812 sigset_t set, oldset;
5813 abi_ulong mask;
5814 int how;
5815
5816 switch (arg1) {
5817 case TARGET_SIG_BLOCK:
5818 how = SIG_BLOCK;
5819 break;
5820 case TARGET_SIG_UNBLOCK:
5821 how = SIG_UNBLOCK;
5822 break;
5823 case TARGET_SIG_SETMASK:
5824 how = SIG_SETMASK;
5825 break;
5826 default:
5827 ret = -TARGET_EINVAL;
5828 goto fail;
5829 }
5830 mask = arg2;
5831 target_to_host_old_sigset(&set, &mask);
5832
5833 ret = get_errno(sigprocmask(how, &set, &oldset));
5834
5835 if (!is_error(ret)) {
5836 host_to_target_old_sigset(&mask, &oldset);
5837 ret = mask;
5838 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5839 }
5840#else
bellard66fb9762003-03-23 01:06:05 +00005841 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005842 int how;
ths3b46e622007-09-17 08:09:54 +00005843
pbrook53a59602006-03-25 19:31:22 +00005844 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005845 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005846 case TARGET_SIG_BLOCK:
5847 how = SIG_BLOCK;
5848 break;
5849 case TARGET_SIG_UNBLOCK:
5850 how = SIG_UNBLOCK;
5851 break;
5852 case TARGET_SIG_SETMASK:
5853 how = SIG_SETMASK;
5854 break;
5855 default:
ths0da46a62007-10-20 20:23:07 +00005856 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005857 goto fail;
5858 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005859 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005860 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005861 target_to_host_old_sigset(&set, p);
5862 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005863 set_ptr = &set;
5864 } else {
5865 how = 0;
5866 set_ptr = NULL;
5867 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005868 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005869 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005870 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005871 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005872 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005873 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005874 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005875#endif
bellard66fb9762003-03-23 01:06:05 +00005876 }
5877 break;
thse5febef2007-04-01 18:31:35 +00005878#endif
bellard66fb9762003-03-23 01:06:05 +00005879 case TARGET_NR_rt_sigprocmask:
5880 {
5881 int how = arg1;
5882 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005883
pbrook53a59602006-03-25 19:31:22 +00005884 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005885 switch(how) {
5886 case TARGET_SIG_BLOCK:
5887 how = SIG_BLOCK;
5888 break;
5889 case TARGET_SIG_UNBLOCK:
5890 how = SIG_UNBLOCK;
5891 break;
5892 case TARGET_SIG_SETMASK:
5893 how = SIG_SETMASK;
5894 break;
5895 default:
ths0da46a62007-10-20 20:23:07 +00005896 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005897 goto fail;
5898 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005899 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005900 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005901 target_to_host_sigset(&set, p);
5902 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005903 set_ptr = &set;
5904 } else {
5905 how = 0;
5906 set_ptr = NULL;
5907 }
5908 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005909 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005910 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005911 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005912 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005913 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005914 }
5915 }
5916 break;
thse5febef2007-04-01 18:31:35 +00005917#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005918 case TARGET_NR_sigpending:
5919 {
5920 sigset_t set;
5921 ret = get_errno(sigpending(&set));
5922 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005923 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005924 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005925 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005926 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005927 }
5928 }
5929 break;
thse5febef2007-04-01 18:31:35 +00005930#endif
bellard66fb9762003-03-23 01:06:05 +00005931 case TARGET_NR_rt_sigpending:
5932 {
5933 sigset_t set;
5934 ret = get_errno(sigpending(&set));
5935 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005936 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005937 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005938 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005939 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005940 }
5941 }
5942 break;
thse5febef2007-04-01 18:31:35 +00005943#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005944 case TARGET_NR_sigsuspend:
5945 {
5946 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005947#if defined(TARGET_ALPHA)
5948 abi_ulong mask = arg1;
5949 target_to_host_old_sigset(&set, &mask);
5950#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005951 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005952 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005953 target_to_host_old_sigset(&set, p);
5954 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005955#endif
bellard66fb9762003-03-23 01:06:05 +00005956 ret = get_errno(sigsuspend(&set));
5957 }
5958 break;
thse5febef2007-04-01 18:31:35 +00005959#endif
bellard66fb9762003-03-23 01:06:05 +00005960 case TARGET_NR_rt_sigsuspend:
5961 {
5962 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005963 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005964 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005965 target_to_host_sigset(&set, p);
5966 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005967 ret = get_errno(sigsuspend(&set));
5968 }
5969 break;
5970 case TARGET_NR_rt_sigtimedwait:
5971 {
bellard66fb9762003-03-23 01:06:05 +00005972 sigset_t set;
5973 struct timespec uts, *puts;
5974 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005975
Anthony Liguoric227f092009-10-01 16:12:16 -05005976 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005977 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005978 target_to_host_sigset(&set, p);
5979 unlock_user(p, arg1, 0);
5980 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005981 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005982 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005983 } else {
5984 puts = NULL;
5985 }
5986 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005987 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005988 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005989 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005990 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005991 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005992 }
5993 }
5994 break;
5995 case TARGET_NR_rt_sigqueueinfo:
5996 {
5997 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005998 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005999 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006000 target_to_host_siginfo(&uinfo, p);
6001 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006002 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6003 }
6004 break;
thse5febef2007-04-01 18:31:35 +00006005#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006006 case TARGET_NR_sigreturn:
6007 /* NOTE: ret is eax, so not transcoding must be done */
6008 ret = do_sigreturn(cpu_env);
6009 break;
thse5febef2007-04-01 18:31:35 +00006010#endif
bellard66fb9762003-03-23 01:06:05 +00006011 case TARGET_NR_rt_sigreturn:
6012 /* NOTE: ret is eax, so not transcoding must be done */
6013 ret = do_rt_sigreturn(cpu_env);
6014 break;
bellard31e31b82003-02-18 22:55:36 +00006015 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006016 if (!(p = lock_user_string(arg1)))
6017 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006018 ret = get_errno(sethostname(p, arg2));
6019 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006020 break;
6021 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006022 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006023 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006024 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006025 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006026 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6027 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006028 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6029 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006030 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006031 ret = get_errno(setrlimit(resource, &rlim));
6032 }
6033 break;
bellard31e31b82003-02-18 22:55:36 +00006034 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006035 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006036 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006037 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006038 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006039
bellard9de5e442003-03-23 16:49:39 +00006040 ret = get_errno(getrlimit(resource, &rlim));
6041 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006042 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6043 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006044 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6045 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006046 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006047 }
6048 }
6049 break;
bellard31e31b82003-02-18 22:55:36 +00006050 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006051 {
6052 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006053 ret = get_errno(getrusage(arg1, &rusage));
6054 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006055 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006056 }
6057 }
6058 break;
bellard31e31b82003-02-18 22:55:36 +00006059 case TARGET_NR_gettimeofday:
6060 {
bellard31e31b82003-02-18 22:55:36 +00006061 struct timeval tv;
6062 ret = get_errno(gettimeofday(&tv, NULL));
6063 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006064 if (copy_to_user_timeval(arg1, &tv))
6065 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006066 }
6067 }
6068 break;
6069 case TARGET_NR_settimeofday:
6070 {
bellard31e31b82003-02-18 22:55:36 +00006071 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006072 if (copy_from_user_timeval(&tv, arg1))
6073 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006074 ret = get_errno(settimeofday(&tv, NULL));
6075 }
6076 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006077#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00006078 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00006079 {
pbrook53a59602006-03-25 19:31:22 +00006080 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006081 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006082 long nsel;
6083
bellard579a97f2007-11-11 14:26:47 +00006084 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6085 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006086 nsel = tswapal(sel->n);
6087 inp = tswapal(sel->inp);
6088 outp = tswapal(sel->outp);
6089 exp = tswapal(sel->exp);
6090 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006091 unlock_user_struct(sel, arg1, 0);
6092 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006093 }
6094 break;
bellard048f6b42005-11-26 18:47:20 +00006095#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006096#ifdef TARGET_NR_pselect6
6097 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006098 {
6099 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6100 fd_set rfds, wfds, efds;
6101 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6102 struct timespec ts, *ts_ptr;
6103
6104 /*
6105 * The 6th arg is actually two args smashed together,
6106 * so we cannot use the C library.
6107 */
6108 sigset_t set;
6109 struct {
6110 sigset_t *set;
6111 size_t size;
6112 } sig, *sig_ptr;
6113
6114 abi_ulong arg_sigset, arg_sigsize, *arg7;
6115 target_sigset_t *target_sigset;
6116
6117 n = arg1;
6118 rfd_addr = arg2;
6119 wfd_addr = arg3;
6120 efd_addr = arg4;
6121 ts_addr = arg5;
6122
6123 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6124 if (ret) {
6125 goto fail;
6126 }
6127 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6128 if (ret) {
6129 goto fail;
6130 }
6131 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6132 if (ret) {
6133 goto fail;
6134 }
6135
6136 /*
6137 * This takes a timespec, and not a timeval, so we cannot
6138 * use the do_select() helper ...
6139 */
6140 if (ts_addr) {
6141 if (target_to_host_timespec(&ts, ts_addr)) {
6142 goto efault;
6143 }
6144 ts_ptr = &ts;
6145 } else {
6146 ts_ptr = NULL;
6147 }
6148
6149 /* Extract the two packed args for the sigset */
6150 if (arg6) {
6151 sig_ptr = &sig;
6152 sig.size = _NSIG / 8;
6153
6154 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6155 if (!arg7) {
6156 goto efault;
6157 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006158 arg_sigset = tswapal(arg7[0]);
6159 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006160 unlock_user(arg7, arg6, 0);
6161
6162 if (arg_sigset) {
6163 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006164 if (arg_sigsize != sizeof(*target_sigset)) {
6165 /* Like the kernel, we enforce correct size sigsets */
6166 ret = -TARGET_EINVAL;
6167 goto fail;
6168 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006169 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6170 sizeof(*target_sigset), 1);
6171 if (!target_sigset) {
6172 goto efault;
6173 }
6174 target_to_host_sigset(&set, target_sigset);
6175 unlock_user(target_sigset, arg_sigset, 0);
6176 } else {
6177 sig.set = NULL;
6178 }
6179 } else {
6180 sig_ptr = NULL;
6181 }
6182
6183 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6184 ts_ptr, sig_ptr));
6185
6186 if (!is_error(ret)) {
6187 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6188 goto efault;
6189 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6190 goto efault;
6191 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6192 goto efault;
6193
6194 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6195 goto efault;
6196 }
6197 }
6198 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006199#endif
bellard31e31b82003-02-18 22:55:36 +00006200 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006201 {
6202 void *p2;
6203 p = lock_user_string(arg1);
6204 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006205 if (!p || !p2)
6206 ret = -TARGET_EFAULT;
6207 else
6208 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006209 unlock_user(p2, arg2, 0);
6210 unlock_user(p, arg1, 0);
6211 }
bellard31e31b82003-02-18 22:55:36 +00006212 break;
thsf0b62432007-09-24 09:25:40 +00006213#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
6214 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006215 {
bellard579a97f2007-11-11 14:26:47 +00006216 void *p2;
thsf0b62432007-09-24 09:25:40 +00006217 p = lock_user_string(arg1);
6218 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006219 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006220 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006221 else
6222 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006223 unlock_user(p2, arg3, 0);
6224 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006225 }
6226 break;
6227#endif
bellardebc05482003-09-30 21:08:41 +00006228#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006229 case TARGET_NR_oldlstat:
6230 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006231#endif
bellard31e31b82003-02-18 22:55:36 +00006232 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006233 {
aurel32d088d662009-01-30 20:09:01 +00006234 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006235 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006236 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6237 if (!p || !p2)
6238 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006239 else {
6240 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6241 char real[PATH_MAX];
6242 temp = realpath(exec_path,real);
6243 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6244 snprintf((char *)p2, arg3, "%s", real);
6245 }
6246 else
6247 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006248 }
pbrook53a59602006-03-25 19:31:22 +00006249 unlock_user(p2, arg2, ret);
6250 unlock_user(p, arg1, 0);
6251 }
bellard31e31b82003-02-18 22:55:36 +00006252 break;
ths5e0ccb12007-09-24 09:26:10 +00006253#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
6254 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006255 {
bellard579a97f2007-11-11 14:26:47 +00006256 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006257 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006258 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6259 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006260 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006261 else
6262 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006263 unlock_user(p2, arg3, ret);
6264 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006265 }
6266 break;
6267#endif
thse5febef2007-04-01 18:31:35 +00006268#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006269 case TARGET_NR_uselib:
6270 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006271#endif
6272#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006273 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006274 if (!(p = lock_user_string(arg1)))
6275 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006276 ret = get_errno(swapon(p, arg2));
6277 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006278 break;
thse5febef2007-04-01 18:31:35 +00006279#endif
bellard31e31b82003-02-18 22:55:36 +00006280 case TARGET_NR_reboot:
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006281 if (!(p = lock_user_string(arg4)))
6282 goto efault;
6283 ret = reboot(arg1, arg2, arg3, p);
6284 unlock_user(p, arg4, 0);
6285 break;
thse5febef2007-04-01 18:31:35 +00006286#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006287 case TARGET_NR_readdir:
6288 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006289#endif
6290#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006291 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006292#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6293 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6294 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006295 {
blueswir1992f48a2007-10-14 16:27:31 +00006296 abi_ulong *v;
6297 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006298 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6299 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006300 v1 = tswapal(v[0]);
6301 v2 = tswapal(v[1]);
6302 v3 = tswapal(v[2]);
6303 v4 = tswapal(v[3]);
6304 v5 = tswapal(v[4]);
6305 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006306 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006307 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006308 target_to_host_bitmask(v4, mmap_flags_tbl),
6309 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006310 }
bellard31e31b82003-02-18 22:55:36 +00006311#else
ths5fafdf22007-09-16 21:08:06 +00006312 ret = get_errno(target_mmap(arg1, arg2, arg3,
6313 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006314 arg5,
6315 arg6));
bellard31e31b82003-02-18 22:55:36 +00006316#endif
bellard6fb883e2003-07-09 17:12:39 +00006317 break;
thse5febef2007-04-01 18:31:35 +00006318#endif
bellarda315a142005-01-30 22:59:18 +00006319#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006320 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006321#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006322#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006323#endif
ths5fafdf22007-09-16 21:08:06 +00006324 ret = get_errno(target_mmap(arg1, arg2, arg3,
6325 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006326 arg5,
bellardc573ff62004-01-04 15:51:36 +00006327 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006328 break;
bellarda315a142005-01-30 22:59:18 +00006329#endif
bellard31e31b82003-02-18 22:55:36 +00006330 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006331 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006332 break;
bellard9de5e442003-03-23 16:49:39 +00006333 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006334 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006335 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006336 /* Special hack to detect libc making the stack executable. */
6337 if ((arg3 & PROT_GROWSDOWN)
6338 && arg1 >= ts->info->stack_limit
6339 && arg1 <= ts->info->start_stack) {
6340 arg3 &= ~PROT_GROWSDOWN;
6341 arg2 = arg2 + arg1 - ts->info->stack_limit;
6342 arg1 = ts->info->stack_limit;
6343 }
6344 }
bellard54936002003-05-13 00:25:15 +00006345 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006346 break;
thse5febef2007-04-01 18:31:35 +00006347#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006348 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006349 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006350 break;
thse5febef2007-04-01 18:31:35 +00006351#endif
pbrook53a59602006-03-25 19:31:22 +00006352 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006353#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006354 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006355 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006356 break;
thse5febef2007-04-01 18:31:35 +00006357#endif
6358#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006359 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006360 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006361 break;
thse5febef2007-04-01 18:31:35 +00006362#endif
6363#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006364 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006365 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006366 break;
thse5febef2007-04-01 18:31:35 +00006367#endif
6368#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006369 case TARGET_NR_mlockall:
6370 ret = get_errno(mlockall(arg1));
6371 break;
thse5febef2007-04-01 18:31:35 +00006372#endif
6373#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006374 case TARGET_NR_munlockall:
6375 ret = get_errno(munlockall());
6376 break;
thse5febef2007-04-01 18:31:35 +00006377#endif
bellard31e31b82003-02-18 22:55:36 +00006378 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006379 if (!(p = lock_user_string(arg1)))
6380 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006381 ret = get_errno(truncate(p, arg2));
6382 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006383 break;
6384 case TARGET_NR_ftruncate:
6385 ret = get_errno(ftruncate(arg1, arg2));
6386 break;
6387 case TARGET_NR_fchmod:
6388 ret = get_errno(fchmod(arg1, arg2));
6389 break;
ths814d7972007-09-24 09:26:51 +00006390#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
6391 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006392 if (!(p = lock_user_string(arg2)))
6393 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00006394 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006395 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006396 break;
6397#endif
bellard31e31b82003-02-18 22:55:36 +00006398 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00006399 /* libc does special remapping of the return value of
6400 * sys_getpriority() so it's just easiest to call
6401 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03006402 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006403 break;
6404 case TARGET_NR_setpriority:
6405 ret = get_errno(setpriority(arg1, arg2, arg3));
6406 break;
bellardebc05482003-09-30 21:08:41 +00006407#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006408 case TARGET_NR_profil:
6409 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006410#endif
bellard31e31b82003-02-18 22:55:36 +00006411 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006412 if (!(p = lock_user_string(arg1)))
6413 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006414 ret = get_errno(statfs(path(p), &stfs));
6415 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006416 convert_statfs:
6417 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006418 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006419
bellard579a97f2007-11-11 14:26:47 +00006420 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6421 goto efault;
6422 __put_user(stfs.f_type, &target_stfs->f_type);
6423 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6424 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6425 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6426 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6427 __put_user(stfs.f_files, &target_stfs->f_files);
6428 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6429 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6430 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6431 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00006432 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006433 }
6434 break;
6435 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006436 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006437 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006438#ifdef TARGET_NR_statfs64
6439 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006440 if (!(p = lock_user_string(arg1)))
6441 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006442 ret = get_errno(statfs(path(p), &stfs));
6443 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006444 convert_statfs64:
6445 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006446 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006447
bellard579a97f2007-11-11 14:26:47 +00006448 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6449 goto efault;
6450 __put_user(stfs.f_type, &target_stfs->f_type);
6451 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6452 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6453 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6454 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6455 __put_user(stfs.f_files, &target_stfs->f_files);
6456 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6457 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6458 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6459 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
6460 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006461 }
6462 break;
6463 case TARGET_NR_fstatfs64:
6464 ret = get_errno(fstatfs(arg1, &stfs));
6465 goto convert_statfs64;
6466#endif
bellardebc05482003-09-30 21:08:41 +00006467#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006468 case TARGET_NR_ioperm:
6469 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006470#endif
thse5febef2007-04-01 18:31:35 +00006471#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006472 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006473 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006474 break;
thse5febef2007-04-01 18:31:35 +00006475#endif
bellard3532fa72006-06-24 15:06:03 +00006476#ifdef TARGET_NR_accept
6477 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006478 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006479 break;
6480#endif
6481#ifdef TARGET_NR_bind
6482 case TARGET_NR_bind:
6483 ret = do_bind(arg1, arg2, arg3);
6484 break;
6485#endif
6486#ifdef TARGET_NR_connect
6487 case TARGET_NR_connect:
6488 ret = do_connect(arg1, arg2, arg3);
6489 break;
6490#endif
6491#ifdef TARGET_NR_getpeername
6492 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006493 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006494 break;
6495#endif
6496#ifdef TARGET_NR_getsockname
6497 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006498 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006499 break;
6500#endif
6501#ifdef TARGET_NR_getsockopt
6502 case TARGET_NR_getsockopt:
6503 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6504 break;
6505#endif
6506#ifdef TARGET_NR_listen
6507 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006508 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006509 break;
6510#endif
6511#ifdef TARGET_NR_recv
6512 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006513 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006514 break;
6515#endif
6516#ifdef TARGET_NR_recvfrom
6517 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006518 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006519 break;
6520#endif
6521#ifdef TARGET_NR_recvmsg
6522 case TARGET_NR_recvmsg:
6523 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6524 break;
6525#endif
6526#ifdef TARGET_NR_send
6527 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006528 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006529 break;
6530#endif
6531#ifdef TARGET_NR_sendmsg
6532 case TARGET_NR_sendmsg:
6533 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6534 break;
6535#endif
6536#ifdef TARGET_NR_sendto
6537 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006538 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006539 break;
6540#endif
6541#ifdef TARGET_NR_shutdown
6542 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006543 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006544 break;
6545#endif
6546#ifdef TARGET_NR_socket
6547 case TARGET_NR_socket:
6548 ret = do_socket(arg1, arg2, arg3);
6549 break;
6550#endif
6551#ifdef TARGET_NR_socketpair
6552 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006553 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006554 break;
6555#endif
6556#ifdef TARGET_NR_setsockopt
6557 case TARGET_NR_setsockopt:
6558 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6559 break;
6560#endif
ths7494b0f2007-02-11 18:26:53 +00006561
bellard31e31b82003-02-18 22:55:36 +00006562 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006563 if (!(p = lock_user_string(arg2)))
6564 goto efault;
thse5574482007-02-11 20:03:13 +00006565 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6566 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006567 break;
6568
bellard31e31b82003-02-18 22:55:36 +00006569 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006570 {
bellard66fb9762003-03-23 01:06:05 +00006571 struct itimerval value, ovalue, *pvalue;
6572
pbrook53a59602006-03-25 19:31:22 +00006573 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006574 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006575 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6576 || copy_from_user_timeval(&pvalue->it_value,
6577 arg2 + sizeof(struct target_timeval)))
6578 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006579 } else {
6580 pvalue = NULL;
6581 }
6582 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006583 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006584 if (copy_to_user_timeval(arg3,
6585 &ovalue.it_interval)
6586 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6587 &ovalue.it_value))
6588 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006589 }
6590 }
6591 break;
bellard31e31b82003-02-18 22:55:36 +00006592 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006593 {
bellard66fb9762003-03-23 01:06:05 +00006594 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006595
bellard66fb9762003-03-23 01:06:05 +00006596 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006597 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006598 if (copy_to_user_timeval(arg2,
6599 &value.it_interval)
6600 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6601 &value.it_value))
6602 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006603 }
6604 }
6605 break;
bellard31e31b82003-02-18 22:55:36 +00006606 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006607 if (!(p = lock_user_string(arg1)))
6608 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006609 ret = get_errno(stat(path(p), &st));
6610 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006611 goto do_stat;
6612 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006613 if (!(p = lock_user_string(arg1)))
6614 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006615 ret = get_errno(lstat(path(p), &st));
6616 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006617 goto do_stat;
6618 case TARGET_NR_fstat:
6619 {
6620 ret = get_errno(fstat(arg1, &st));
6621 do_stat:
6622 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006623 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006624
bellard579a97f2007-11-11 14:26:47 +00006625 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6626 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006627 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006628 __put_user(st.st_dev, &target_st->st_dev);
6629 __put_user(st.st_ino, &target_st->st_ino);
6630 __put_user(st.st_mode, &target_st->st_mode);
6631 __put_user(st.st_uid, &target_st->st_uid);
6632 __put_user(st.st_gid, &target_st->st_gid);
6633 __put_user(st.st_nlink, &target_st->st_nlink);
6634 __put_user(st.st_rdev, &target_st->st_rdev);
6635 __put_user(st.st_size, &target_st->st_size);
6636 __put_user(st.st_blksize, &target_st->st_blksize);
6637 __put_user(st.st_blocks, &target_st->st_blocks);
6638 __put_user(st.st_atime, &target_st->target_st_atime);
6639 __put_user(st.st_mtime, &target_st->target_st_mtime);
6640 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006641 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006642 }
6643 }
6644 break;
bellardebc05482003-09-30 21:08:41 +00006645#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006646 case TARGET_NR_olduname:
6647 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006648#endif
6649#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006650 case TARGET_NR_iopl:
6651 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006652#endif
bellard31e31b82003-02-18 22:55:36 +00006653 case TARGET_NR_vhangup:
6654 ret = get_errno(vhangup());
6655 break;
bellardebc05482003-09-30 21:08:41 +00006656#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006657 case TARGET_NR_idle:
6658 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006659#endif
bellard42ad6ae2005-01-03 22:48:11 +00006660#ifdef TARGET_NR_syscall
6661 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006662 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6663 arg6, arg7, arg8, 0);
6664 break;
bellard42ad6ae2005-01-03 22:48:11 +00006665#endif
bellard31e31b82003-02-18 22:55:36 +00006666 case TARGET_NR_wait4:
6667 {
6668 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006669 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006670 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006671 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006672 if (target_rusage)
6673 rusage_ptr = &rusage;
6674 else
6675 rusage_ptr = NULL;
6676 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6677 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006678 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006679 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006680 if (put_user_s32(status, status_ptr))
6681 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006682 }
bellard2f619692007-11-16 10:46:05 +00006683 if (target_rusage)
6684 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006685 }
6686 }
6687 break;
thse5febef2007-04-01 18:31:35 +00006688#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006689 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006690 if (!(p = lock_user_string(arg1)))
6691 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006692 ret = get_errno(swapoff(p));
6693 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006694 break;
thse5febef2007-04-01 18:31:35 +00006695#endif
bellard31e31b82003-02-18 22:55:36 +00006696 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006697 {
pbrook53a59602006-03-25 19:31:22 +00006698 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006699 struct sysinfo value;
6700 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006701 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006702 {
bellard579a97f2007-11-11 14:26:47 +00006703 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6704 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006705 __put_user(value.uptime, &target_value->uptime);
6706 __put_user(value.loads[0], &target_value->loads[0]);
6707 __put_user(value.loads[1], &target_value->loads[1]);
6708 __put_user(value.loads[2], &target_value->loads[2]);
6709 __put_user(value.totalram, &target_value->totalram);
6710 __put_user(value.freeram, &target_value->freeram);
6711 __put_user(value.sharedram, &target_value->sharedram);
6712 __put_user(value.bufferram, &target_value->bufferram);
6713 __put_user(value.totalswap, &target_value->totalswap);
6714 __put_user(value.freeswap, &target_value->freeswap);
6715 __put_user(value.procs, &target_value->procs);
6716 __put_user(value.totalhigh, &target_value->totalhigh);
6717 __put_user(value.freehigh, &target_value->freehigh);
6718 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006719 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006720 }
6721 }
6722 break;
thse5febef2007-04-01 18:31:35 +00006723#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006724 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006725 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6726 break;
thse5febef2007-04-01 18:31:35 +00006727#endif
aurel32e5289082009-04-18 16:16:12 +00006728#ifdef TARGET_NR_semget
6729 case TARGET_NR_semget:
6730 ret = get_errno(semget(arg1, arg2, arg3));
6731 break;
6732#endif
6733#ifdef TARGET_NR_semop
6734 case TARGET_NR_semop:
6735 ret = get_errno(do_semop(arg1, arg2, arg3));
6736 break;
6737#endif
6738#ifdef TARGET_NR_semctl
6739 case TARGET_NR_semctl:
6740 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6741 break;
6742#endif
aurel32eeb438c2008-10-13 21:08:55 +00006743#ifdef TARGET_NR_msgctl
6744 case TARGET_NR_msgctl:
6745 ret = do_msgctl(arg1, arg2, arg3);
6746 break;
6747#endif
6748#ifdef TARGET_NR_msgget
6749 case TARGET_NR_msgget:
6750 ret = get_errno(msgget(arg1, arg2));
6751 break;
6752#endif
6753#ifdef TARGET_NR_msgrcv
6754 case TARGET_NR_msgrcv:
6755 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6756 break;
6757#endif
6758#ifdef TARGET_NR_msgsnd
6759 case TARGET_NR_msgsnd:
6760 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6761 break;
6762#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006763#ifdef TARGET_NR_shmget
6764 case TARGET_NR_shmget:
6765 ret = get_errno(shmget(arg1, arg2, arg3));
6766 break;
6767#endif
6768#ifdef TARGET_NR_shmctl
6769 case TARGET_NR_shmctl:
6770 ret = do_shmctl(arg1, arg2, arg3);
6771 break;
6772#endif
6773#ifdef TARGET_NR_shmat
6774 case TARGET_NR_shmat:
6775 ret = do_shmat(arg1, arg2, arg3);
6776 break;
6777#endif
6778#ifdef TARGET_NR_shmdt
6779 case TARGET_NR_shmdt:
6780 ret = do_shmdt(arg1);
6781 break;
6782#endif
bellard31e31b82003-02-18 22:55:36 +00006783 case TARGET_NR_fsync:
6784 ret = get_errno(fsync(arg1));
6785 break;
bellard31e31b82003-02-18 22:55:36 +00006786 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006787#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006788 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006789#elif defined(TARGET_CRIS)
6790 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006791#elif defined(TARGET_S390X)
6792 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006793#else
pbrookd865bab2008-06-07 22:12:17 +00006794 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006795#endif
bellard1b6b0292003-03-22 17:31:38 +00006796 break;
bellardec86b0f2003-04-11 00:15:04 +00006797#ifdef __NR_exit_group
6798 /* new thread calls */
6799 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006800#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006801 _mcleanup();
6802#endif
bellarde9009672005-04-26 20:42:36 +00006803 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006804 ret = get_errno(exit_group(arg1));
6805 break;
6806#endif
bellard31e31b82003-02-18 22:55:36 +00006807 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006808 if (!(p = lock_user_string(arg1)))
6809 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006810 ret = get_errno(setdomainname(p, arg2));
6811 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006812 break;
6813 case TARGET_NR_uname:
6814 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006815 {
6816 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006817
bellard579a97f2007-11-11 14:26:47 +00006818 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6819 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006820 ret = get_errno(sys_uname(buf));
6821 if (!is_error(ret)) {
6822 /* Overrite the native machine name with whatever is being
6823 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006824 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006825 /* Allow the user to override the reported release. */
6826 if (qemu_uname_release && *qemu_uname_release)
6827 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006828 }
pbrook53a59602006-03-25 19:31:22 +00006829 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006830 }
bellard31e31b82003-02-18 22:55:36 +00006831 break;
bellard6dbad632003-03-16 18:05:05 +00006832#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006833 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006834 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006835 break;
j_mayer84409dd2007-04-06 08:56:50 +00006836#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006837 case TARGET_NR_vm86old:
6838 goto unimplemented;
6839 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006840 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006841 break;
6842#endif
j_mayer84409dd2007-04-06 08:56:50 +00006843#endif
bellard31e31b82003-02-18 22:55:36 +00006844 case TARGET_NR_adjtimex:
6845 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006846#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006847 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006848#endif
bellard31e31b82003-02-18 22:55:36 +00006849 case TARGET_NR_init_module:
6850 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006851#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006852 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006853#endif
bellard31e31b82003-02-18 22:55:36 +00006854 goto unimplemented;
6855 case TARGET_NR_quotactl:
6856 goto unimplemented;
6857 case TARGET_NR_getpgid:
6858 ret = get_errno(getpgid(arg1));
6859 break;
6860 case TARGET_NR_fchdir:
6861 ret = get_errno(fchdir(arg1));
6862 break;
j_mayer84409dd2007-04-06 08:56:50 +00006863#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006864 case TARGET_NR_bdflush:
6865 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006866#endif
thse5febef2007-04-01 18:31:35 +00006867#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006868 case TARGET_NR_sysfs:
6869 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006870#endif
bellard31e31b82003-02-18 22:55:36 +00006871 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006872 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006873 break;
thse5febef2007-04-01 18:31:35 +00006874#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006875 case TARGET_NR_afs_syscall:
6876 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006877#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006878#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006879 case TARGET_NR__llseek:
6880 {
6881 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006882#if !defined(__NR_llseek)
6883 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6884 if (res == -1) {
6885 ret = get_errno(res);
6886 } else {
6887 ret = 0;
6888 }
6889#else
bellard31e31b82003-02-18 22:55:36 +00006890 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006891#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006892 if ((ret == 0) && put_user_s64(res, arg4)) {
6893 goto efault;
6894 }
bellard31e31b82003-02-18 22:55:36 +00006895 }
6896 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006897#endif
bellard31e31b82003-02-18 22:55:36 +00006898 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006899#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006900 {
pbrook53a59602006-03-25 19:31:22 +00006901 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006902 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006903 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006904
6905 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006906 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006907 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006908 goto fail;
6909 }
ths3b46e622007-09-17 08:09:54 +00006910
bellard4add45b2003-06-05 01:52:59 +00006911 ret = get_errno(sys_getdents(arg1, dirp, count));
6912 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006913 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006914 struct target_dirent *tde;
6915 int len = ret;
6916 int reclen, treclen;
6917 int count1, tnamelen;
6918
6919 count1 = 0;
6920 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006921 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6922 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006923 tde = target_dirp;
6924 while (len > 0) {
6925 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006926 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006927 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006928 tde->d_ino = tswapal(de->d_ino);
6929 tde->d_off = tswapal(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006930 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006931 if (tnamelen > 256)
6932 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006933 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006934 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006935 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006936 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006937 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006938 count1 += treclen;
6939 }
6940 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006941 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006942 }
6943 free(dirp);
6944 }
6945#else
bellard31e31b82003-02-18 22:55:36 +00006946 {
aurel326556a832008-10-13 21:08:17 +00006947 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006948 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006949
bellard579a97f2007-11-11 14:26:47 +00006950 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6951 goto efault;
bellard72f03902003-02-18 23:33:18 +00006952 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006953 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006954 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006955 int len = ret;
6956 int reclen;
6957 de = dirp;
6958 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006959 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006960 if (reclen > len)
6961 break;
bellard8083a3e2003-03-24 23:12:16 +00006962 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006963 tswapls(&de->d_ino);
6964 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006965 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006966 len -= reclen;
6967 }
6968 }
pbrook53a59602006-03-25 19:31:22 +00006969 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006970 }
bellard4add45b2003-06-05 01:52:59 +00006971#endif
bellard31e31b82003-02-18 22:55:36 +00006972 break;
ths3ae43202007-09-16 21:39:48 +00006973#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006974 case TARGET_NR_getdents64:
6975 {
aurel326556a832008-10-13 21:08:17 +00006976 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006977 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006978 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6979 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006980 ret = get_errno(sys_getdents64(arg1, dirp, count));
6981 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006982 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006983 int len = ret;
6984 int reclen;
6985 de = dirp;
6986 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006987 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006988 if (reclen > len)
6989 break;
bellard8083a3e2003-03-24 23:12:16 +00006990 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006991 tswap64s((uint64_t *)&de->d_ino);
6992 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006993 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006994 len -= reclen;
6995 }
6996 }
pbrook53a59602006-03-25 19:31:22 +00006997 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006998 }
6999 break;
bellarda541f292004-04-12 20:39:29 +00007000#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007001#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
7002#ifdef TARGET_S390X
7003 case TARGET_NR_select:
7004#else
bellard31e31b82003-02-18 22:55:36 +00007005 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007006#endif
pbrook53a59602006-03-25 19:31:22 +00007007 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007008 break;
thse5febef2007-04-01 18:31:35 +00007009#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007010#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7011# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007012 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007013# endif
7014# ifdef TARGET_NR_ppoll
7015 case TARGET_NR_ppoll:
7016# endif
bellard9de5e442003-03-23 16:49:39 +00007017 {
pbrook53a59602006-03-25 19:31:22 +00007018 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007019 unsigned int nfds = arg2;
7020 int timeout = arg3;
7021 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007022 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007023
bellard579a97f2007-11-11 14:26:47 +00007024 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7025 if (!target_pfd)
7026 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007027
bellard9de5e442003-03-23 16:49:39 +00007028 pfd = alloca(sizeof(struct pollfd) * nfds);
7029 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007030 pfd[i].fd = tswap32(target_pfd[i].fd);
7031 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007032 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007033
7034# ifdef TARGET_NR_ppoll
7035 if (num == TARGET_NR_ppoll) {
7036 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7037 target_sigset_t *target_set;
7038 sigset_t _set, *set = &_set;
7039
7040 if (arg3) {
7041 if (target_to_host_timespec(timeout_ts, arg3)) {
7042 unlock_user(target_pfd, arg1, 0);
7043 goto efault;
7044 }
7045 } else {
7046 timeout_ts = NULL;
7047 }
7048
7049 if (arg4) {
7050 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7051 if (!target_set) {
7052 unlock_user(target_pfd, arg1, 0);
7053 goto efault;
7054 }
7055 target_to_host_sigset(set, target_set);
7056 } else {
7057 set = NULL;
7058 }
7059
7060 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7061
7062 if (!is_error(ret) && arg3) {
7063 host_to_target_timespec(arg3, timeout_ts);
7064 }
7065 if (arg4) {
7066 unlock_user(target_set, arg4, 0);
7067 }
7068 } else
7069# endif
7070 ret = get_errno(poll(pfd, nfds, timeout));
7071
bellard9de5e442003-03-23 16:49:39 +00007072 if (!is_error(ret)) {
7073 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007074 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007075 }
7076 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007077 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007078 }
7079 break;
thse5febef2007-04-01 18:31:35 +00007080#endif
bellard31e31b82003-02-18 22:55:36 +00007081 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007082 /* NOTE: the flock constant seems to be the same for every
7083 Linux platform */
7084 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007085 break;
7086 case TARGET_NR_readv:
7087 {
7088 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00007089 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00007090
7091 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00007092 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
7093 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007094 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00007095 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00007096 }
7097 break;
7098 case TARGET_NR_writev:
7099 {
7100 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00007101 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00007102
7103 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00007104 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7105 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007106 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00007107 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00007108 }
7109 break;
7110 case TARGET_NR_getsid:
7111 ret = get_errno(getsid(arg1));
7112 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007113#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007114 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007115 ret = get_errno(fdatasync(arg1));
7116 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007117#endif
bellard31e31b82003-02-18 22:55:36 +00007118 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007119 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007120 return value. */
ths0da46a62007-10-20 20:23:07 +00007121 ret = -TARGET_ENOTDIR;
7122 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007123 case TARGET_NR_sched_getaffinity:
7124 {
7125 unsigned int mask_size;
7126 unsigned long *mask;
7127
7128 /*
7129 * sched_getaffinity needs multiples of ulong, so need to take
7130 * care of mismatches between target ulong and host ulong sizes.
7131 */
7132 if (arg2 & (sizeof(abi_ulong) - 1)) {
7133 ret = -TARGET_EINVAL;
7134 break;
7135 }
7136 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7137
7138 mask = alloca(mask_size);
7139 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7140
7141 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007142 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007143 goto efault;
7144 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007145 }
7146 }
7147 break;
7148 case TARGET_NR_sched_setaffinity:
7149 {
7150 unsigned int mask_size;
7151 unsigned long *mask;
7152
7153 /*
7154 * sched_setaffinity needs multiples of ulong, so need to take
7155 * care of mismatches between target ulong and host ulong sizes.
7156 */
7157 if (arg2 & (sizeof(abi_ulong) - 1)) {
7158 ret = -TARGET_EINVAL;
7159 break;
7160 }
7161 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7162
7163 mask = alloca(mask_size);
7164 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7165 goto efault;
7166 }
7167 memcpy(mask, p, arg2);
7168 unlock_user_struct(p, arg2, 0);
7169
7170 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7171 }
7172 break;
bellard31e31b82003-02-18 22:55:36 +00007173 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007174 {
pbrook53a59602006-03-25 19:31:22 +00007175 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007176 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007177
bellard579a97f2007-11-11 14:26:47 +00007178 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7179 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007180 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007181 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007182 ret = get_errno(sched_setparam(arg1, &schp));
7183 }
7184 break;
bellard31e31b82003-02-18 22:55:36 +00007185 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007186 {
pbrook53a59602006-03-25 19:31:22 +00007187 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007188 struct sched_param schp;
7189 ret = get_errno(sched_getparam(arg1, &schp));
7190 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007191 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7192 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007193 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007194 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007195 }
7196 }
7197 break;
bellard31e31b82003-02-18 22:55:36 +00007198 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007199 {
pbrook53a59602006-03-25 19:31:22 +00007200 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007201 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007202 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7203 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007204 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007205 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007206 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7207 }
7208 break;
bellard31e31b82003-02-18 22:55:36 +00007209 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007210 ret = get_errno(sched_getscheduler(arg1));
7211 break;
bellard31e31b82003-02-18 22:55:36 +00007212 case TARGET_NR_sched_yield:
7213 ret = get_errno(sched_yield());
7214 break;
7215 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007216 ret = get_errno(sched_get_priority_max(arg1));
7217 break;
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007219 ret = get_errno(sched_get_priority_min(arg1));
7220 break;
bellard31e31b82003-02-18 22:55:36 +00007221 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007222 {
bellard5cd43932003-03-29 16:54:36 +00007223 struct timespec ts;
7224 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7225 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007226 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007227 }
7228 }
7229 break;
bellard31e31b82003-02-18 22:55:36 +00007230 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007231 {
bellard1b6b0292003-03-22 17:31:38 +00007232 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007233 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007234 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007235 if (is_error(ret) && arg2) {
7236 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007237 }
7238 }
7239 break;
thse5febef2007-04-01 18:31:35 +00007240#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007241 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007242 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007243#endif
7244#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007245 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007246 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007247#endif
bellard31e31b82003-02-18 22:55:36 +00007248 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007249 switch (arg1) {
7250 case PR_GET_PDEATHSIG:
7251 {
7252 int deathsig;
7253 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7254 if (!is_error(ret) && arg2
7255 && put_user_ual(deathsig, arg2)) {
7256 goto efault;
thse5574482007-02-11 20:03:13 +00007257 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007258 break;
7259 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007260#ifdef PR_GET_NAME
7261 case PR_GET_NAME:
7262 {
7263 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7264 if (!name) {
7265 goto efault;
7266 }
7267 ret = get_errno(prctl(arg1, (unsigned long)name,
7268 arg3, arg4, arg5));
7269 unlock_user(name, arg2, 16);
7270 break;
7271 }
7272 case PR_SET_NAME:
7273 {
7274 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7275 if (!name) {
7276 goto efault;
7277 }
7278 ret = get_errno(prctl(arg1, (unsigned long)name,
7279 arg3, arg4, arg5));
7280 unlock_user(name, arg2, 0);
7281 break;
7282 }
7283#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007284 default:
7285 /* Most prctl options have no pointer arguments */
7286 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7287 break;
7288 }
ths39b9aae2007-02-11 18:36:44 +00007289 break;
bellardd2fd1af2007-11-14 18:08:56 +00007290#ifdef TARGET_NR_arch_prctl
7291 case TARGET_NR_arch_prctl:
7292#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7293 ret = do_arch_prctl(cpu_env, arg1, arg2);
7294 break;
7295#else
7296 goto unimplemented;
7297#endif
7298#endif
bellard67867302003-11-23 17:05:30 +00007299#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00007300 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03007301 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007302 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007303 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7304 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007305 ret = get_errno(pread(arg1, p, arg3, arg4));
7306 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00007307 break;
bellard31e31b82003-02-18 22:55:36 +00007308 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03007309 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007310 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007311 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7312 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007313 ret = get_errno(pwrite(arg1, p, arg3, arg4));
7314 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00007315 break;
bellard67867302003-11-23 17:05:30 +00007316#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007317#ifdef TARGET_NR_pread64
7318 case TARGET_NR_pread64:
7319 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7320 goto efault;
7321 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7322 unlock_user(p, arg2, ret);
7323 break;
7324 case TARGET_NR_pwrite64:
7325 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7326 goto efault;
7327 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7328 unlock_user(p, arg2, 0);
7329 break;
7330#endif
bellard31e31b82003-02-18 22:55:36 +00007331 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007332 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7333 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007334 ret = get_errno(sys_getcwd1(p, arg2));
7335 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007336 break;
7337 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007338 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007339 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007340 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007341 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007342#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007343 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007344 defined(TARGET_M68K) || defined(TARGET_S390X)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007345 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007346 break;
7347#else
bellard5cd43932003-03-29 16:54:36 +00007348 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007349#endif
bellard31e31b82003-02-18 22:55:36 +00007350 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00007351 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007352#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007353 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007354 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007355#endif
7356#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007357 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007358 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007359#endif
bellard048f6b42005-11-26 18:47:20 +00007360#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007361 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007362 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7363 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007364 break;
bellard048f6b42005-11-26 18:47:20 +00007365#endif
bellardebc05482003-09-30 21:08:41 +00007366#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007367 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007368 {
7369 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007370 int resource = target_to_host_resource(arg1);
7371 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007372 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007373 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007374 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7375 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007376 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7377 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007378 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007379 }
7380 break;
7381 }
bellardebc05482003-09-30 21:08:41 +00007382#endif
bellarda315a142005-01-30 22:59:18 +00007383#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007384 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007385 if (!(p = lock_user_string(arg1)))
7386 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007387 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7388 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007389 break;
bellarda315a142005-01-30 22:59:18 +00007390#endif
7391#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007392 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007393 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007394 break;
bellarda315a142005-01-30 22:59:18 +00007395#endif
7396#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007397 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007398 if (!(p = lock_user_string(arg1)))
7399 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007400 ret = get_errno(stat(path(p), &st));
7401 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007402 if (!is_error(ret))
7403 ret = host_to_target_stat64(cpu_env, arg2, &st);
7404 break;
bellarda315a142005-01-30 22:59:18 +00007405#endif
7406#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007407 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007408 if (!(p = lock_user_string(arg1)))
7409 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007410 ret = get_errno(lstat(path(p), &st));
7411 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007412 if (!is_error(ret))
7413 ret = host_to_target_stat64(cpu_env, arg2, &st);
7414 break;
bellarda315a142005-01-30 22:59:18 +00007415#endif
7416#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007417 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007418 ret = get_errno(fstat(arg1, &st));
7419 if (!is_error(ret))
7420 ret = host_to_target_stat64(cpu_env, arg2, &st);
7421 break;
bellardec86b0f2003-04-11 00:15:04 +00007422#endif
aurel329d33b762009-04-08 23:07:05 +00007423#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7424 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7425#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007426 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007427#endif
7428#ifdef TARGET_NR_newfstatat
7429 case TARGET_NR_newfstatat:
7430#endif
balrog6a24a772008-09-20 02:23:36 +00007431 if (!(p = lock_user_string(arg2)))
7432 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007433#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007434 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007435#else
7436 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7437#endif
balrog6a24a772008-09-20 02:23:36 +00007438 if (!is_error(ret))
7439 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007440 break;
bellarda315a142005-01-30 22:59:18 +00007441#endif
bellard67867302003-11-23 17:05:30 +00007442 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007443 if (!(p = lock_user_string(arg1)))
7444 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007445 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7446 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007447 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007448#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007449 case TARGET_NR_getuid:
7450 ret = get_errno(high2lowuid(getuid()));
7451 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007452#endif
7453#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007454 case TARGET_NR_getgid:
7455 ret = get_errno(high2lowgid(getgid()));
7456 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007457#endif
7458#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007459 case TARGET_NR_geteuid:
7460 ret = get_errno(high2lowuid(geteuid()));
7461 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007462#endif
7463#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007464 case TARGET_NR_getegid:
7465 ret = get_errno(high2lowgid(getegid()));
7466 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007467#endif
bellard67867302003-11-23 17:05:30 +00007468 case TARGET_NR_setreuid:
7469 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7470 break;
7471 case TARGET_NR_setregid:
7472 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7473 break;
7474 case TARGET_NR_getgroups:
7475 {
7476 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007477 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007478 gid_t *grouplist;
7479 int i;
7480
7481 grouplist = alloca(gidsetsize * sizeof(gid_t));
7482 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007483 if (gidsetsize == 0)
7484 break;
bellard67867302003-11-23 17:05:30 +00007485 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007486 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7487 if (!target_grouplist)
7488 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007489 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007490 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007491 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007492 }
7493 }
7494 break;
7495 case TARGET_NR_setgroups:
7496 {
7497 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007498 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007499 gid_t *grouplist;
7500 int i;
7501
7502 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007503 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7504 if (!target_grouplist) {
7505 ret = -TARGET_EFAULT;
7506 goto fail;
7507 }
bellard67867302003-11-23 17:05:30 +00007508 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007509 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007510 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007511 ret = get_errno(setgroups(gidsetsize, grouplist));
7512 }
7513 break;
7514 case TARGET_NR_fchown:
7515 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7516 break;
thsccfa72b2007-09-24 09:23:34 +00007517#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7518 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007519 if (!(p = lock_user_string(arg2)))
7520 goto efault;
7521 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7522 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007523 break;
7524#endif
bellard67867302003-11-23 17:05:30 +00007525#ifdef TARGET_NR_setresuid
7526 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007527 ret = get_errno(setresuid(low2highuid(arg1),
7528 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007529 low2highuid(arg3)));
7530 break;
7531#endif
7532#ifdef TARGET_NR_getresuid
7533 case TARGET_NR_getresuid:
7534 {
pbrook53a59602006-03-25 19:31:22 +00007535 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007536 ret = get_errno(getresuid(&ruid, &euid, &suid));
7537 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007538 if (put_user_u16(high2lowuid(ruid), arg1)
7539 || put_user_u16(high2lowuid(euid), arg2)
7540 || put_user_u16(high2lowuid(suid), arg3))
7541 goto efault;
bellard67867302003-11-23 17:05:30 +00007542 }
7543 }
7544 break;
7545#endif
7546#ifdef TARGET_NR_getresgid
7547 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007548 ret = get_errno(setresgid(low2highgid(arg1),
7549 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007550 low2highgid(arg3)));
7551 break;
7552#endif
7553#ifdef TARGET_NR_getresgid
7554 case TARGET_NR_getresgid:
7555 {
pbrook53a59602006-03-25 19:31:22 +00007556 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007557 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7558 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007559 if (put_user_u16(high2lowgid(rgid), arg1)
7560 || put_user_u16(high2lowgid(egid), arg2)
7561 || put_user_u16(high2lowgid(sgid), arg3))
7562 goto efault;
bellard67867302003-11-23 17:05:30 +00007563 }
7564 }
7565 break;
7566#endif
7567 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007568 if (!(p = lock_user_string(arg1)))
7569 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007570 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7571 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007572 break;
7573 case TARGET_NR_setuid:
7574 ret = get_errno(setuid(low2highuid(arg1)));
7575 break;
7576 case TARGET_NR_setgid:
7577 ret = get_errno(setgid(low2highgid(arg1)));
7578 break;
7579 case TARGET_NR_setfsuid:
7580 ret = get_errno(setfsuid(arg1));
7581 break;
7582 case TARGET_NR_setfsgid:
7583 ret = get_errno(setfsgid(arg1));
7584 break;
bellard67867302003-11-23 17:05:30 +00007585
bellarda315a142005-01-30 22:59:18 +00007586#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007587 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007588 if (!(p = lock_user_string(arg1)))
7589 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007590 ret = get_errno(lchown(p, arg2, arg3));
7591 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007592 break;
bellarda315a142005-01-30 22:59:18 +00007593#endif
7594#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007595 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007596 ret = get_errno(getuid());
7597 break;
bellarda315a142005-01-30 22:59:18 +00007598#endif
aurel3264b4d282008-11-14 17:20:15 +00007599
7600#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7601 /* Alpha specific */
7602 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007603 {
7604 uid_t euid;
7605 euid=geteuid();
7606 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7607 }
aurel3264b4d282008-11-14 17:20:15 +00007608 ret = get_errno(getuid());
7609 break;
7610#endif
7611#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7612 /* Alpha specific */
7613 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007614 {
7615 uid_t egid;
7616 egid=getegid();
7617 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7618 }
aurel3264b4d282008-11-14 17:20:15 +00007619 ret = get_errno(getgid());
7620 break;
7621#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007622#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7623 /* Alpha specific */
7624 case TARGET_NR_osf_getsysinfo:
7625 ret = -TARGET_EOPNOTSUPP;
7626 switch (arg1) {
7627 case TARGET_GSI_IEEE_FP_CONTROL:
7628 {
7629 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7630
7631 /* Copied from linux ieee_fpcr_to_swcr. */
7632 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7633 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7634 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7635 | SWCR_TRAP_ENABLE_DZE
7636 | SWCR_TRAP_ENABLE_OVF);
7637 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7638 | SWCR_TRAP_ENABLE_INE);
7639 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7640 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7641
7642 if (put_user_u64 (swcr, arg2))
7643 goto efault;
7644 ret = 0;
7645 }
7646 break;
7647
7648 /* case GSI_IEEE_STATE_AT_SIGNAL:
7649 -- Not implemented in linux kernel.
7650 case GSI_UACPROC:
7651 -- Retrieves current unaligned access state; not much used.
7652 case GSI_PROC_TYPE:
7653 -- Retrieves implver information; surely not used.
7654 case GSI_GET_HWRPB:
7655 -- Grabs a copy of the HWRPB; surely not used.
7656 */
7657 }
7658 break;
7659#endif
7660#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7661 /* Alpha specific */
7662 case TARGET_NR_osf_setsysinfo:
7663 ret = -TARGET_EOPNOTSUPP;
7664 switch (arg1) {
7665 case TARGET_SSI_IEEE_FP_CONTROL:
7666 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7667 {
7668 uint64_t swcr, fpcr, orig_fpcr;
7669
7670 if (get_user_u64 (swcr, arg2))
7671 goto efault;
7672 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7673 fpcr = orig_fpcr & FPCR_DYN_MASK;
7674
7675 /* Copied from linux ieee_swcr_to_fpcr. */
7676 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7677 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7678 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7679 | SWCR_TRAP_ENABLE_DZE
7680 | SWCR_TRAP_ENABLE_OVF)) << 48;
7681 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7682 | SWCR_TRAP_ENABLE_INE)) << 57;
7683 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7684 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7685
7686 cpu_alpha_store_fpcr (cpu_env, fpcr);
7687 ret = 0;
7688
7689 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7690 /* Old exceptions are not signaled. */
7691 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7692
7693 /* If any exceptions set by this call, and are unmasked,
7694 send a signal. */
7695 /* ??? FIXME */
7696 }
7697 }
7698 break;
7699
7700 /* case SSI_NVPAIRS:
7701 -- Used with SSIN_UACPROC to enable unaligned accesses.
7702 case SSI_IEEE_STATE_AT_SIGNAL:
7703 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7704 -- Not implemented in linux kernel
7705 */
7706 }
7707 break;
7708#endif
7709#ifdef TARGET_NR_osf_sigprocmask
7710 /* Alpha specific. */
7711 case TARGET_NR_osf_sigprocmask:
7712 {
7713 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007714 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007715 sigset_t set, oldset;
7716
7717 switch(arg1) {
7718 case TARGET_SIG_BLOCK:
7719 how = SIG_BLOCK;
7720 break;
7721 case TARGET_SIG_UNBLOCK:
7722 how = SIG_UNBLOCK;
7723 break;
7724 case TARGET_SIG_SETMASK:
7725 how = SIG_SETMASK;
7726 break;
7727 default:
7728 ret = -TARGET_EINVAL;
7729 goto fail;
7730 }
7731 mask = arg2;
7732 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007733 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007734 host_to_target_old_sigset(&mask, &oldset);
7735 ret = mask;
7736 }
7737 break;
7738#endif
aurel3264b4d282008-11-14 17:20:15 +00007739
bellarda315a142005-01-30 22:59:18 +00007740#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007741 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007742 ret = get_errno(getgid());
7743 break;
bellarda315a142005-01-30 22:59:18 +00007744#endif
7745#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007746 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007747 ret = get_errno(geteuid());
7748 break;
bellarda315a142005-01-30 22:59:18 +00007749#endif
7750#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007751 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007752 ret = get_errno(getegid());
7753 break;
bellarda315a142005-01-30 22:59:18 +00007754#endif
7755#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007756 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007757 ret = get_errno(setreuid(arg1, arg2));
7758 break;
bellarda315a142005-01-30 22:59:18 +00007759#endif
7760#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007761 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007762 ret = get_errno(setregid(arg1, arg2));
7763 break;
bellarda315a142005-01-30 22:59:18 +00007764#endif
7765#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007766 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007767 {
7768 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007769 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007770 gid_t *grouplist;
7771 int i;
7772
7773 grouplist = alloca(gidsetsize * sizeof(gid_t));
7774 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007775 if (gidsetsize == 0)
7776 break;
bellard99c475a2005-01-31 20:45:13 +00007777 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007778 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7779 if (!target_grouplist) {
7780 ret = -TARGET_EFAULT;
7781 goto fail;
7782 }
balroga2155fc2008-09-20 02:12:08 +00007783 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007784 target_grouplist[i] = tswap32(grouplist[i]);
7785 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007786 }
7787 }
7788 break;
bellarda315a142005-01-30 22:59:18 +00007789#endif
7790#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007791 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007792 {
7793 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007794 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007795 gid_t *grouplist;
7796 int i;
ths3b46e622007-09-17 08:09:54 +00007797
bellard99c475a2005-01-31 20:45:13 +00007798 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007799 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7800 if (!target_grouplist) {
7801 ret = -TARGET_EFAULT;
7802 goto fail;
7803 }
bellard99c475a2005-01-31 20:45:13 +00007804 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007805 grouplist[i] = tswap32(target_grouplist[i]);
7806 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007807 ret = get_errno(setgroups(gidsetsize, grouplist));
7808 }
7809 break;
bellarda315a142005-01-30 22:59:18 +00007810#endif
7811#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007812 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007813 ret = get_errno(fchown(arg1, arg2, arg3));
7814 break;
bellarda315a142005-01-30 22:59:18 +00007815#endif
7816#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007817 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007818 ret = get_errno(setresuid(arg1, arg2, arg3));
7819 break;
bellarda315a142005-01-30 22:59:18 +00007820#endif
7821#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007822 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007823 {
pbrook53a59602006-03-25 19:31:22 +00007824 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007825 ret = get_errno(getresuid(&ruid, &euid, &suid));
7826 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007827 if (put_user_u32(ruid, arg1)
7828 || put_user_u32(euid, arg2)
7829 || put_user_u32(suid, arg3))
7830 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007831 }
7832 }
7833 break;
bellarda315a142005-01-30 22:59:18 +00007834#endif
7835#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007836 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007837 ret = get_errno(setresgid(arg1, arg2, arg3));
7838 break;
bellarda315a142005-01-30 22:59:18 +00007839#endif
7840#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007841 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007842 {
pbrook53a59602006-03-25 19:31:22 +00007843 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007844 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7845 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007846 if (put_user_u32(rgid, arg1)
7847 || put_user_u32(egid, arg2)
7848 || put_user_u32(sgid, arg3))
7849 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007850 }
7851 }
7852 break;
bellarda315a142005-01-30 22:59:18 +00007853#endif
7854#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007855 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007856 if (!(p = lock_user_string(arg1)))
7857 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007858 ret = get_errno(chown(p, arg2, arg3));
7859 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007860 break;
bellarda315a142005-01-30 22:59:18 +00007861#endif
7862#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007863 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007864 ret = get_errno(setuid(arg1));
7865 break;
bellarda315a142005-01-30 22:59:18 +00007866#endif
7867#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007868 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007869 ret = get_errno(setgid(arg1));
7870 break;
bellarda315a142005-01-30 22:59:18 +00007871#endif
7872#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007873 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007874 ret = get_errno(setfsuid(arg1));
7875 break;
bellarda315a142005-01-30 22:59:18 +00007876#endif
7877#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007878 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007879 ret = get_errno(setfsgid(arg1));
7880 break;
bellarda315a142005-01-30 22:59:18 +00007881#endif
bellard67867302003-11-23 17:05:30 +00007882
bellard31e31b82003-02-18 22:55:36 +00007883 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007884 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007885#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007886 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007887 {
7888 void *a;
7889 ret = -TARGET_EFAULT;
7890 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7891 goto efault;
7892 if (!(p = lock_user_string(arg3)))
7893 goto mincore_fail;
7894 ret = get_errno(mincore(a, arg2, p));
7895 unlock_user(p, arg3, ret);
7896 mincore_fail:
7897 unlock_user(a, arg1, 0);
7898 }
7899 break;
bellardffa65c32004-01-04 23:57:22 +00007900#endif
aurel32408321b2008-10-01 21:46:32 +00007901#ifdef TARGET_NR_arm_fadvise64_64
7902 case TARGET_NR_arm_fadvise64_64:
7903 {
7904 /*
7905 * arm_fadvise64_64 looks like fadvise64_64 but
7906 * with different argument order
7907 */
7908 abi_long temp;
7909 temp = arg3;
7910 arg3 = arg4;
7911 arg4 = temp;
7912 }
7913#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007914#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007915#ifdef TARGET_NR_fadvise64_64
7916 case TARGET_NR_fadvise64_64:
7917#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007918#ifdef TARGET_NR_fadvise64
7919 case TARGET_NR_fadvise64:
7920#endif
7921#ifdef TARGET_S390X
7922 switch (arg4) {
7923 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7924 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7925 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7926 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7927 default: break;
7928 }
7929#endif
7930 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007931 break;
7932#endif
bellardffa65c32004-01-04 23:57:22 +00007933#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007934 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007935 /* A straight passthrough may not be safe because qemu sometimes
7936 turns private flie-backed mappings into anonymous mappings.
7937 This will break MADV_DONTNEED.
7938 This is a hint, so ignoring and returning success is ok. */
7939 ret = get_errno(0);
7940 break;
bellardffa65c32004-01-04 23:57:22 +00007941#endif
blueswir1992f48a2007-10-14 16:27:31 +00007942#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007943 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007944 {
thsb1e341e2007-03-20 21:50:52 +00007945 int cmd;
bellard77e46722003-04-29 20:39:06 +00007946 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007947 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007948#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007949 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007950#endif
bellard77e46722003-04-29 20:39:06 +00007951
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007952 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00007953 if (cmd == -TARGET_EINVAL) {
7954 ret = cmd;
7955 break;
7956 }
thsb1e341e2007-03-20 21:50:52 +00007957
bellard60cd49d2003-03-16 22:53:56 +00007958 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007959 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007960#ifdef TARGET_ARM
7961 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007962 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7963 goto efault;
ths58134272007-03-31 18:59:32 +00007964 fl.l_type = tswap16(target_efl->l_type);
7965 fl.l_whence = tswap16(target_efl->l_whence);
7966 fl.l_start = tswap64(target_efl->l_start);
7967 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007968 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007969 unlock_user_struct(target_efl, arg3, 0);
7970 } else
7971#endif
7972 {
bellard9ee1fa22007-11-11 15:11:19 +00007973 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7974 goto efault;
ths58134272007-03-31 18:59:32 +00007975 fl.l_type = tswap16(target_fl->l_type);
7976 fl.l_whence = tswap16(target_fl->l_whence);
7977 fl.l_start = tswap64(target_fl->l_start);
7978 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007979 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007980 unlock_user_struct(target_fl, arg3, 0);
7981 }
thsb1e341e2007-03-20 21:50:52 +00007982 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007983 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007984#ifdef TARGET_ARM
7985 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007986 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7987 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007988 target_efl->l_type = tswap16(fl.l_type);
7989 target_efl->l_whence = tswap16(fl.l_whence);
7990 target_efl->l_start = tswap64(fl.l_start);
7991 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007992 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007993 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007994 } else
7995#endif
7996 {
bellard9ee1fa22007-11-11 15:11:19 +00007997 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7998 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007999 target_fl->l_type = tswap16(fl.l_type);
8000 target_fl->l_whence = tswap16(fl.l_whence);
8001 target_fl->l_start = tswap64(fl.l_start);
8002 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008003 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008004 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008005 }
bellard77e46722003-04-29 20:39:06 +00008006 }
8007 break;
8008
thsb1e341e2007-03-20 21:50:52 +00008009 case TARGET_F_SETLK64:
8010 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008011#ifdef TARGET_ARM
8012 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008013 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8014 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008015 fl.l_type = tswap16(target_efl->l_type);
8016 fl.l_whence = tswap16(target_efl->l_whence);
8017 fl.l_start = tswap64(target_efl->l_start);
8018 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008019 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008020 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008021 } else
8022#endif
8023 {
bellard9ee1fa22007-11-11 15:11:19 +00008024 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8025 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008026 fl.l_type = tswap16(target_fl->l_type);
8027 fl.l_whence = tswap16(target_fl->l_whence);
8028 fl.l_start = tswap64(target_fl->l_start);
8029 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008030 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008031 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008032 }
thsb1e341e2007-03-20 21:50:52 +00008033 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008034 break;
bellard60cd49d2003-03-16 22:53:56 +00008035 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008036 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008037 break;
8038 }
bellard77e46722003-04-29 20:39:06 +00008039 break;
8040 }
bellard60cd49d2003-03-16 22:53:56 +00008041#endif
ths7d600c82006-12-08 01:32:58 +00008042#ifdef TARGET_NR_cacheflush
8043 case TARGET_NR_cacheflush:
8044 /* self-modifying code is handled automatically, so nothing needed */
8045 ret = 0;
8046 break;
8047#endif
bellardebc05482003-09-30 21:08:41 +00008048#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008049 case TARGET_NR_security:
8050 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008051#endif
bellardc573ff62004-01-04 15:51:36 +00008052#ifdef TARGET_NR_getpagesize
8053 case TARGET_NR_getpagesize:
8054 ret = TARGET_PAGE_SIZE;
8055 break;
8056#endif
bellard31e31b82003-02-18 22:55:36 +00008057 case TARGET_NR_gettid:
8058 ret = get_errno(gettid());
8059 break;
thse5febef2007-04-01 18:31:35 +00008060#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008061 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008062#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008063 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008064 arg2 = arg3;
8065 arg3 = arg4;
8066 arg4 = arg5;
8067 }
aurel322054ac92008-10-13 21:08:07 +00008068 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8069#else
8070 ret = get_errno(readahead(arg1, arg2, arg3));
8071#endif
8072 break;
thse5febef2007-04-01 18:31:35 +00008073#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008074#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008075#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008076 case TARGET_NR_listxattr:
8077 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008078 {
8079 void *p, *b = 0;
8080 if (arg2) {
8081 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8082 if (!b) {
8083 ret = -TARGET_EFAULT;
8084 break;
8085 }
8086 }
8087 p = lock_user_string(arg1);
8088 if (p) {
8089 if (num == TARGET_NR_listxattr) {
8090 ret = get_errno(listxattr(p, b, arg3));
8091 } else {
8092 ret = get_errno(llistxattr(p, b, arg3));
8093 }
8094 } else {
8095 ret = -TARGET_EFAULT;
8096 }
8097 unlock_user(p, arg1, 0);
8098 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008099 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008100 }
8101 case TARGET_NR_flistxattr:
8102 {
8103 void *b = 0;
8104 if (arg2) {
8105 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8106 if (!b) {
8107 ret = -TARGET_EFAULT;
8108 break;
8109 }
8110 }
8111 ret = get_errno(flistxattr(arg1, b, arg3));
8112 unlock_user(b, arg2, arg3);
8113 break;
8114 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008115 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008116 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008117 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008118 void *p, *n, *v = 0;
8119 if (arg3) {
8120 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8121 if (!v) {
8122 ret = -TARGET_EFAULT;
8123 break;
8124 }
8125 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008126 p = lock_user_string(arg1);
8127 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008128 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008129 if (num == TARGET_NR_setxattr) {
8130 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8131 } else {
8132 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8133 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008134 } else {
8135 ret = -TARGET_EFAULT;
8136 }
8137 unlock_user(p, arg1, 0);
8138 unlock_user(n, arg2, 0);
8139 unlock_user(v, arg3, 0);
8140 }
8141 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008142 case TARGET_NR_fsetxattr:
8143 {
8144 void *n, *v = 0;
8145 if (arg3) {
8146 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8147 if (!v) {
8148 ret = -TARGET_EFAULT;
8149 break;
8150 }
8151 }
8152 n = lock_user_string(arg2);
8153 if (n) {
8154 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8155 } else {
8156 ret = -TARGET_EFAULT;
8157 }
8158 unlock_user(n, arg2, 0);
8159 unlock_user(v, arg3, 0);
8160 }
8161 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008162 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008163 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008164 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008165 void *p, *n, *v = 0;
8166 if (arg3) {
8167 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8168 if (!v) {
8169 ret = -TARGET_EFAULT;
8170 break;
8171 }
8172 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008173 p = lock_user_string(arg1);
8174 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008175 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008176 if (num == TARGET_NR_getxattr) {
8177 ret = get_errno(getxattr(p, n, v, arg4));
8178 } else {
8179 ret = get_errno(lgetxattr(p, n, v, arg4));
8180 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008181 } else {
8182 ret = -TARGET_EFAULT;
8183 }
8184 unlock_user(p, arg1, 0);
8185 unlock_user(n, arg2, 0);
8186 unlock_user(v, arg3, arg4);
8187 }
8188 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008189 case TARGET_NR_fgetxattr:
8190 {
8191 void *n, *v = 0;
8192 if (arg3) {
8193 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8194 if (!v) {
8195 ret = -TARGET_EFAULT;
8196 break;
8197 }
8198 }
8199 n = lock_user_string(arg2);
8200 if (n) {
8201 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8202 } else {
8203 ret = -TARGET_EFAULT;
8204 }
8205 unlock_user(n, arg2, 0);
8206 unlock_user(v, arg3, arg4);
8207 }
8208 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008209 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008210 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008211 {
8212 void *p, *n;
8213 p = lock_user_string(arg1);
8214 n = lock_user_string(arg2);
8215 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008216 if (num == TARGET_NR_removexattr) {
8217 ret = get_errno(removexattr(p, n));
8218 } else {
8219 ret = get_errno(lremovexattr(p, n));
8220 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008221 } else {
8222 ret = -TARGET_EFAULT;
8223 }
8224 unlock_user(p, arg1, 0);
8225 unlock_user(n, arg2, 0);
8226 }
8227 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008228 case TARGET_NR_fremovexattr:
8229 {
8230 void *n;
8231 n = lock_user_string(arg2);
8232 if (n) {
8233 ret = get_errno(fremovexattr(arg1, n));
8234 } else {
8235 ret = -TARGET_EFAULT;
8236 }
8237 unlock_user(n, arg2, 0);
8238 }
8239 break;
bellardebc05482003-09-30 21:08:41 +00008240#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008241#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008242#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008243 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008244#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008245 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8246 ret = 0;
8247 break;
edgar_iglef967792009-01-07 14:19:38 +00008248#elif defined(TARGET_CRIS)
8249 if (arg1 & 0xff)
8250 ret = -TARGET_EINVAL;
8251 else {
8252 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8253 ret = 0;
8254 }
8255 break;
bellard8d18e892007-11-14 15:18:40 +00008256#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8257 ret = do_set_thread_area(cpu_env, arg1);
8258 break;
ths6f5b89a2007-03-02 20:48:00 +00008259#else
8260 goto unimplemented_nowarn;
8261#endif
8262#endif
8263#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008264 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008265#if defined(TARGET_I386) && defined(TARGET_ABI32)
8266 ret = do_get_thread_area(cpu_env, arg1);
8267#else
bellard5cd43932003-03-29 16:54:36 +00008268 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008269#endif
bellard8d18e892007-11-14 15:18:40 +00008270#endif
bellard48dc41e2006-06-21 18:15:50 +00008271#ifdef TARGET_NR_getdomainname
8272 case TARGET_NR_getdomainname:
8273 goto unimplemented_nowarn;
8274#endif
ths6f5b89a2007-03-02 20:48:00 +00008275
thsb5906f92007-03-19 13:32:45 +00008276#ifdef TARGET_NR_clock_gettime
8277 case TARGET_NR_clock_gettime:
8278 {
8279 struct timespec ts;
8280 ret = get_errno(clock_gettime(arg1, &ts));
8281 if (!is_error(ret)) {
8282 host_to_target_timespec(arg2, &ts);
8283 }
8284 break;
8285 }
8286#endif
8287#ifdef TARGET_NR_clock_getres
8288 case TARGET_NR_clock_getres:
8289 {
8290 struct timespec ts;
8291 ret = get_errno(clock_getres(arg1, &ts));
8292 if (!is_error(ret)) {
8293 host_to_target_timespec(arg2, &ts);
8294 }
8295 break;
8296 }
8297#endif
pbrook63d76512008-05-29 13:43:29 +00008298#ifdef TARGET_NR_clock_nanosleep
8299 case TARGET_NR_clock_nanosleep:
8300 {
8301 struct timespec ts;
8302 target_to_host_timespec(&ts, arg3);
8303 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8304 if (arg4)
8305 host_to_target_timespec(arg4, &ts);
8306 break;
8307 }
8308#endif
thsb5906f92007-03-19 13:32:45 +00008309
ths6f5b89a2007-03-02 20:48:00 +00008310#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8311 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008312 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8313 break;
ths6f5b89a2007-03-02 20:48:00 +00008314#endif
8315
ths3ae43202007-09-16 21:39:48 +00008316#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008317 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008318 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008319 break;
8320#endif
8321
ths3ae43202007-09-16 21:39:48 +00008322#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008323 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008324 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8325 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008326 break;
8327#endif
8328
ths4f2b1fe2007-06-21 21:57:12 +00008329#ifdef TARGET_NR_set_robust_list
8330 case TARGET_NR_set_robust_list:
8331 goto unimplemented_nowarn;
8332#endif
8333
ths9007f0e2007-09-25 17:50:37 +00008334#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8335 case TARGET_NR_utimensat:
8336 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008337 struct timespec *tsp, ts[2];
8338 if (!arg3) {
8339 tsp = NULL;
8340 } else {
8341 target_to_host_timespec(ts, arg3);
8342 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8343 tsp = ts;
8344 }
ths9007f0e2007-09-25 17:50:37 +00008345 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008346 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008347 else {
bellard579a97f2007-11-11 14:26:47 +00008348 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008349 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008350 goto fail;
8351 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008352 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008353 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008354 }
8355 }
8356 break;
8357#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02008358#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00008359 case TARGET_NR_futex:
8360 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8361 break;
8362#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008363#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008364 case TARGET_NR_inotify_init:
8365 ret = get_errno(sys_inotify_init());
8366 break;
8367#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008368#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008369#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8370 case TARGET_NR_inotify_init1:
8371 ret = get_errno(sys_inotify_init1(arg1));
8372 break;
8373#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008374#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008375#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008376 case TARGET_NR_inotify_add_watch:
8377 p = lock_user_string(arg2);
8378 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8379 unlock_user(p, arg2, 0);
8380 break;
8381#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008382#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008383 case TARGET_NR_inotify_rm_watch:
8384 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8385 break;
8386#endif
ths9007f0e2007-09-25 17:50:37 +00008387
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008388#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008389 case TARGET_NR_mq_open:
8390 {
8391 struct mq_attr posix_mq_attr;
8392
8393 p = lock_user_string(arg1 - 1);
8394 if (arg4 != 0)
8395 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8396 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8397 unlock_user (p, arg1, 0);
8398 }
8399 break;
8400
8401 case TARGET_NR_mq_unlink:
8402 p = lock_user_string(arg1 - 1);
8403 ret = get_errno(mq_unlink(p));
8404 unlock_user (p, arg1, 0);
8405 break;
8406
8407 case TARGET_NR_mq_timedsend:
8408 {
8409 struct timespec ts;
8410
8411 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8412 if (arg5 != 0) {
8413 target_to_host_timespec(&ts, arg5);
8414 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8415 host_to_target_timespec(arg5, &ts);
8416 }
8417 else
8418 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8419 unlock_user (p, arg2, arg3);
8420 }
8421 break;
8422
8423 case TARGET_NR_mq_timedreceive:
8424 {
8425 struct timespec ts;
8426 unsigned int prio;
8427
8428 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8429 if (arg5 != 0) {
8430 target_to_host_timespec(&ts, arg5);
8431 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8432 host_to_target_timespec(arg5, &ts);
8433 }
8434 else
8435 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8436 unlock_user (p, arg2, arg3);
8437 if (arg4 != 0)
8438 put_user_u32(prio, arg4);
8439 }
8440 break;
8441
8442 /* Not implemented for now... */
8443/* case TARGET_NR_mq_notify: */
8444/* break; */
8445
8446 case TARGET_NR_mq_getsetattr:
8447 {
8448 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8449 ret = 0;
8450 if (arg3 != 0) {
8451 ret = mq_getattr(arg1, &posix_mq_attr_out);
8452 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8453 }
8454 if (arg2 != 0) {
8455 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8456 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8457 }
8458
8459 }
8460 break;
8461#endif
8462
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308463#ifdef CONFIG_SPLICE
8464#ifdef TARGET_NR_tee
8465 case TARGET_NR_tee:
8466 {
8467 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8468 }
8469 break;
8470#endif
8471#ifdef TARGET_NR_splice
8472 case TARGET_NR_splice:
8473 {
8474 loff_t loff_in, loff_out;
8475 loff_t *ploff_in = NULL, *ploff_out = NULL;
8476 if(arg2) {
8477 get_user_u64(loff_in, arg2);
8478 ploff_in = &loff_in;
8479 }
8480 if(arg4) {
8481 get_user_u64(loff_out, arg2);
8482 ploff_out = &loff_out;
8483 }
8484 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8485 }
8486 break;
8487#endif
8488#ifdef TARGET_NR_vmsplice
8489 case TARGET_NR_vmsplice:
8490 {
8491 int count = arg3;
8492 struct iovec *vec;
8493
8494 vec = alloca(count * sizeof(struct iovec));
8495 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
8496 goto efault;
8497 ret = get_errno(vmsplice(arg1, vec, count, arg4));
8498 unlock_iovec(vec, arg2, count, 0);
8499 }
8500 break;
8501#endif
8502#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008503#ifdef CONFIG_EVENTFD
8504#if defined(TARGET_NR_eventfd)
8505 case TARGET_NR_eventfd:
8506 ret = get_errno(eventfd(arg1, 0));
8507 break;
8508#endif
8509#if defined(TARGET_NR_eventfd2)
8510 case TARGET_NR_eventfd2:
8511 ret = get_errno(eventfd(arg1, arg2));
8512 break;
8513#endif
8514#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008515#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8516 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008517#if TARGET_ABI_BITS == 32
8518 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8519 target_offset64(arg5, arg6)));
8520#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008521 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008522#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008523 break;
8524#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008525#if defined(CONFIG_SYNC_FILE_RANGE)
8526#if defined(TARGET_NR_sync_file_range)
8527 case TARGET_NR_sync_file_range:
8528#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008529#if defined(TARGET_MIPS)
8530 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8531 target_offset64(arg5, arg6), arg7));
8532#else
Peter Maydellc727f472011-01-06 11:05:10 +00008533 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8534 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008535#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008536#else
8537 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8538#endif
8539 break;
8540#endif
8541#if defined(TARGET_NR_sync_file_range2)
8542 case TARGET_NR_sync_file_range2:
8543 /* This is like sync_file_range but the arguments are reordered */
8544#if TARGET_ABI_BITS == 32
8545 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8546 target_offset64(arg5, arg6), arg2));
8547#else
8548 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8549#endif
8550 break;
8551#endif
8552#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008553#if defined(CONFIG_EPOLL)
8554#if defined(TARGET_NR_epoll_create)
8555 case TARGET_NR_epoll_create:
8556 ret = get_errno(epoll_create(arg1));
8557 break;
8558#endif
8559#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8560 case TARGET_NR_epoll_create1:
8561 ret = get_errno(epoll_create1(arg1));
8562 break;
8563#endif
8564#if defined(TARGET_NR_epoll_ctl)
8565 case TARGET_NR_epoll_ctl:
8566 {
8567 struct epoll_event ep;
8568 struct epoll_event *epp = 0;
8569 if (arg4) {
8570 struct target_epoll_event *target_ep;
8571 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8572 goto efault;
8573 }
8574 ep.events = tswap32(target_ep->events);
8575 /* The epoll_data_t union is just opaque data to the kernel,
8576 * so we transfer all 64 bits across and need not worry what
8577 * actual data type it is.
8578 */
8579 ep.data.u64 = tswap64(target_ep->data.u64);
8580 unlock_user_struct(target_ep, arg4, 0);
8581 epp = &ep;
8582 }
8583 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8584 break;
8585 }
8586#endif
8587
8588#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8589#define IMPLEMENT_EPOLL_PWAIT
8590#endif
8591#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8592#if defined(TARGET_NR_epoll_wait)
8593 case TARGET_NR_epoll_wait:
8594#endif
8595#if defined(IMPLEMENT_EPOLL_PWAIT)
8596 case TARGET_NR_epoll_pwait:
8597#endif
8598 {
8599 struct target_epoll_event *target_ep;
8600 struct epoll_event *ep;
8601 int epfd = arg1;
8602 int maxevents = arg3;
8603 int timeout = arg4;
8604
8605 target_ep = lock_user(VERIFY_WRITE, arg2,
8606 maxevents * sizeof(struct target_epoll_event), 1);
8607 if (!target_ep) {
8608 goto efault;
8609 }
8610
8611 ep = alloca(maxevents * sizeof(struct epoll_event));
8612
8613 switch (num) {
8614#if defined(IMPLEMENT_EPOLL_PWAIT)
8615 case TARGET_NR_epoll_pwait:
8616 {
8617 target_sigset_t *target_set;
8618 sigset_t _set, *set = &_set;
8619
8620 if (arg5) {
8621 target_set = lock_user(VERIFY_READ, arg5,
8622 sizeof(target_sigset_t), 1);
8623 if (!target_set) {
8624 unlock_user(target_ep, arg2, 0);
8625 goto efault;
8626 }
8627 target_to_host_sigset(set, target_set);
8628 unlock_user(target_set, arg5, 0);
8629 } else {
8630 set = NULL;
8631 }
8632
8633 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8634 break;
8635 }
8636#endif
8637#if defined(TARGET_NR_epoll_wait)
8638 case TARGET_NR_epoll_wait:
8639 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8640 break;
8641#endif
8642 default:
8643 ret = -TARGET_ENOSYS;
8644 }
8645 if (!is_error(ret)) {
8646 int i;
8647 for (i = 0; i < ret; i++) {
8648 target_ep[i].events = tswap32(ep[i].events);
8649 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8650 }
8651 }
8652 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8653 break;
8654 }
8655#endif
8656#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008657#ifdef TARGET_NR_prlimit64
8658 case TARGET_NR_prlimit64:
8659 {
8660 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8661 struct target_rlimit64 *target_rnew, *target_rold;
8662 struct host_rlimit64 rnew, rold, *rnewp = 0;
8663 if (arg3) {
8664 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8665 goto efault;
8666 }
8667 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8668 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8669 unlock_user_struct(target_rnew, arg3, 0);
8670 rnewp = &rnew;
8671 }
8672
8673 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8674 if (!is_error(ret) && arg4) {
8675 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8676 goto efault;
8677 }
8678 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8679 target_rold->rlim_max = tswap64(rold.rlim_max);
8680 unlock_user_struct(target_rold, arg4, 1);
8681 }
8682 break;
8683 }
8684#endif
bellard31e31b82003-02-18 22:55:36 +00008685 default:
8686 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008687 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008688#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 +00008689 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008690#endif
ths0da46a62007-10-20 20:23:07 +00008691 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008692 break;
8693 }
bellard579a97f2007-11-11 14:26:47 +00008694fail:
bellardc573ff62004-01-04 15:51:36 +00008695#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008696 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008697#endif
thsb92c47c2007-11-01 00:07:38 +00008698 if(do_strace)
8699 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008700 return ret;
bellard579a97f2007-11-11 14:26:47 +00008701efault:
8702 ret = -TARGET_EFAULT;
8703 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008704}