blob: 038aefe5486f8c866c00e1acbf2f50ea282c4f5d [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>
Jing Huang920394d2012-07-24 13:59:23 +000063#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020064#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020065#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000066#include <sys/gmon.h>
67#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030068#ifdef CONFIG_EVENTFD
69#include <sys/eventfd.h>
70#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000071#ifdef CONFIG_EPOLL
72#include <sys/epoll.h>
73#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070074#ifdef CONFIG_ATTR
Avi Kivity4f26f2b2011-11-09 14:44:52 +020075#include "qemu-xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070076#endif
bellard31e31b82003-02-18 22:55:36 +000077
78#define termios host_termios
79#define winsize host_winsize
80#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000081#define sgttyb host_sgttyb /* same as target */
82#define tchars host_tchars /* same as target */
83#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000084
85#include <linux/termios.h>
86#include <linux/unistd.h>
87#include <linux/utsname.h>
88#include <linux/cdrom.h>
89#include <linux/hdreg.h>
90#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000091#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000092#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030093#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000094#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000095#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000096#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020097#include <linux/fb.h>
98#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010099#include <linux/dm-ioctl.h>
pbrookd7e40362008-05-23 16:06:43 +0000100#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100101#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000102
bellard3ef693a2003-03-23 20:17:16 +0000103#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000104
Juan Quintela2f7bb872009-07-27 16:13:24 +0200105#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000106#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
107 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
108#else
109/* XXX: Hardcode the above values. */
110#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000111#endif
112
bellard72f03902003-02-18 23:33:18 +0000113//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000114
bellard1a9353d2003-03-16 20:28:50 +0000115//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000116#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
117#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000118
bellard70a194b2003-08-11 22:20:16 +0000119
bellard70a194b2003-08-11 22:20:16 +0000120#undef _syscall0
121#undef _syscall1
122#undef _syscall2
123#undef _syscall3
124#undef _syscall4
125#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000126#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000127
bellard83fcb512006-06-14 13:37:16 +0000128#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000129static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000130{ \
131 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000132}
133
bellard83fcb512006-06-14 13:37:16 +0000134#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000135static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000136{ \
137 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000138}
139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
159 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000160static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000161{ \
162 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000163}
bellard83fcb512006-06-14 13:37:16 +0000164
165
166#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
169 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000170{ \
171 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
172}
173
bellard70a194b2003-08-11 22:20:16 +0000174
bellard31e31b82003-02-18 22:55:36 +0000175#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000176#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000177#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000178#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000179#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000180#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000181#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000183#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000184#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000185#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000186#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000187#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000188#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000189#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000190#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000191#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000192#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000193#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000194#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000195#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000196#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000197#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000198#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000199#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000200#define __NR_sys_inotify_init __NR_inotify_init
201#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
202#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000203
Alexander Graf42a39fb2011-04-15 17:32:45 +0200204#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
205 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000206#define __NR__llseek __NR_lseek
207#endif
208
bellard72f03902003-02-18 23:33:18 +0000209#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000210_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000211#else
ths0da46a62007-10-20 20:23:07 +0000212/* This is a replacement for the host gettid() and must return a host
213 errno. */
bellard72f03902003-02-18 23:33:18 +0000214static int gettid(void) {
215 return -ENOSYS;
216}
217#endif
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000219#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
220_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
221#endif
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, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700264 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000265 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
266 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
267 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
268 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000269#if defined(O_DIRECT)
270 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
271#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700272#if defined(O_NOATIME)
273 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
274#endif
275#if defined(O_CLOEXEC)
276 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
277#endif
278#if defined(O_PATH)
279 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
280#endif
281 /* Don't terminate the list prematurely on 64-bit host+guest. */
282#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
283 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
284#endif
aurel323b3f24a2009-04-15 16:12:13 +0000285 { 0, 0, 0, 0 }
286};
287
288#define COPY_UTSNAME_FIELD(dest, src) \
289 do { \
290 /* __NEW_UTS_LEN doesn't include terminating null */ \
291 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
292 (dest)[__NEW_UTS_LEN] = '\0'; \
293 } while (0)
294
295static int sys_uname(struct new_utsname *buf)
296{
297 struct utsname uts_buf;
298
299 if (uname(&uts_buf) < 0)
300 return (-1);
301
302 /*
303 * Just in case these have some differences, we
304 * translate utsname to new_utsname (which is the
305 * struct linux kernel uses).
306 */
307
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200308 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000309 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
310 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
311 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
312 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
313 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
314#ifdef _GNU_SOURCE
315 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
316#endif
317 return (0);
318
319#undef COPY_UTSNAME_FIELD
320}
321
322static int sys_getcwd1(char *buf, size_t size)
323{
324 if (getcwd(buf, size) == NULL) {
325 /* getcwd() sets errno */
326 return (-1);
327 }
aurel32aaf4ad32009-04-16 14:17:14 +0000328 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000329}
330
331#ifdef CONFIG_ATFILE
332/*
333 * Host system seems to have atfile syscall stubs available. We
334 * now enable them one by one as specified by target syscall_nr.h.
335 */
336
337#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000338static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000339{
aurel32465c9f02009-04-19 08:52:17 +0000340 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000341}
342#endif
343#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000344static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000345{
aurel32465c9f02009-04-19 08:52:17 +0000346 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000347}
348#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300349#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000350static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
351 gid_t group, int flags)
352{
353 return (fchownat(dirfd, pathname, owner, group, flags));
354}
355#endif
356#ifdef __NR_fstatat64
357static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
358 int flags)
359{
360 return (fstatat(dirfd, pathname, buf, flags));
361}
362#endif
363#ifdef __NR_newfstatat
364static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
365 int flags)
366{
367 return (fstatat(dirfd, pathname, buf, flags));
368}
369#endif
370#ifdef TARGET_NR_futimesat
371static int sys_futimesat(int dirfd, const char *pathname,
372 const struct timeval times[2])
373{
374 return (futimesat(dirfd, pathname, times));
375}
376#endif
377#ifdef TARGET_NR_linkat
378static int sys_linkat(int olddirfd, const char *oldpath,
379 int newdirfd, const char *newpath, int flags)
380{
381 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
382}
383#endif
384#ifdef TARGET_NR_mkdirat
385static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
386{
387 return (mkdirat(dirfd, pathname, mode));
388}
389#endif
390#ifdef TARGET_NR_mknodat
391static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
392 dev_t dev)
393{
394 return (mknodat(dirfd, pathname, mode, dev));
395}
396#endif
397#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200398static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000399{
400 /*
401 * open(2) has extra parameter 'mode' when called with
402 * flag O_CREAT.
403 */
404 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000405 return (openat(dirfd, pathname, flags, mode));
406 }
407 return (openat(dirfd, pathname, flags));
408}
409#endif
410#ifdef TARGET_NR_readlinkat
411static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
412{
413 return (readlinkat(dirfd, pathname, buf, bufsiz));
414}
415#endif
416#ifdef TARGET_NR_renameat
417static int sys_renameat(int olddirfd, const char *oldpath,
418 int newdirfd, const char *newpath)
419{
420 return (renameat(olddirfd, oldpath, newdirfd, newpath));
421}
422#endif
423#ifdef TARGET_NR_symlinkat
424static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
425{
426 return (symlinkat(oldpath, newdirfd, newpath));
427}
428#endif
429#ifdef TARGET_NR_unlinkat
430static int sys_unlinkat(int dirfd, const char *pathname, int flags)
431{
432 return (unlinkat(dirfd, pathname, flags));
433}
434#endif
aurel323b3f24a2009-04-15 16:12:13 +0000435#else /* !CONFIG_ATFILE */
436
437/*
438 * Try direct syscalls instead
439 */
ths92a34c12007-09-24 09:27:49 +0000440#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000441_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000442#endif
ths814d7972007-09-24 09:26:51 +0000443#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000444_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000445#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300446#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000447_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
448 uid_t,owner,gid_t,group,int,flags)
449#endif
aurel329d33b762009-04-08 23:07:05 +0000450#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
451 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000452_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
453 struct stat *,buf,int,flags)
454#endif
balrogac8a6552008-09-20 02:25:39 +0000455#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
456_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
457 const struct timeval *,times)
458#endif
aurel323b3f24a2009-04-15 16:12:13 +0000459#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
460 defined(__NR_newfstatat)
461_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
462 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000463#endif
ths64f0ce42007-09-24 09:25:06 +0000464#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
465_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000466 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000467#endif
ths4472ad02007-09-24 09:22:32 +0000468#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
469_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
470#endif
ths75ac37a2007-09-24 09:23:05 +0000471#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
472_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
473 mode_t,mode,dev_t,dev)
474#endif
ths82424832007-09-24 09:21:55 +0000475#if defined(TARGET_NR_openat) && defined(__NR_openat)
476_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
477#endif
ths5e0ccb12007-09-24 09:26:10 +0000478#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
479_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
480 char *,buf,size_t,bufsize)
481#endif
ths722183f2007-09-24 09:24:37 +0000482#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
483_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
484 int,newdirfd,const char *,newpath)
485#endif
thsb51eaa82007-09-25 16:09:22 +0000486#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000487_syscall3(int,sys_symlinkat,const char *,oldpath,
488 int,newdirfd,const char *,newpath)
489#endif
ths8170f562007-09-24 09:24:11 +0000490#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
491_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
492#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300493
494#endif /* CONFIG_ATFILE */
495
496#ifdef CONFIG_UTIMENSAT
497static int sys_utimensat(int dirfd, const char *pathname,
498 const struct timespec times[2], int flags)
499{
500 if (pathname == NULL)
501 return futimens(dirfd, times);
502 else
503 return utimensat(dirfd, pathname, times, flags);
504}
505#else
ths9007f0e2007-09-25 17:50:37 +0000506#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
507_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
508 const struct timespec *,tsp,int,flags)
509#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300510#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000511
512#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000513#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000514
aurel3239b59762008-10-01 21:46:50 +0000515#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000516static int sys_inotify_init(void)
517{
518 return (inotify_init());
519}
aurel3239b59762008-10-01 21:46:50 +0000520#endif
521#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000522static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
523{
524 return (inotify_add_watch(fd, pathname, mask));
525}
aurel3239b59762008-10-01 21:46:50 +0000526#endif
527#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000528static int sys_inotify_rm_watch(int fd, int32_t wd)
529{
aurel328690e422009-04-17 13:50:32 +0000530 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000531}
aurel3239b59762008-10-01 21:46:50 +0000532#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000533#ifdef CONFIG_INOTIFY1
534#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
535static int sys_inotify_init1(int flags)
536{
537 return (inotify_init1(flags));
538}
539#endif
540#endif
aurel323b3f24a2009-04-15 16:12:13 +0000541#else
542/* Userspace can usually survive runtime without inotify */
543#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000544#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000545#undef TARGET_NR_inotify_add_watch
546#undef TARGET_NR_inotify_rm_watch
547#endif /* CONFIG_INOTIFY */
548
Mike Frysingerd8035d42011-02-07 01:05:51 -0500549#if defined(TARGET_NR_ppoll)
550#ifndef __NR_ppoll
551# define __NR_ppoll -1
552#endif
553#define __NR_sys_ppoll __NR_ppoll
554_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
555 struct timespec *, timeout, const __sigset_t *, sigmask,
556 size_t, sigsetsize)
557#endif
bellard66fb9762003-03-23 01:06:05 +0000558
Mike Frysinger055e0902011-06-03 17:01:49 -0400559#if defined(TARGET_NR_pselect6)
560#ifndef __NR_pselect6
561# define __NR_pselect6 -1
562#endif
563#define __NR_sys_pselect6 __NR_pselect6
564_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
565 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
566#endif
567
Peter Maydell163a05a2011-06-27 17:44:52 +0100568#if defined(TARGET_NR_prlimit64)
569#ifndef __NR_prlimit64
570# define __NR_prlimit64 -1
571#endif
572#define __NR_sys_prlimit64 __NR_prlimit64
573/* The glibc rlimit structure may not be that used by the underlying syscall */
574struct host_rlimit64 {
575 uint64_t rlim_cur;
576 uint64_t rlim_max;
577};
578_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
579 const struct host_rlimit64 *, new_limit,
580 struct host_rlimit64 *, old_limit)
581#endif
582
bellard66fb9762003-03-23 01:06:05 +0000583extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000584extern int flock(int, int);
585extern int setfsuid(int);
586extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000587extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000588
Riku Voipio48e515d2011-07-12 15:40:51 +0300589/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
590#ifdef TARGET_ARM
591static inline int regpairs_aligned(void *cpu_env) {
592 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
593}
594#elif defined(TARGET_MIPS)
595static inline int regpairs_aligned(void *cpu_env) { return 1; }
596#else
597static inline int regpairs_aligned(void *cpu_env) { return 0; }
598#endif
599
thsb92c47c2007-11-01 00:07:38 +0000600#define ERRNO_TABLE_SIZE 1200
601
602/* target_to_host_errno_table[] is initialized from
603 * host_to_target_errno_table[] in syscall_init(). */
604static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
605};
606
ths637947f2007-06-01 12:09:19 +0000607/*
thsfe8f0962007-07-12 10:59:21 +0000608 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000609 * minus the errnos that are not actually generic to all archs.
610 */
thsb92c47c2007-11-01 00:07:38 +0000611static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000612 [EIDRM] = TARGET_EIDRM,
613 [ECHRNG] = TARGET_ECHRNG,
614 [EL2NSYNC] = TARGET_EL2NSYNC,
615 [EL3HLT] = TARGET_EL3HLT,
616 [EL3RST] = TARGET_EL3RST,
617 [ELNRNG] = TARGET_ELNRNG,
618 [EUNATCH] = TARGET_EUNATCH,
619 [ENOCSI] = TARGET_ENOCSI,
620 [EL2HLT] = TARGET_EL2HLT,
621 [EDEADLK] = TARGET_EDEADLK,
622 [ENOLCK] = TARGET_ENOLCK,
623 [EBADE] = TARGET_EBADE,
624 [EBADR] = TARGET_EBADR,
625 [EXFULL] = TARGET_EXFULL,
626 [ENOANO] = TARGET_ENOANO,
627 [EBADRQC] = TARGET_EBADRQC,
628 [EBADSLT] = TARGET_EBADSLT,
629 [EBFONT] = TARGET_EBFONT,
630 [ENOSTR] = TARGET_ENOSTR,
631 [ENODATA] = TARGET_ENODATA,
632 [ETIME] = TARGET_ETIME,
633 [ENOSR] = TARGET_ENOSR,
634 [ENONET] = TARGET_ENONET,
635 [ENOPKG] = TARGET_ENOPKG,
636 [EREMOTE] = TARGET_EREMOTE,
637 [ENOLINK] = TARGET_ENOLINK,
638 [EADV] = TARGET_EADV,
639 [ESRMNT] = TARGET_ESRMNT,
640 [ECOMM] = TARGET_ECOMM,
641 [EPROTO] = TARGET_EPROTO,
642 [EDOTDOT] = TARGET_EDOTDOT,
643 [EMULTIHOP] = TARGET_EMULTIHOP,
644 [EBADMSG] = TARGET_EBADMSG,
645 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
646 [EOVERFLOW] = TARGET_EOVERFLOW,
647 [ENOTUNIQ] = TARGET_ENOTUNIQ,
648 [EBADFD] = TARGET_EBADFD,
649 [EREMCHG] = TARGET_EREMCHG,
650 [ELIBACC] = TARGET_ELIBACC,
651 [ELIBBAD] = TARGET_ELIBBAD,
652 [ELIBSCN] = TARGET_ELIBSCN,
653 [ELIBMAX] = TARGET_ELIBMAX,
654 [ELIBEXEC] = TARGET_ELIBEXEC,
655 [EILSEQ] = TARGET_EILSEQ,
656 [ENOSYS] = TARGET_ENOSYS,
657 [ELOOP] = TARGET_ELOOP,
658 [ERESTART] = TARGET_ERESTART,
659 [ESTRPIPE] = TARGET_ESTRPIPE,
660 [ENOTEMPTY] = TARGET_ENOTEMPTY,
661 [EUSERS] = TARGET_EUSERS,
662 [ENOTSOCK] = TARGET_ENOTSOCK,
663 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
664 [EMSGSIZE] = TARGET_EMSGSIZE,
665 [EPROTOTYPE] = TARGET_EPROTOTYPE,
666 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
667 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
668 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
669 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
670 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
671 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
672 [EADDRINUSE] = TARGET_EADDRINUSE,
673 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
674 [ENETDOWN] = TARGET_ENETDOWN,
675 [ENETUNREACH] = TARGET_ENETUNREACH,
676 [ENETRESET] = TARGET_ENETRESET,
677 [ECONNABORTED] = TARGET_ECONNABORTED,
678 [ECONNRESET] = TARGET_ECONNRESET,
679 [ENOBUFS] = TARGET_ENOBUFS,
680 [EISCONN] = TARGET_EISCONN,
681 [ENOTCONN] = TARGET_ENOTCONN,
682 [EUCLEAN] = TARGET_EUCLEAN,
683 [ENOTNAM] = TARGET_ENOTNAM,
684 [ENAVAIL] = TARGET_ENAVAIL,
685 [EISNAM] = TARGET_EISNAM,
686 [EREMOTEIO] = TARGET_EREMOTEIO,
687 [ESHUTDOWN] = TARGET_ESHUTDOWN,
688 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
689 [ETIMEDOUT] = TARGET_ETIMEDOUT,
690 [ECONNREFUSED] = TARGET_ECONNREFUSED,
691 [EHOSTDOWN] = TARGET_EHOSTDOWN,
692 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
693 [EALREADY] = TARGET_EALREADY,
694 [EINPROGRESS] = TARGET_EINPROGRESS,
695 [ESTALE] = TARGET_ESTALE,
696 [ECANCELED] = TARGET_ECANCELED,
697 [ENOMEDIUM] = TARGET_ENOMEDIUM,
698 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000699#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000700 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000701#endif
702#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000703 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000704#endif
705#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000706 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000707#endif
708#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000709 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000710#endif
711#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000712 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000713#endif
714#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000715 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000716#endif
thsb92c47c2007-11-01 00:07:38 +0000717};
ths637947f2007-06-01 12:09:19 +0000718
719static inline int host_to_target_errno(int err)
720{
721 if(host_to_target_errno_table[err])
722 return host_to_target_errno_table[err];
723 return err;
724}
725
thsb92c47c2007-11-01 00:07:38 +0000726static inline int target_to_host_errno(int err)
727{
728 if (target_to_host_errno_table[err])
729 return target_to_host_errno_table[err];
730 return err;
731}
732
blueswir1992f48a2007-10-14 16:27:31 +0000733static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000734{
735 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000736 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000737 else
738 return ret;
739}
740
blueswir1992f48a2007-10-14 16:27:31 +0000741static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000742{
blueswir1992f48a2007-10-14 16:27:31 +0000743 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000744}
745
thsb92c47c2007-11-01 00:07:38 +0000746char *target_strerror(int err)
747{
Alexander Graf962b2892011-11-21 12:04:07 +0100748 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
749 return NULL;
750 }
thsb92c47c2007-11-01 00:07:38 +0000751 return strerror(target_to_host_errno(err));
752}
753
blueswir1992f48a2007-10-14 16:27:31 +0000754static abi_ulong target_brk;
755static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000756static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000757
blueswir1992f48a2007-10-14 16:27:31 +0000758void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000759{
blueswir14c1de732007-07-07 20:45:44 +0000760 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000761 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000762}
763
vincent4d1de872011-06-14 21:56:33 +0000764//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
765#define DEBUGF_BRK(message, args...)
766
ths0da46a62007-10-20 20:23:07 +0000767/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000768abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000769{
blueswir1992f48a2007-10-14 16:27:31 +0000770 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000771 int new_alloc_size;
772
Paul Brook3a0c6c42012-02-09 19:04:27 +0000773 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000774
vincent4d1de872011-06-14 21:56:33 +0000775 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000776 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000777 return target_brk;
778 }
779 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000780 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
781 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000782 return target_brk;
783 }
bellard31e31b82003-02-18 22:55:36 +0000784
vincent4d1de872011-06-14 21:56:33 +0000785 /* If the new brk is less than the highest page reserved to the
786 * target heap allocation, set it and we're almost done... */
787 if (new_brk <= brk_page) {
788 /* Heap contents are initialized to zero, as for anonymous
789 * mapped pages. */
790 if (new_brk > target_brk) {
791 memset(g2h(target_brk), 0, new_brk - target_brk);
792 }
bellard31e31b82003-02-18 22:55:36 +0000793 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000794 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000795 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000796 }
797
Peter Maydell00faf082011-04-18 16:34:24 +0100798 /* We need to allocate more memory after the brk... Note that
799 * we don't use MAP_FIXED because that will map over the top of
800 * any existing mapping (like the one with the host libc or qemu
801 * itself); instead we treat "mapped but at wrong address" as
802 * a failure and unmap again.
803 */
vincent4d1de872011-06-14 21:56:33 +0000804 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000805 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000806 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100807 MAP_ANON|MAP_PRIVATE, 0, 0));
808
809 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200810 /* Heap contents are initialized to zero, as for anonymous
811 * mapped pages. Technically the new pages are already
812 * initialized to zero since they *are* anonymous mapped
813 * pages, however we have to take care with the contents that
814 * come from the remaining part of the previous page: it may
815 * contains garbage data due to a previous heap usage (grown
816 * then shrunken). */
817 memset(g2h(target_brk), 0, brk_page - target_brk);
818
Peter Maydell00faf082011-04-18 16:34:24 +0100819 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000820 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000821 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
822 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100823 return target_brk;
824 } else if (mapped_addr != -1) {
825 /* Mapped but at wrong address, meaning there wasn't actually
826 * enough space for this brk.
827 */
828 target_munmap(mapped_addr, new_alloc_size);
829 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000830 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000831 }
832 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000833 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100834 }
balrog7ab240a2008-04-26 12:17:34 +0000835
Richard Henderson7dd46c02010-05-03 10:07:49 -0700836#if defined(TARGET_ALPHA)
837 /* We (partially) emulate OSF/1 on Alpha, which requires we
838 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100839 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700840#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100841 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000842 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000843}
844
ths26edcf42007-12-09 02:25:24 +0000845static inline abi_long copy_from_user_fdset(fd_set *fds,
846 abi_ulong target_fds_addr,
847 int n)
bellard31e31b82003-02-18 22:55:36 +0000848{
ths26edcf42007-12-09 02:25:24 +0000849 int i, nw, j, k;
850 abi_ulong b, *target_fds;
851
852 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
853 if (!(target_fds = lock_user(VERIFY_READ,
854 target_fds_addr,
855 sizeof(abi_ulong) * nw,
856 1)))
857 return -TARGET_EFAULT;
858
859 FD_ZERO(fds);
860 k = 0;
861 for (i = 0; i < nw; i++) {
862 /* grab the abi_ulong */
863 __get_user(b, &target_fds[i]);
864 for (j = 0; j < TARGET_ABI_BITS; j++) {
865 /* check the bit inside the abi_ulong */
866 if ((b >> j) & 1)
867 FD_SET(k, fds);
868 k++;
bellard31e31b82003-02-18 22:55:36 +0000869 }
bellard31e31b82003-02-18 22:55:36 +0000870 }
ths26edcf42007-12-09 02:25:24 +0000871
872 unlock_user(target_fds, target_fds_addr, 0);
873
874 return 0;
bellard31e31b82003-02-18 22:55:36 +0000875}
876
Mike Frysinger055e0902011-06-03 17:01:49 -0400877static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
878 abi_ulong target_fds_addr,
879 int n)
880{
881 if (target_fds_addr) {
882 if (copy_from_user_fdset(fds, target_fds_addr, n))
883 return -TARGET_EFAULT;
884 *fds_ptr = fds;
885 } else {
886 *fds_ptr = NULL;
887 }
888 return 0;
889}
890
ths26edcf42007-12-09 02:25:24 +0000891static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
892 const fd_set *fds,
893 int n)
bellard31e31b82003-02-18 22:55:36 +0000894{
bellard31e31b82003-02-18 22:55:36 +0000895 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000896 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000897 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000898
ths26edcf42007-12-09 02:25:24 +0000899 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
900 if (!(target_fds = lock_user(VERIFY_WRITE,
901 target_fds_addr,
902 sizeof(abi_ulong) * nw,
903 0)))
904 return -TARGET_EFAULT;
905
906 k = 0;
907 for (i = 0; i < nw; i++) {
908 v = 0;
909 for (j = 0; j < TARGET_ABI_BITS; j++) {
910 v |= ((FD_ISSET(k, fds) != 0) << j);
911 k++;
bellard31e31b82003-02-18 22:55:36 +0000912 }
ths26edcf42007-12-09 02:25:24 +0000913 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000914 }
ths26edcf42007-12-09 02:25:24 +0000915
916 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
917
918 return 0;
bellard31e31b82003-02-18 22:55:36 +0000919}
920
bellardc596ed12003-07-13 17:32:31 +0000921#if defined(__alpha__)
922#define HOST_HZ 1024
923#else
924#define HOST_HZ 100
925#endif
926
blueswir1992f48a2007-10-14 16:27:31 +0000927static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000928{
929#if HOST_HZ == TARGET_HZ
930 return ticks;
931#else
932 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
933#endif
934}
935
bellard579a97f2007-11-11 14:26:47 +0000936static inline abi_long host_to_target_rusage(abi_ulong target_addr,
937 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000938{
pbrook53a59602006-03-25 19:31:22 +0000939 struct target_rusage *target_rusage;
940
bellard579a97f2007-11-11 14:26:47 +0000941 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
942 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200943 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
944 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
945 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
946 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
947 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
948 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
949 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
950 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
951 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
952 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
953 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
954 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
955 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
956 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
957 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
958 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
959 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
960 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000961 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000962
963 return 0;
bellardb4091862003-05-16 15:39:34 +0000964}
965
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200966static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900967{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200968 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300969 rlim_t result;
970
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200971 target_rlim_swap = tswapal(target_rlim);
972 if (target_rlim_swap == TARGET_RLIM_INFINITY)
973 return RLIM_INFINITY;
974
975 result = target_rlim_swap;
976 if (target_rlim_swap != (rlim_t)result)
977 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300978
979 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900980}
981
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200982static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900983{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200984 abi_ulong target_rlim_swap;
985 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300986
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200987 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300988 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900989 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300990 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200991 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300992
993 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900994}
995
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300996static inline int target_to_host_resource(int code)
997{
998 switch (code) {
999 case TARGET_RLIMIT_AS:
1000 return RLIMIT_AS;
1001 case TARGET_RLIMIT_CORE:
1002 return RLIMIT_CORE;
1003 case TARGET_RLIMIT_CPU:
1004 return RLIMIT_CPU;
1005 case TARGET_RLIMIT_DATA:
1006 return RLIMIT_DATA;
1007 case TARGET_RLIMIT_FSIZE:
1008 return RLIMIT_FSIZE;
1009 case TARGET_RLIMIT_LOCKS:
1010 return RLIMIT_LOCKS;
1011 case TARGET_RLIMIT_MEMLOCK:
1012 return RLIMIT_MEMLOCK;
1013 case TARGET_RLIMIT_MSGQUEUE:
1014 return RLIMIT_MSGQUEUE;
1015 case TARGET_RLIMIT_NICE:
1016 return RLIMIT_NICE;
1017 case TARGET_RLIMIT_NOFILE:
1018 return RLIMIT_NOFILE;
1019 case TARGET_RLIMIT_NPROC:
1020 return RLIMIT_NPROC;
1021 case TARGET_RLIMIT_RSS:
1022 return RLIMIT_RSS;
1023 case TARGET_RLIMIT_RTPRIO:
1024 return RLIMIT_RTPRIO;
1025 case TARGET_RLIMIT_SIGPENDING:
1026 return RLIMIT_SIGPENDING;
1027 case TARGET_RLIMIT_STACK:
1028 return RLIMIT_STACK;
1029 default:
1030 return code;
1031 }
1032}
1033
ths788f5ec2007-12-09 02:37:05 +00001034static inline abi_long copy_from_user_timeval(struct timeval *tv,
1035 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001036{
pbrook53a59602006-03-25 19:31:22 +00001037 struct target_timeval *target_tv;
1038
ths788f5ec2007-12-09 02:37:05 +00001039 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001040 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001041
1042 __get_user(tv->tv_sec, &target_tv->tv_sec);
1043 __get_user(tv->tv_usec, &target_tv->tv_usec);
1044
1045 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001046
1047 return 0;
bellard31e31b82003-02-18 22:55:36 +00001048}
1049
ths788f5ec2007-12-09 02:37:05 +00001050static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1051 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001052{
pbrook53a59602006-03-25 19:31:22 +00001053 struct target_timeval *target_tv;
1054
ths788f5ec2007-12-09 02:37:05 +00001055 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001056 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001057
1058 __put_user(tv->tv_sec, &target_tv->tv_sec);
1059 __put_user(tv->tv_usec, &target_tv->tv_usec);
1060
1061 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001062
1063 return 0;
bellard31e31b82003-02-18 22:55:36 +00001064}
1065
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001066#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1067#include <mqueue.h>
1068
aurel3224e10032009-04-15 16:11:43 +00001069static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1070 abi_ulong target_mq_attr_addr)
1071{
1072 struct target_mq_attr *target_mq_attr;
1073
1074 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1075 target_mq_attr_addr, 1))
1076 return -TARGET_EFAULT;
1077
1078 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1079 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1080 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1081 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1082
1083 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1084
1085 return 0;
1086}
1087
1088static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1089 const struct mq_attr *attr)
1090{
1091 struct target_mq_attr *target_mq_attr;
1092
1093 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1094 target_mq_attr_addr, 0))
1095 return -TARGET_EFAULT;
1096
1097 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1098 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1099 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1100 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1101
1102 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1103
1104 return 0;
1105}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001106#endif
bellard31e31b82003-02-18 22:55:36 +00001107
Mike Frysinger055e0902011-06-03 17:01:49 -04001108#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001109/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001110static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001111 abi_ulong rfd_addr, abi_ulong wfd_addr,
1112 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001113{
1114 fd_set rfds, wfds, efds;
1115 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1116 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001117 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001118
Mike Frysinger055e0902011-06-03 17:01:49 -04001119 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1120 if (ret) {
1121 return ret;
pbrook53a59602006-03-25 19:31:22 +00001122 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001123 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1124 if (ret) {
1125 return ret;
pbrook53a59602006-03-25 19:31:22 +00001126 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001127 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1128 if (ret) {
1129 return ret;
pbrook53a59602006-03-25 19:31:22 +00001130 }
ths3b46e622007-09-17 08:09:54 +00001131
ths26edcf42007-12-09 02:25:24 +00001132 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001133 if (copy_from_user_timeval(&tv, target_tv_addr))
1134 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001135 tv_ptr = &tv;
1136 } else {
1137 tv_ptr = NULL;
1138 }
ths26edcf42007-12-09 02:25:24 +00001139
bellard31e31b82003-02-18 22:55:36 +00001140 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001141
ths26edcf42007-12-09 02:25:24 +00001142 if (!is_error(ret)) {
1143 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1144 return -TARGET_EFAULT;
1145 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1146 return -TARGET_EFAULT;
1147 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1148 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001149
ths788f5ec2007-12-09 02:37:05 +00001150 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1151 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001152 }
bellard579a97f2007-11-11 14:26:47 +00001153
bellard31e31b82003-02-18 22:55:36 +00001154 return ret;
1155}
Mike Frysinger055e0902011-06-03 17:01:49 -04001156#endif
bellard31e31b82003-02-18 22:55:36 +00001157
Riku Voipio099d6b02009-05-05 12:10:04 +03001158static abi_long do_pipe2(int host_pipe[], int flags)
1159{
1160#ifdef CONFIG_PIPE2
1161 return pipe2(host_pipe, flags);
1162#else
1163 return -ENOSYS;
1164#endif
1165}
1166
Richard Hendersonfb41a662010-05-03 10:07:52 -07001167static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1168 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001169{
1170 int host_pipe[2];
1171 abi_long ret;
1172 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1173
1174 if (is_error(ret))
1175 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001176
1177 /* Several targets have special calling conventions for the original
1178 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1179 if (!is_pipe2) {
1180#if defined(TARGET_ALPHA)
1181 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1182 return host_pipe[0];
1183#elif defined(TARGET_MIPS)
1184 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1185 return host_pipe[0];
1186#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001187 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001188 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001189#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001190 }
1191
Riku Voipio099d6b02009-05-05 12:10:04 +03001192 if (put_user_s32(host_pipe[0], pipedes)
1193 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1194 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001195 return get_errno(ret);
1196}
1197
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001198static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1199 abi_ulong target_addr,
1200 socklen_t len)
1201{
1202 struct target_ip_mreqn *target_smreqn;
1203
1204 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1205 if (!target_smreqn)
1206 return -TARGET_EFAULT;
1207 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1208 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1209 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001210 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001211 unlock_user(target_smreqn, target_addr, 0);
1212
1213 return 0;
1214}
1215
bellard579a97f2007-11-11 14:26:47 +00001216static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1217 abi_ulong target_addr,
1218 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001219{
aurel32607175e2009-04-15 16:11:59 +00001220 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1221 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001222 struct target_sockaddr *target_saddr;
1223
bellard579a97f2007-11-11 14:26:47 +00001224 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1225 if (!target_saddr)
1226 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001227
1228 sa_family = tswap16(target_saddr->sa_family);
1229
1230 /* Oops. The caller might send a incomplete sun_path; sun_path
1231 * must be terminated by \0 (see the manual page), but
1232 * unfortunately it is quite common to specify sockaddr_un
1233 * length as "strlen(x->sun_path)" while it should be
1234 * "strlen(...) + 1". We'll fix that here if needed.
1235 * Linux kernel has a similar feature.
1236 */
1237
1238 if (sa_family == AF_UNIX) {
1239 if (len < unix_maxlen && len > 0) {
1240 char *cp = (char*)target_saddr;
1241
1242 if ( cp[len-1] && !cp[len] )
1243 len++;
1244 }
1245 if (len > unix_maxlen)
1246 len = unix_maxlen;
1247 }
1248
pbrook53a59602006-03-25 19:31:22 +00001249 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001250 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001251 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001252
1253 return 0;
bellard7854b052003-03-29 17:22:23 +00001254}
1255
bellard579a97f2007-11-11 14:26:47 +00001256static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1257 struct sockaddr *addr,
1258 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001259{
pbrook53a59602006-03-25 19:31:22 +00001260 struct target_sockaddr *target_saddr;
1261
bellard579a97f2007-11-11 14:26:47 +00001262 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1263 if (!target_saddr)
1264 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001265 memcpy(target_saddr, addr, len);
1266 target_saddr->sa_family = tswap16(addr->sa_family);
1267 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001268
1269 return 0;
bellard7854b052003-03-29 17:22:23 +00001270}
1271
bellard5a4a8982007-11-11 17:39:18 +00001272static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1273 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001274{
1275 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001276 abi_long msg_controllen;
1277 abi_ulong target_cmsg_addr;
1278 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001279 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001280
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001281 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001282 if (msg_controllen < sizeof (struct target_cmsghdr))
1283 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001284 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001285 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1286 if (!target_cmsg)
1287 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001288
1289 while (cmsg && target_cmsg) {
1290 void *data = CMSG_DATA(cmsg);
1291 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1292
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001293 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001294 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1295
1296 space += CMSG_SPACE(len);
1297 if (space > msgh->msg_controllen) {
1298 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001299 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001300 break;
1301 }
1302
1303 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1304 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1305 cmsg->cmsg_len = CMSG_LEN(len);
1306
bellard3532fa72006-06-24 15:06:03 +00001307 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001308 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1309 memcpy(data, target_data, len);
1310 } else {
1311 int *fd = (int *)data;
1312 int *target_fd = (int *)target_data;
1313 int i, numfds = len / sizeof(int);
1314
1315 for (i = 0; i < numfds; i++)
1316 fd[i] = tswap32(target_fd[i]);
1317 }
1318
1319 cmsg = CMSG_NXTHDR(msgh, cmsg);
1320 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1321 }
bellard5a4a8982007-11-11 17:39:18 +00001322 unlock_user(target_cmsg, target_cmsg_addr, 0);
1323 the_end:
bellard7854b052003-03-29 17:22:23 +00001324 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001325 return 0;
bellard7854b052003-03-29 17:22:23 +00001326}
1327
bellard5a4a8982007-11-11 17:39:18 +00001328static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1329 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001330{
1331 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001332 abi_long msg_controllen;
1333 abi_ulong target_cmsg_addr;
1334 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001335 socklen_t space = 0;
1336
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001337 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001338 if (msg_controllen < sizeof (struct target_cmsghdr))
1339 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001340 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001341 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1342 if (!target_cmsg)
1343 return -TARGET_EFAULT;
1344
bellard7854b052003-03-29 17:22:23 +00001345 while (cmsg && target_cmsg) {
1346 void *data = CMSG_DATA(cmsg);
1347 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1348
1349 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1350
1351 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001352 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001353 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001354 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001355 break;
1356 }
1357
1358 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1359 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001360 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001361
Jing Huangaebf5bc2012-07-24 14:01:42 +00001362 if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1363 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001364 int *fd = (int *)data;
1365 int *target_fd = (int *)target_data;
1366 int i, numfds = len / sizeof(int);
1367
1368 for (i = 0; i < numfds; i++)
1369 target_fd[i] = tswap32(fd[i]);
Jing Huangaebf5bc2012-07-24 14:01:42 +00001370 } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1371 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1372 (len == sizeof(struct timeval))) {
1373 /* copy struct timeval to target */
1374 struct timeval *tv = (struct timeval *)data;
1375 struct target_timeval *target_tv =
1376 (struct target_timeval *)target_data;
1377
1378 target_tv->tv_sec = tswapal(tv->tv_sec);
1379 target_tv->tv_usec = tswapal(tv->tv_usec);
1380 } else {
1381 gemu_log("Unsupported ancillary data: %d/%d\n",
1382 cmsg->cmsg_level, cmsg->cmsg_type);
1383 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001384 }
1385
1386 cmsg = CMSG_NXTHDR(msgh, cmsg);
1387 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1388 }
bellard5a4a8982007-11-11 17:39:18 +00001389 unlock_user(target_cmsg, target_cmsg_addr, space);
1390 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001391 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001392 return 0;
bellard7854b052003-03-29 17:22:23 +00001393}
1394
ths0da46a62007-10-20 20:23:07 +00001395/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001396static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001397 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001398{
blueswir1992f48a2007-10-14 16:27:31 +00001399 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001400 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001401 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001402 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001403
bellard8853f862004-02-22 14:57:26 +00001404 switch(level) {
1405 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001406 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001407 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001408 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001409
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 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1413 break;
1414 case SOL_IP:
1415 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001416 case IP_TOS:
1417 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001418 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001419 case IP_ROUTER_ALERT:
1420 case IP_RECVOPTS:
1421 case IP_RETOPTS:
1422 case IP_PKTINFO:
1423 case IP_MTU_DISCOVER:
1424 case IP_RECVERR:
1425 case IP_RECVTOS:
1426#ifdef IP_FREEBIND
1427 case IP_FREEBIND:
1428#endif
1429 case IP_MULTICAST_TTL:
1430 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001431 val = 0;
1432 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001433 if (get_user_u32(val, optval_addr))
1434 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001435 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001436 if (get_user_u8(val, optval_addr))
1437 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001438 }
1439 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1440 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001441 case IP_ADD_MEMBERSHIP:
1442 case IP_DROP_MEMBERSHIP:
1443 if (optlen < sizeof (struct target_ip_mreq) ||
1444 optlen > sizeof (struct target_ip_mreqn))
1445 return -TARGET_EINVAL;
1446
1447 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1448 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1449 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1450 break;
1451
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001452 case IP_BLOCK_SOURCE:
1453 case IP_UNBLOCK_SOURCE:
1454 case IP_ADD_SOURCE_MEMBERSHIP:
1455 case IP_DROP_SOURCE_MEMBERSHIP:
1456 if (optlen != sizeof (struct target_ip_mreq_source))
1457 return -TARGET_EINVAL;
1458
1459 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1460 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1461 unlock_user (ip_mreq_source, optval_addr, 0);
1462 break;
1463
bellard8853f862004-02-22 14:57:26 +00001464 default:
1465 goto unimplemented;
1466 }
1467 break;
Jing Huang920394d2012-07-24 13:59:23 +00001468 case SOL_RAW:
1469 switch (optname) {
1470 case ICMP_FILTER:
1471 /* struct icmp_filter takes an u32 value */
1472 if (optlen < sizeof(uint32_t)) {
1473 return -TARGET_EINVAL;
1474 }
1475
1476 if (get_user_u32(val, optval_addr)) {
1477 return -TARGET_EFAULT;
1478 }
1479 ret = get_errno(setsockopt(sockfd, level, optname,
1480 &val, sizeof(val)));
1481 break;
1482
1483 default:
1484 goto unimplemented;
1485 }
1486 break;
bellard3532fa72006-06-24 15:06:03 +00001487 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001488 switch (optname) {
1489 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001490 case TARGET_SO_DEBUG:
1491 optname = SO_DEBUG;
1492 break;
1493 case TARGET_SO_REUSEADDR:
1494 optname = SO_REUSEADDR;
1495 break;
1496 case TARGET_SO_TYPE:
1497 optname = SO_TYPE;
1498 break;
1499 case TARGET_SO_ERROR:
1500 optname = SO_ERROR;
1501 break;
1502 case TARGET_SO_DONTROUTE:
1503 optname = SO_DONTROUTE;
1504 break;
1505 case TARGET_SO_BROADCAST:
1506 optname = SO_BROADCAST;
1507 break;
1508 case TARGET_SO_SNDBUF:
1509 optname = SO_SNDBUF;
1510 break;
1511 case TARGET_SO_RCVBUF:
1512 optname = SO_RCVBUF;
1513 break;
1514 case TARGET_SO_KEEPALIVE:
1515 optname = SO_KEEPALIVE;
1516 break;
1517 case TARGET_SO_OOBINLINE:
1518 optname = SO_OOBINLINE;
1519 break;
1520 case TARGET_SO_NO_CHECK:
1521 optname = SO_NO_CHECK;
1522 break;
1523 case TARGET_SO_PRIORITY:
1524 optname = SO_PRIORITY;
1525 break;
bellard5e83e8e2005-03-01 22:32:06 +00001526#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001527 case TARGET_SO_BSDCOMPAT:
1528 optname = SO_BSDCOMPAT;
1529 break;
bellard5e83e8e2005-03-01 22:32:06 +00001530#endif
bellard3532fa72006-06-24 15:06:03 +00001531 case TARGET_SO_PASSCRED:
1532 optname = SO_PASSCRED;
1533 break;
1534 case TARGET_SO_TIMESTAMP:
1535 optname = SO_TIMESTAMP;
1536 break;
1537 case TARGET_SO_RCVLOWAT:
1538 optname = SO_RCVLOWAT;
1539 break;
1540 case TARGET_SO_RCVTIMEO:
1541 optname = SO_RCVTIMEO;
1542 break;
1543 case TARGET_SO_SNDTIMEO:
1544 optname = SO_SNDTIMEO;
1545 break;
bellard8853f862004-02-22 14:57:26 +00001546 break;
1547 default:
1548 goto unimplemented;
1549 }
bellard3532fa72006-06-24 15:06:03 +00001550 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001551 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001552
bellard2f619692007-11-16 10:46:05 +00001553 if (get_user_u32(val, optval_addr))
1554 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001555 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001556 break;
bellard7854b052003-03-29 17:22:23 +00001557 default:
bellard8853f862004-02-22 14:57:26 +00001558 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001559 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001560 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001561 }
bellard8853f862004-02-22 14:57:26 +00001562 return ret;
bellard7854b052003-03-29 17:22:23 +00001563}
1564
ths0da46a62007-10-20 20:23:07 +00001565/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001566static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001567 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001568{
blueswir1992f48a2007-10-14 16:27:31 +00001569 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001570 int len, val;
1571 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001572
1573 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001574 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001575 level = SOL_SOCKET;
1576 switch (optname) {
1577 /* These don't just return a single integer */
1578 case TARGET_SO_LINGER:
1579 case TARGET_SO_RCVTIMEO:
1580 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001581 case TARGET_SO_PEERNAME:
1582 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001583 case TARGET_SO_PEERCRED: {
1584 struct ucred cr;
1585 socklen_t crlen;
1586 struct target_ucred *tcr;
1587
1588 if (get_user_u32(len, optlen)) {
1589 return -TARGET_EFAULT;
1590 }
1591 if (len < 0) {
1592 return -TARGET_EINVAL;
1593 }
1594
1595 crlen = sizeof(cr);
1596 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1597 &cr, &crlen));
1598 if (ret < 0) {
1599 return ret;
1600 }
1601 if (len > crlen) {
1602 len = crlen;
1603 }
1604 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1605 return -TARGET_EFAULT;
1606 }
1607 __put_user(cr.pid, &tcr->pid);
1608 __put_user(cr.uid, &tcr->uid);
1609 __put_user(cr.gid, &tcr->gid);
1610 unlock_user_struct(tcr, optval_addr, 1);
1611 if (put_user_u32(len, optlen)) {
1612 return -TARGET_EFAULT;
1613 }
1614 break;
1615 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001616 /* Options with 'int' argument. */
1617 case TARGET_SO_DEBUG:
1618 optname = SO_DEBUG;
1619 goto int_case;
1620 case TARGET_SO_REUSEADDR:
1621 optname = SO_REUSEADDR;
1622 goto int_case;
1623 case TARGET_SO_TYPE:
1624 optname = SO_TYPE;
1625 goto int_case;
1626 case TARGET_SO_ERROR:
1627 optname = SO_ERROR;
1628 goto int_case;
1629 case TARGET_SO_DONTROUTE:
1630 optname = SO_DONTROUTE;
1631 goto int_case;
1632 case TARGET_SO_BROADCAST:
1633 optname = SO_BROADCAST;
1634 goto int_case;
1635 case TARGET_SO_SNDBUF:
1636 optname = SO_SNDBUF;
1637 goto int_case;
1638 case TARGET_SO_RCVBUF:
1639 optname = SO_RCVBUF;
1640 goto int_case;
1641 case TARGET_SO_KEEPALIVE:
1642 optname = SO_KEEPALIVE;
1643 goto int_case;
1644 case TARGET_SO_OOBINLINE:
1645 optname = SO_OOBINLINE;
1646 goto int_case;
1647 case TARGET_SO_NO_CHECK:
1648 optname = SO_NO_CHECK;
1649 goto int_case;
1650 case TARGET_SO_PRIORITY:
1651 optname = SO_PRIORITY;
1652 goto int_case;
1653#ifdef SO_BSDCOMPAT
1654 case TARGET_SO_BSDCOMPAT:
1655 optname = SO_BSDCOMPAT;
1656 goto int_case;
1657#endif
1658 case TARGET_SO_PASSCRED:
1659 optname = SO_PASSCRED;
1660 goto int_case;
1661 case TARGET_SO_TIMESTAMP:
1662 optname = SO_TIMESTAMP;
1663 goto int_case;
1664 case TARGET_SO_RCVLOWAT:
1665 optname = SO_RCVLOWAT;
1666 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001667 default:
bellard2efbe912005-07-23 15:10:20 +00001668 goto int_case;
1669 }
1670 break;
1671 case SOL_TCP:
1672 /* TCP options all take an 'int' value. */
1673 int_case:
bellard2f619692007-11-16 10:46:05 +00001674 if (get_user_u32(len, optlen))
1675 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001676 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001677 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001678 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001679 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1680 if (ret < 0)
1681 return ret;
bellard2efbe912005-07-23 15:10:20 +00001682 if (len > lv)
1683 len = lv;
bellard2f619692007-11-16 10:46:05 +00001684 if (len == 4) {
1685 if (put_user_u32(val, optval_addr))
1686 return -TARGET_EFAULT;
1687 } else {
1688 if (put_user_u8(val, optval_addr))
1689 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001690 }
bellard2f619692007-11-16 10:46:05 +00001691 if (put_user_u32(len, optlen))
1692 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001693 break;
1694 case SOL_IP:
1695 switch(optname) {
1696 case IP_TOS:
1697 case IP_TTL:
1698 case IP_HDRINCL:
1699 case IP_ROUTER_ALERT:
1700 case IP_RECVOPTS:
1701 case IP_RETOPTS:
1702 case IP_PKTINFO:
1703 case IP_MTU_DISCOVER:
1704 case IP_RECVERR:
1705 case IP_RECVTOS:
1706#ifdef IP_FREEBIND
1707 case IP_FREEBIND:
1708#endif
1709 case IP_MULTICAST_TTL:
1710 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001711 if (get_user_u32(len, optlen))
1712 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001713 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001714 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001715 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001716 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1717 if (ret < 0)
1718 return ret;
bellard2efbe912005-07-23 15:10:20 +00001719 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001720 len = 1;
bellard2f619692007-11-16 10:46:05 +00001721 if (put_user_u32(len, optlen)
1722 || put_user_u8(val, optval_addr))
1723 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001724 } else {
bellard2efbe912005-07-23 15:10:20 +00001725 if (len > sizeof(int))
1726 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001727 if (put_user_u32(len, optlen)
1728 || put_user_u32(val, optval_addr))
1729 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001730 }
bellard8853f862004-02-22 14:57:26 +00001731 break;
bellard2efbe912005-07-23 15:10:20 +00001732 default:
thsc02f4992007-12-18 02:39:59 +00001733 ret = -TARGET_ENOPROTOOPT;
1734 break;
bellard8853f862004-02-22 14:57:26 +00001735 }
1736 break;
1737 default:
1738 unimplemented:
1739 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1740 level, optname);
thsc02f4992007-12-18 02:39:59 +00001741 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001742 break;
1743 }
1744 return ret;
bellard7854b052003-03-29 17:22:23 +00001745}
1746
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001747static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1748 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001749{
1750 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001751 struct iovec *vec;
1752 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001753 int i;
pbrook53a59602006-03-25 19:31:22 +00001754
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001755 if (count == 0) {
1756 errno = 0;
1757 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001758 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001759 if (count > IOV_MAX) {
1760 errno = EINVAL;
1761 return NULL;
1762 }
1763
1764 vec = calloc(count, sizeof(struct iovec));
1765 if (vec == NULL) {
1766 errno = ENOMEM;
1767 return NULL;
1768 }
1769
1770 target_vec = lock_user(VERIFY_READ, target_addr,
1771 count * sizeof(struct target_iovec), 1);
1772 if (target_vec == NULL) {
1773 errno = EFAULT;
1774 goto fail2;
1775 }
1776
1777 /* ??? If host page size > target page size, this will result in a
1778 value larger than what we can actually support. */
1779 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1780 total_len = 0;
1781
1782 for (i = 0; i < count; i++) {
1783 abi_ulong base = tswapal(target_vec[i].iov_base);
1784 abi_long len = tswapal(target_vec[i].iov_len);
1785
1786 if (len < 0) {
1787 errno = EINVAL;
1788 goto fail;
1789 } else if (len == 0) {
1790 /* Zero length pointer is ignored. */
1791 vec[i].iov_base = 0;
1792 } else {
1793 vec[i].iov_base = lock_user(type, base, len, copy);
1794 if (!vec[i].iov_base) {
1795 errno = EFAULT;
1796 goto fail;
1797 }
1798 if (len > max_len - total_len) {
1799 len = max_len - total_len;
1800 }
1801 }
1802 vec[i].iov_len = len;
1803 total_len += len;
1804 }
1805
1806 unlock_user(target_vec, target_addr, 0);
1807 return vec;
1808
1809 fail:
1810 free(vec);
1811 fail2:
1812 unlock_user(target_vec, target_addr, 0);
1813 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001814}
1815
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001816static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1817 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001818{
1819 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001820 int i;
1821
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001822 target_vec = lock_user(VERIFY_READ, target_addr,
1823 count * sizeof(struct target_iovec), 1);
1824 if (target_vec) {
1825 for (i = 0; i < count; i++) {
1826 abi_ulong base = tswapal(target_vec[i].iov_base);
1827 abi_long len = tswapal(target_vec[i].iov_base);
1828 if (len < 0) {
1829 break;
1830 }
balrogd732dcb2008-10-28 10:21:03 +00001831 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1832 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001833 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001834 }
bellard579a97f2007-11-11 14:26:47 +00001835
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001836 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001837}
1838
ths0da46a62007-10-20 20:23:07 +00001839/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001840static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001841{
1842#if defined(TARGET_MIPS)
1843 switch(type) {
1844 case TARGET_SOCK_DGRAM:
1845 type = SOCK_DGRAM;
1846 break;
1847 case TARGET_SOCK_STREAM:
1848 type = SOCK_STREAM;
1849 break;
1850 case TARGET_SOCK_RAW:
1851 type = SOCK_RAW;
1852 break;
1853 case TARGET_SOCK_RDM:
1854 type = SOCK_RDM;
1855 break;
1856 case TARGET_SOCK_SEQPACKET:
1857 type = SOCK_SEQPACKET;
1858 break;
1859 case TARGET_SOCK_PACKET:
1860 type = SOCK_PACKET;
1861 break;
1862 }
1863#endif
balrog12bc92a2007-10-30 21:06:14 +00001864 if (domain == PF_NETLINK)
1865 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001866 return get_errno(socket(domain, type, protocol));
1867}
1868
ths0da46a62007-10-20 20:23:07 +00001869/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001870static abi_long do_bind(int sockfd, abi_ulong target_addr,
1871 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001872{
aurel328f7aeaf2009-01-30 19:47:57 +00001873 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001874 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001875
Blue Swirl38724252010-09-18 05:53:14 +00001876 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001877 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001878 }
aurel328f7aeaf2009-01-30 19:47:57 +00001879
aurel32607175e2009-04-15 16:11:59 +00001880 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001881
Arnaud Patard917507b2009-06-19 10:44:45 +03001882 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1883 if (ret)
1884 return ret;
1885
bellard3532fa72006-06-24 15:06:03 +00001886 return get_errno(bind(sockfd, addr, addrlen));
1887}
1888
ths0da46a62007-10-20 20:23:07 +00001889/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001890static abi_long do_connect(int sockfd, abi_ulong target_addr,
1891 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001892{
aurel328f7aeaf2009-01-30 19:47:57 +00001893 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001894 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001895
Blue Swirl38724252010-09-18 05:53:14 +00001896 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001897 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001898 }
aurel328f7aeaf2009-01-30 19:47:57 +00001899
1900 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001901
Arnaud Patard917507b2009-06-19 10:44:45 +03001902 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1903 if (ret)
1904 return ret;
1905
bellard3532fa72006-06-24 15:06:03 +00001906 return get_errno(connect(sockfd, addr, addrlen));
1907}
1908
ths0da46a62007-10-20 20:23:07 +00001909/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001910static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1911 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001912{
balrog6de645c2008-10-28 10:26:29 +00001913 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001914 struct target_msghdr *msgp;
1915 struct msghdr msg;
1916 int count;
1917 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001918 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001919
bellard579a97f2007-11-11 14:26:47 +00001920 /* FIXME */
1921 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1922 msgp,
1923 target_msg,
1924 send ? 1 : 0))
1925 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001926 if (msgp->msg_name) {
1927 msg.msg_namelen = tswap32(msgp->msg_namelen);
1928 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001929 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001930 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001931 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001932 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001933 }
bellard3532fa72006-06-24 15:06:03 +00001934 } else {
1935 msg.msg_name = NULL;
1936 msg.msg_namelen = 0;
1937 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001938 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001939 msg.msg_control = alloca(msg.msg_controllen);
1940 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001941
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001942 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001943 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001944 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1945 target_vec, count, send);
1946 if (vec == NULL) {
1947 ret = -host_to_target_errno(errno);
1948 goto out2;
1949 }
bellard3532fa72006-06-24 15:06:03 +00001950 msg.msg_iovlen = count;
1951 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001952
bellard3532fa72006-06-24 15:06:03 +00001953 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001954 ret = target_to_host_cmsg(&msg, msgp);
1955 if (ret == 0)
1956 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001957 } else {
1958 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001959 if (!is_error(ret)) {
1960 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001961 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001962 if (!is_error(ret)) {
1963 msgp->msg_namelen = tswap32(msg.msg_namelen);
1964 if (msg.msg_name != NULL) {
1965 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1966 msg.msg_name, msg.msg_namelen);
1967 if (ret) {
1968 goto out;
1969 }
1970 }
1971
balrog6de645c2008-10-28 10:26:29 +00001972 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001973 }
balrog6de645c2008-10-28 10:26:29 +00001974 }
bellard3532fa72006-06-24 15:06:03 +00001975 }
Jing Huangca619062012-07-24 13:58:02 +00001976
1977out:
bellard3532fa72006-06-24 15:06:03 +00001978 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001979out2:
bellard579a97f2007-11-11 14:26:47 +00001980 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001981 return ret;
1982}
1983
ths0da46a62007-10-20 20:23:07 +00001984/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001985static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001986 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001987{
bellard2f619692007-11-16 10:46:05 +00001988 socklen_t addrlen;
1989 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001990 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001991
Arnaud Patard917507b2009-06-19 10:44:45 +03001992 if (target_addr == 0)
1993 return get_errno(accept(fd, NULL, NULL));
1994
1995 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001996 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001997 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001998
Blue Swirl38724252010-09-18 05:53:14 +00001999 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002000 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002001 }
aurel328f7aeaf2009-01-30 19:47:57 +00002002
Arnaud Patard917507b2009-06-19 10:44:45 +03002003 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2004 return -TARGET_EINVAL;
2005
bellard2f619692007-11-16 10:46:05 +00002006 addr = alloca(addrlen);
2007
pbrook1be9e1d2006-11-19 15:26:04 +00002008 ret = get_errno(accept(fd, addr, &addrlen));
2009 if (!is_error(ret)) {
2010 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002011 if (put_user_u32(addrlen, target_addrlen_addr))
2012 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002013 }
2014 return ret;
2015}
2016
ths0da46a62007-10-20 20:23:07 +00002017/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002018static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002019 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002020{
bellard2f619692007-11-16 10:46:05 +00002021 socklen_t addrlen;
2022 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002023 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002024
bellard2f619692007-11-16 10:46:05 +00002025 if (get_user_u32(addrlen, target_addrlen_addr))
2026 return -TARGET_EFAULT;
2027
Blue Swirl38724252010-09-18 05:53:14 +00002028 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002029 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002030 }
aurel328f7aeaf2009-01-30 19:47:57 +00002031
Arnaud Patard917507b2009-06-19 10:44:45 +03002032 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2033 return -TARGET_EFAULT;
2034
bellard2f619692007-11-16 10:46:05 +00002035 addr = alloca(addrlen);
2036
pbrook1be9e1d2006-11-19 15:26:04 +00002037 ret = get_errno(getpeername(fd, addr, &addrlen));
2038 if (!is_error(ret)) {
2039 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002040 if (put_user_u32(addrlen, target_addrlen_addr))
2041 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002042 }
2043 return ret;
2044}
2045
ths0da46a62007-10-20 20:23:07 +00002046/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002047static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002048 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002049{
bellard2f619692007-11-16 10:46:05 +00002050 socklen_t addrlen;
2051 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002052 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002053
bellard2f619692007-11-16 10:46:05 +00002054 if (get_user_u32(addrlen, target_addrlen_addr))
2055 return -TARGET_EFAULT;
2056
Blue Swirl38724252010-09-18 05:53:14 +00002057 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002058 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002059 }
aurel328f7aeaf2009-01-30 19:47:57 +00002060
Arnaud Patard917507b2009-06-19 10:44:45 +03002061 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2062 return -TARGET_EFAULT;
2063
bellard2f619692007-11-16 10:46:05 +00002064 addr = alloca(addrlen);
2065
pbrook1be9e1d2006-11-19 15:26:04 +00002066 ret = get_errno(getsockname(fd, addr, &addrlen));
2067 if (!is_error(ret)) {
2068 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002069 if (put_user_u32(addrlen, target_addrlen_addr))
2070 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002071 }
2072 return ret;
2073}
2074
ths0da46a62007-10-20 20:23:07 +00002075/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002076static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002077 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002078{
2079 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002080 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002081
2082 ret = get_errno(socketpair(domain, type, protocol, tab));
2083 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002084 if (put_user_s32(tab[0], target_tab_addr)
2085 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2086 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002087 }
2088 return ret;
2089}
2090
ths0da46a62007-10-20 20:23:07 +00002091/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002092static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2093 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002094{
2095 void *addr;
2096 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002097 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002098
Blue Swirl38724252010-09-18 05:53:14 +00002099 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002100 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002101 }
aurel328f7aeaf2009-01-30 19:47:57 +00002102
bellard579a97f2007-11-11 14:26:47 +00002103 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2104 if (!host_msg)
2105 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002106 if (target_addr) {
2107 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002108 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2109 if (ret) {
2110 unlock_user(host_msg, msg, 0);
2111 return ret;
2112 }
pbrook1be9e1d2006-11-19 15:26:04 +00002113 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2114 } else {
2115 ret = get_errno(send(fd, host_msg, len, flags));
2116 }
2117 unlock_user(host_msg, msg, 0);
2118 return ret;
2119}
2120
ths0da46a62007-10-20 20:23:07 +00002121/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002122static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2123 abi_ulong target_addr,
2124 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002125{
2126 socklen_t addrlen;
2127 void *addr;
2128 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002129 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002130
bellard579a97f2007-11-11 14:26:47 +00002131 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2132 if (!host_msg)
2133 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002134 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002135 if (get_user_u32(addrlen, target_addrlen)) {
2136 ret = -TARGET_EFAULT;
2137 goto fail;
2138 }
Blue Swirl38724252010-09-18 05:53:14 +00002139 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002140 ret = -TARGET_EINVAL;
2141 goto fail;
2142 }
pbrook1be9e1d2006-11-19 15:26:04 +00002143 addr = alloca(addrlen);
2144 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2145 } else {
2146 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002147 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002148 }
2149 if (!is_error(ret)) {
2150 if (target_addr) {
2151 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002152 if (put_user_u32(addrlen, target_addrlen)) {
2153 ret = -TARGET_EFAULT;
2154 goto fail;
2155 }
pbrook1be9e1d2006-11-19 15:26:04 +00002156 }
2157 unlock_user(host_msg, msg, len);
2158 } else {
bellard2f619692007-11-16 10:46:05 +00002159fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002160 unlock_user(host_msg, msg, 0);
2161 }
2162 return ret;
2163}
2164
j_mayer32407102007-09-26 23:01:49 +00002165#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002166/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002167static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002168{
blueswir1992f48a2007-10-14 16:27:31 +00002169 abi_long ret;
2170 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002171
2172 switch(num) {
2173 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002174 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002175 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002176
Ulrich Hecht98818182009-07-03 17:09:28 +02002177 if (get_user_ual(domain, vptr)
2178 || get_user_ual(type, vptr + n)
2179 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002180 return -TARGET_EFAULT;
2181
bellard3532fa72006-06-24 15:06:03 +00002182 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002183 }
bellard31e31b82003-02-18 22:55:36 +00002184 break;
2185 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002186 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002187 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002188 abi_ulong target_addr;
2189 socklen_t addrlen;
2190
Ulrich Hecht98818182009-07-03 17:09:28 +02002191 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002192 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002193 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002194 return -TARGET_EFAULT;
2195
bellard3532fa72006-06-24 15:06:03 +00002196 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002197 }
bellard31e31b82003-02-18 22:55:36 +00002198 break;
2199 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002200 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002201 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002202 abi_ulong target_addr;
2203 socklen_t addrlen;
2204
Ulrich Hecht98818182009-07-03 17:09:28 +02002205 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002206 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002207 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002208 return -TARGET_EFAULT;
2209
bellard3532fa72006-06-24 15:06:03 +00002210 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002211 }
bellard31e31b82003-02-18 22:55:36 +00002212 break;
2213 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002214 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002215 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002216
Ulrich Hecht98818182009-07-03 17:09:28 +02002217 if (get_user_ual(sockfd, vptr)
2218 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002219 return -TARGET_EFAULT;
2220
bellard7854b052003-03-29 17:22:23 +00002221 ret = get_errno(listen(sockfd, backlog));
2222 }
bellard31e31b82003-02-18 22:55:36 +00002223 break;
2224 case SOCKOP_accept:
2225 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002226 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002227 abi_ulong target_addr, target_addrlen;
2228
Ulrich Hecht98818182009-07-03 17:09:28 +02002229 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002230 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002231 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002232 return -TARGET_EFAULT;
2233
pbrook1be9e1d2006-11-19 15:26:04 +00002234 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002235 }
2236 break;
2237 case SOCKOP_getsockname:
2238 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002239 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002240 abi_ulong target_addr, target_addrlen;
2241
Ulrich Hecht98818182009-07-03 17:09:28 +02002242 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002243 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002244 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002245 return -TARGET_EFAULT;
2246
pbrook1be9e1d2006-11-19 15:26:04 +00002247 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002248 }
2249 break;
2250 case SOCKOP_getpeername:
2251 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002252 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002253 abi_ulong target_addr, target_addrlen;
2254
Ulrich Hecht98818182009-07-03 17:09:28 +02002255 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002256 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002257 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002258 return -TARGET_EFAULT;
2259
pbrook1be9e1d2006-11-19 15:26:04 +00002260 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002261 }
2262 break;
2263 case SOCKOP_socketpair:
2264 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002265 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002266 abi_ulong tab;
2267
Ulrich Hecht98818182009-07-03 17:09:28 +02002268 if (get_user_ual(domain, vptr)
2269 || get_user_ual(type, vptr + n)
2270 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002271 || get_user_ual(tab, vptr + 3 * n))
2272 return -TARGET_EFAULT;
2273
pbrook1be9e1d2006-11-19 15:26:04 +00002274 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002275 }
2276 break;
2277 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002278 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002279 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002280 abi_ulong msg;
2281 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002282 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002283
Ulrich Hecht98818182009-07-03 17:09:28 +02002284 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002285 || get_user_ual(msg, vptr + n)
2286 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002287 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002288 return -TARGET_EFAULT;
2289
pbrook1be9e1d2006-11-19 15:26:04 +00002290 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002291 }
bellard31e31b82003-02-18 22:55:36 +00002292 break;
2293 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002294 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002295 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002296 abi_ulong msg;
2297 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002298 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002299
Ulrich Hecht98818182009-07-03 17:09:28 +02002300 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002301 || get_user_ual(msg, vptr + n)
2302 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002303 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002304 return -TARGET_EFAULT;
2305
pbrook1be9e1d2006-11-19 15:26:04 +00002306 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002307 }
bellard31e31b82003-02-18 22:55:36 +00002308 break;
2309 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002310 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002311 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002312 abi_ulong msg;
2313 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002314 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002315 abi_ulong addr;
2316 socklen_t addrlen;
2317
Ulrich Hecht98818182009-07-03 17:09:28 +02002318 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002319 || get_user_ual(msg, vptr + n)
2320 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002321 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002322 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002323 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002324 return -TARGET_EFAULT;
2325
pbrook1be9e1d2006-11-19 15:26:04 +00002326 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002327 }
bellard31e31b82003-02-18 22:55:36 +00002328 break;
2329 case SOCKOP_recvfrom:
2330 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002331 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002332 abi_ulong msg;
2333 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002334 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002335 abi_ulong addr;
2336 socklen_t addrlen;
2337
Ulrich Hecht98818182009-07-03 17:09:28 +02002338 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002339 || get_user_ual(msg, vptr + n)
2340 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002341 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002342 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002343 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002344 return -TARGET_EFAULT;
2345
pbrook1be9e1d2006-11-19 15:26:04 +00002346 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002347 }
2348 break;
2349 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002350 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002351 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002352
Ulrich Hecht98818182009-07-03 17:09:28 +02002353 if (get_user_ual(sockfd, vptr)
2354 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002355 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002356
2357 ret = get_errno(shutdown(sockfd, how));
2358 }
bellard31e31b82003-02-18 22:55:36 +00002359 break;
2360 case SOCKOP_sendmsg:
2361 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002362 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002363 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002364 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002365 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002366
Ulrich Hecht98818182009-07-03 17:09:28 +02002367 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002368 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002369 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002370 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002371
ths5fafdf22007-09-16 21:08:06 +00002372 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002373 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002374 }
2375 break;
bellard31e31b82003-02-18 22:55:36 +00002376 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002377 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002378 abi_ulong sockfd;
2379 abi_ulong level;
2380 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002381 abi_ulong optval;
2382 socklen_t optlen;
2383
Ulrich Hecht98818182009-07-03 17:09:28 +02002384 if (get_user_ual(sockfd, vptr)
2385 || get_user_ual(level, vptr + n)
2386 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002387 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002388 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002389 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002390
2391 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2392 }
2393 break;
bellard31e31b82003-02-18 22:55:36 +00002394 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002395 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002396 abi_ulong sockfd;
2397 abi_ulong level;
2398 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002399 abi_ulong optval;
2400 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002401
Ulrich Hecht98818182009-07-03 17:09:28 +02002402 if (get_user_ual(sockfd, vptr)
2403 || get_user_ual(level, vptr + n)
2404 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002405 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002406 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002407 return -TARGET_EFAULT;
2408
2409 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002410 }
2411 break;
bellard31e31b82003-02-18 22:55:36 +00002412 default:
2413 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002414 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002415 break;
2416 }
2417 return ret;
2418}
j_mayer32407102007-09-26 23:01:49 +00002419#endif
bellard31e31b82003-02-18 22:55:36 +00002420
bellard8853f862004-02-22 14:57:26 +00002421#define N_SHM_REGIONS 32
2422
2423static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002424 abi_ulong start;
2425 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002426} shm_regions[N_SHM_REGIONS];
2427
ths3eb6b042007-06-03 14:26:27 +00002428struct target_ipc_perm
2429{
blueswir1992f48a2007-10-14 16:27:31 +00002430 abi_long __key;
2431 abi_ulong uid;
2432 abi_ulong gid;
2433 abi_ulong cuid;
2434 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002435 unsigned short int mode;
2436 unsigned short int __pad1;
2437 unsigned short int __seq;
2438 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002439 abi_ulong __unused1;
2440 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002441};
2442
2443struct target_semid_ds
2444{
2445 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002446 abi_ulong sem_otime;
2447 abi_ulong __unused1;
2448 abi_ulong sem_ctime;
2449 abi_ulong __unused2;
2450 abi_ulong sem_nsems;
2451 abi_ulong __unused3;
2452 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002453};
2454
bellard579a97f2007-11-11 14:26:47 +00002455static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2456 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002457{
2458 struct target_ipc_perm *target_ip;
2459 struct target_semid_ds *target_sd;
2460
bellard579a97f2007-11-11 14:26:47 +00002461 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2462 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002463 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002464 host_ip->__key = tswapal(target_ip->__key);
2465 host_ip->uid = tswapal(target_ip->uid);
2466 host_ip->gid = tswapal(target_ip->gid);
2467 host_ip->cuid = tswapal(target_ip->cuid);
2468 host_ip->cgid = tswapal(target_ip->cgid);
2469 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002470 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002471 return 0;
ths3eb6b042007-06-03 14:26:27 +00002472}
2473
bellard579a97f2007-11-11 14:26:47 +00002474static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2475 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002476{
2477 struct target_ipc_perm *target_ip;
2478 struct target_semid_ds *target_sd;
2479
bellard579a97f2007-11-11 14:26:47 +00002480 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2481 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002482 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002483 target_ip->__key = tswapal(host_ip->__key);
2484 target_ip->uid = tswapal(host_ip->uid);
2485 target_ip->gid = tswapal(host_ip->gid);
2486 target_ip->cuid = tswapal(host_ip->cuid);
2487 target_ip->cgid = tswapal(host_ip->cgid);
2488 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002489 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002490 return 0;
ths3eb6b042007-06-03 14:26:27 +00002491}
2492
bellard579a97f2007-11-11 14:26:47 +00002493static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2494 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002495{
2496 struct target_semid_ds *target_sd;
2497
bellard579a97f2007-11-11 14:26:47 +00002498 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2499 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002500 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2501 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002502 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2503 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2504 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002505 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002506 return 0;
ths3eb6b042007-06-03 14:26:27 +00002507}
2508
bellard579a97f2007-11-11 14:26:47 +00002509static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2510 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002511{
2512 struct target_semid_ds *target_sd;
2513
bellard579a97f2007-11-11 14:26:47 +00002514 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2515 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002516 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002517 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002518 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2519 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2520 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002521 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002522 return 0;
ths3eb6b042007-06-03 14:26:27 +00002523}
2524
aurel32e5289082009-04-18 16:16:12 +00002525struct target_seminfo {
2526 int semmap;
2527 int semmni;
2528 int semmns;
2529 int semmnu;
2530 int semmsl;
2531 int semopm;
2532 int semume;
2533 int semusz;
2534 int semvmx;
2535 int semaem;
2536};
2537
2538static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2539 struct seminfo *host_seminfo)
2540{
2541 struct target_seminfo *target_seminfo;
2542 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2543 return -TARGET_EFAULT;
2544 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2545 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2546 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2547 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2548 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2549 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2550 __put_user(host_seminfo->semume, &target_seminfo->semume);
2551 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2552 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2553 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2554 unlock_user_struct(target_seminfo, target_addr, 1);
2555 return 0;
2556}
2557
thsfa294812007-02-02 22:05:00 +00002558union semun {
2559 int val;
ths3eb6b042007-06-03 14:26:27 +00002560 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002561 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002562 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002563};
2564
ths3eb6b042007-06-03 14:26:27 +00002565union target_semun {
2566 int val;
aurel32e5289082009-04-18 16:16:12 +00002567 abi_ulong buf;
2568 abi_ulong array;
2569 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002570};
2571
aurel32e5289082009-04-18 16:16:12 +00002572static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2573 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002574{
aurel32e5289082009-04-18 16:16:12 +00002575 int nsems;
2576 unsigned short *array;
2577 union semun semun;
2578 struct semid_ds semid_ds;
2579 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002580
aurel32e5289082009-04-18 16:16:12 +00002581 semun.buf = &semid_ds;
2582
2583 ret = semctl(semid, 0, IPC_STAT, semun);
2584 if (ret == -1)
2585 return get_errno(ret);
2586
2587 nsems = semid_ds.sem_nsems;
2588
2589 *host_array = malloc(nsems*sizeof(unsigned short));
2590 array = lock_user(VERIFY_READ, target_addr,
2591 nsems*sizeof(unsigned short), 1);
2592 if (!array)
2593 return -TARGET_EFAULT;
2594
2595 for(i=0; i<nsems; i++) {
2596 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002597 }
aurel32e5289082009-04-18 16:16:12 +00002598 unlock_user(array, target_addr, 0);
2599
bellard579a97f2007-11-11 14:26:47 +00002600 return 0;
ths3eb6b042007-06-03 14:26:27 +00002601}
2602
aurel32e5289082009-04-18 16:16:12 +00002603static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2604 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002605{
aurel32e5289082009-04-18 16:16:12 +00002606 int nsems;
2607 unsigned short *array;
2608 union semun semun;
2609 struct semid_ds semid_ds;
2610 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002611
aurel32e5289082009-04-18 16:16:12 +00002612 semun.buf = &semid_ds;
2613
2614 ret = semctl(semid, 0, IPC_STAT, semun);
2615 if (ret == -1)
2616 return get_errno(ret);
2617
2618 nsems = semid_ds.sem_nsems;
2619
2620 array = lock_user(VERIFY_WRITE, target_addr,
2621 nsems*sizeof(unsigned short), 0);
2622 if (!array)
2623 return -TARGET_EFAULT;
2624
2625 for(i=0; i<nsems; i++) {
2626 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002627 }
aurel32e5289082009-04-18 16:16:12 +00002628 free(*host_array);
2629 unlock_user(array, target_addr, 1);
2630
bellard579a97f2007-11-11 14:26:47 +00002631 return 0;
ths3eb6b042007-06-03 14:26:27 +00002632}
2633
aurel32e5289082009-04-18 16:16:12 +00002634static inline abi_long do_semctl(int semid, int semnum, int cmd,
2635 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002636{
2637 union semun arg;
2638 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302639 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002640 struct seminfo seminfo;
2641 abi_long ret = -TARGET_EINVAL;
2642 abi_long err;
2643 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002644
2645 switch( cmd ) {
2646 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002647 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002648 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002649 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002650 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002651 break;
2652 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002653 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002654 err = target_to_host_semarray(semid, &array, target_su.array);
2655 if (err)
2656 return err;
2657 arg.array = array;
2658 ret = get_errno(semctl(semid, semnum, cmd, arg));
2659 err = host_to_target_semarray(semid, target_su.array, &array);
2660 if (err)
2661 return err;
ths3eb6b042007-06-03 14:26:27 +00002662 break;
2663 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002664 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002665 case SEM_STAT:
2666 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2667 if (err)
2668 return err;
2669 arg.buf = &dsarg;
2670 ret = get_errno(semctl(semid, semnum, cmd, arg));
2671 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2672 if (err)
2673 return err;
ths3eb6b042007-06-03 14:26:27 +00002674 break;
aurel32e5289082009-04-18 16:16:12 +00002675 case IPC_INFO:
2676 case SEM_INFO:
2677 arg.__buf = &seminfo;
2678 ret = get_errno(semctl(semid, semnum, cmd, arg));
2679 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2680 if (err)
2681 return err;
2682 break;
2683 case IPC_RMID:
2684 case GETPID:
2685 case GETNCNT:
2686 case GETZCNT:
2687 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2688 break;
ths3eb6b042007-06-03 14:26:27 +00002689 }
2690
2691 return ret;
2692}
2693
aurel32e5289082009-04-18 16:16:12 +00002694struct target_sembuf {
2695 unsigned short sem_num;
2696 short sem_op;
2697 short sem_flg;
2698};
2699
2700static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2701 abi_ulong target_addr,
2702 unsigned nsops)
2703{
2704 struct target_sembuf *target_sembuf;
2705 int i;
2706
2707 target_sembuf = lock_user(VERIFY_READ, target_addr,
2708 nsops*sizeof(struct target_sembuf), 1);
2709 if (!target_sembuf)
2710 return -TARGET_EFAULT;
2711
2712 for(i=0; i<nsops; i++) {
2713 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2714 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2715 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2716 }
2717
2718 unlock_user(target_sembuf, target_addr, 0);
2719
2720 return 0;
2721}
2722
2723static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2724{
2725 struct sembuf sops[nsops];
2726
2727 if (target_to_host_sembuf(sops, ptr, nsops))
2728 return -TARGET_EFAULT;
2729
2730 return semop(semid, sops, nsops);
2731}
2732
ths1bc012f2007-06-03 14:27:49 +00002733struct target_msqid_ds
2734{
aurel321c54ff92008-10-13 21:08:44 +00002735 struct target_ipc_perm msg_perm;
2736 abi_ulong msg_stime;
2737#if TARGET_ABI_BITS == 32
2738 abi_ulong __unused1;
2739#endif
2740 abi_ulong msg_rtime;
2741#if TARGET_ABI_BITS == 32
2742 abi_ulong __unused2;
2743#endif
2744 abi_ulong msg_ctime;
2745#if TARGET_ABI_BITS == 32
2746 abi_ulong __unused3;
2747#endif
2748 abi_ulong __msg_cbytes;
2749 abi_ulong msg_qnum;
2750 abi_ulong msg_qbytes;
2751 abi_ulong msg_lspid;
2752 abi_ulong msg_lrpid;
2753 abi_ulong __unused4;
2754 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002755};
2756
bellard579a97f2007-11-11 14:26:47 +00002757static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2758 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002759{
2760 struct target_msqid_ds *target_md;
2761
bellard579a97f2007-11-11 14:26:47 +00002762 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2763 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002764 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2765 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002766 host_md->msg_stime = tswapal(target_md->msg_stime);
2767 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2768 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2769 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2770 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2771 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2772 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2773 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002774 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002775 return 0;
ths1bc012f2007-06-03 14:27:49 +00002776}
2777
bellard579a97f2007-11-11 14:26:47 +00002778static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2779 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002780{
2781 struct target_msqid_ds *target_md;
2782
bellard579a97f2007-11-11 14:26:47 +00002783 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2784 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002785 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2786 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002787 target_md->msg_stime = tswapal(host_md->msg_stime);
2788 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2789 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2790 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2791 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2792 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2793 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2794 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002795 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002796 return 0;
ths1bc012f2007-06-03 14:27:49 +00002797}
2798
aurel321c54ff92008-10-13 21:08:44 +00002799struct target_msginfo {
2800 int msgpool;
2801 int msgmap;
2802 int msgmax;
2803 int msgmnb;
2804 int msgmni;
2805 int msgssz;
2806 int msgtql;
2807 unsigned short int msgseg;
2808};
2809
2810static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2811 struct msginfo *host_msginfo)
2812{
2813 struct target_msginfo *target_msginfo;
2814 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2815 return -TARGET_EFAULT;
2816 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2817 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2818 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2819 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2820 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2821 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2822 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2823 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2824 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002825 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002826}
2827
2828static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002829{
2830 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002831 struct msginfo msginfo;
2832 abi_long ret = -TARGET_EINVAL;
2833
2834 cmd &= 0xff;
2835
2836 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002837 case IPC_STAT:
2838 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002839 case MSG_STAT:
2840 if (target_to_host_msqid_ds(&dsarg,ptr))
2841 return -TARGET_EFAULT;
2842 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2843 if (host_to_target_msqid_ds(ptr,&dsarg))
2844 return -TARGET_EFAULT;
2845 break;
2846 case IPC_RMID:
2847 ret = get_errno(msgctl(msgid, cmd, NULL));
2848 break;
2849 case IPC_INFO:
2850 case MSG_INFO:
2851 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2852 if (host_to_target_msginfo(ptr, &msginfo))
2853 return -TARGET_EFAULT;
2854 break;
ths1bc012f2007-06-03 14:27:49 +00002855 }
aurel321c54ff92008-10-13 21:08:44 +00002856
ths1bc012f2007-06-03 14:27:49 +00002857 return ret;
2858}
2859
2860struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002861 abi_long mtype;
2862 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002863};
2864
blueswir1992f48a2007-10-14 16:27:31 +00002865static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2866 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002867{
2868 struct target_msgbuf *target_mb;
2869 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002870 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002871
bellard579a97f2007-11-11 14:26:47 +00002872 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2873 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002874 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002875 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002876 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002877 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2878 free(host_mb);
2879 unlock_user_struct(target_mb, msgp, 0);
2880
2881 return ret;
2882}
2883
blueswir1992f48a2007-10-14 16:27:31 +00002884static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002885 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002886 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002887{
2888 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002889 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002890 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002891 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002892
bellard579a97f2007-11-11 14:26:47 +00002893 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2894 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002895
Jim Meyering0d07fe42012-08-22 13:55:53 +02002896 host_mb = g_malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002897 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002898
bellard579a97f2007-11-11 14:26:47 +00002899 if (ret > 0) {
2900 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2901 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2902 if (!target_mtext) {
2903 ret = -TARGET_EFAULT;
2904 goto end;
2905 }
aurel321c54ff92008-10-13 21:08:44 +00002906 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002907 unlock_user(target_mtext, target_mtext_addr, ret);
2908 }
aurel321c54ff92008-10-13 21:08:44 +00002909
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002910 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002911
bellard579a97f2007-11-11 14:26:47 +00002912end:
2913 if (target_mb)
2914 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002915 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002916 return ret;
2917}
2918
Riku Voipio88a8c982009-04-03 10:42:00 +03002919struct target_shmid_ds
2920{
2921 struct target_ipc_perm shm_perm;
2922 abi_ulong shm_segsz;
2923 abi_ulong shm_atime;
2924#if TARGET_ABI_BITS == 32
2925 abi_ulong __unused1;
2926#endif
2927 abi_ulong shm_dtime;
2928#if TARGET_ABI_BITS == 32
2929 abi_ulong __unused2;
2930#endif
2931 abi_ulong shm_ctime;
2932#if TARGET_ABI_BITS == 32
2933 abi_ulong __unused3;
2934#endif
2935 int shm_cpid;
2936 int shm_lpid;
2937 abi_ulong shm_nattch;
2938 unsigned long int __unused4;
2939 unsigned long int __unused5;
2940};
2941
2942static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2943 abi_ulong target_addr)
2944{
2945 struct target_shmid_ds *target_sd;
2946
2947 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2948 return -TARGET_EFAULT;
2949 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2950 return -TARGET_EFAULT;
2951 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2952 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2953 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2954 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2955 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2956 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2957 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2958 unlock_user_struct(target_sd, target_addr, 0);
2959 return 0;
2960}
2961
2962static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2963 struct shmid_ds *host_sd)
2964{
2965 struct target_shmid_ds *target_sd;
2966
2967 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2968 return -TARGET_EFAULT;
2969 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2970 return -TARGET_EFAULT;
2971 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2972 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2973 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2974 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2975 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2976 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2977 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2978 unlock_user_struct(target_sd, target_addr, 1);
2979 return 0;
2980}
2981
2982struct target_shminfo {
2983 abi_ulong shmmax;
2984 abi_ulong shmmin;
2985 abi_ulong shmmni;
2986 abi_ulong shmseg;
2987 abi_ulong shmall;
2988};
2989
2990static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2991 struct shminfo *host_shminfo)
2992{
2993 struct target_shminfo *target_shminfo;
2994 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2995 return -TARGET_EFAULT;
2996 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2997 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2998 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2999 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3000 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3001 unlock_user_struct(target_shminfo, target_addr, 1);
3002 return 0;
3003}
3004
3005struct target_shm_info {
3006 int used_ids;
3007 abi_ulong shm_tot;
3008 abi_ulong shm_rss;
3009 abi_ulong shm_swp;
3010 abi_ulong swap_attempts;
3011 abi_ulong swap_successes;
3012};
3013
3014static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3015 struct shm_info *host_shm_info)
3016{
3017 struct target_shm_info *target_shm_info;
3018 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3019 return -TARGET_EFAULT;
3020 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3021 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3022 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3023 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3024 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3025 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3026 unlock_user_struct(target_shm_info, target_addr, 1);
3027 return 0;
3028}
3029
3030static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3031{
3032 struct shmid_ds dsarg;
3033 struct shminfo shminfo;
3034 struct shm_info shm_info;
3035 abi_long ret = -TARGET_EINVAL;
3036
3037 cmd &= 0xff;
3038
3039 switch(cmd) {
3040 case IPC_STAT:
3041 case IPC_SET:
3042 case SHM_STAT:
3043 if (target_to_host_shmid_ds(&dsarg, buf))
3044 return -TARGET_EFAULT;
3045 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3046 if (host_to_target_shmid_ds(buf, &dsarg))
3047 return -TARGET_EFAULT;
3048 break;
3049 case IPC_INFO:
3050 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3051 if (host_to_target_shminfo(buf, &shminfo))
3052 return -TARGET_EFAULT;
3053 break;
3054 case SHM_INFO:
3055 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3056 if (host_to_target_shm_info(buf, &shm_info))
3057 return -TARGET_EFAULT;
3058 break;
3059 case IPC_RMID:
3060 case SHM_LOCK:
3061 case SHM_UNLOCK:
3062 ret = get_errno(shmctl(shmid, cmd, NULL));
3063 break;
3064 }
3065
3066 return ret;
3067}
3068
3069static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3070{
3071 abi_long raddr;
3072 void *host_raddr;
3073 struct shmid_ds shm_info;
3074 int i,ret;
3075
3076 /* find out the length of the shared memory segment */
3077 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3078 if (is_error(ret)) {
3079 /* can't get length, bail out */
3080 return ret;
3081 }
3082
3083 mmap_lock();
3084
3085 if (shmaddr)
3086 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3087 else {
3088 abi_ulong mmap_start;
3089
3090 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3091
3092 if (mmap_start == -1) {
3093 errno = ENOMEM;
3094 host_raddr = (void *)-1;
3095 } else
3096 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3097 }
3098
3099 if (host_raddr == (void *)-1) {
3100 mmap_unlock();
3101 return get_errno((long)host_raddr);
3102 }
3103 raddr=h2g((unsigned long)host_raddr);
3104
3105 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3106 PAGE_VALID | PAGE_READ |
3107 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3108
3109 for (i = 0; i < N_SHM_REGIONS; i++) {
3110 if (shm_regions[i].start == 0) {
3111 shm_regions[i].start = raddr;
3112 shm_regions[i].size = shm_info.shm_segsz;
3113 break;
3114 }
3115 }
3116
3117 mmap_unlock();
3118 return raddr;
3119
3120}
3121
3122static inline abi_long do_shmdt(abi_ulong shmaddr)
3123{
3124 int i;
3125
3126 for (i = 0; i < N_SHM_REGIONS; ++i) {
3127 if (shm_regions[i].start == shmaddr) {
3128 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003129 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003130 break;
3131 }
3132 }
3133
3134 return get_errno(shmdt(g2h(shmaddr)));
3135}
3136
aurel321c54ff92008-10-13 21:08:44 +00003137#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003138/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003139/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003140static abi_long do_ipc(unsigned int call, int first,
3141 int second, int third,
3142 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003143{
3144 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003145 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003146
3147 version = call >> 16;
3148 call &= 0xffff;
3149
3150 switch (call) {
thsfa294812007-02-02 22:05:00 +00003151 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003152 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003153 break;
3154
3155 case IPCOP_semget:
3156 ret = get_errno(semget(first, second, third));
3157 break;
3158
3159 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003160 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003161 break;
thsd96372e2007-02-02 22:05:44 +00003162
aurel321c54ff92008-10-13 21:08:44 +00003163 case IPCOP_msgget:
3164 ret = get_errno(msgget(first, second));
3165 break;
thsd96372e2007-02-02 22:05:44 +00003166
aurel321c54ff92008-10-13 21:08:44 +00003167 case IPCOP_msgsnd:
3168 ret = do_msgsnd(first, ptr, second, third);
3169 break;
thsd96372e2007-02-02 22:05:44 +00003170
aurel321c54ff92008-10-13 21:08:44 +00003171 case IPCOP_msgctl:
3172 ret = do_msgctl(first, second, ptr);
3173 break;
thsd96372e2007-02-02 22:05:44 +00003174
aurel321c54ff92008-10-13 21:08:44 +00003175 case IPCOP_msgrcv:
3176 switch (version) {
3177 case 0:
3178 {
3179 struct target_ipc_kludge {
3180 abi_long msgp;
3181 abi_long msgtyp;
3182 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003183
aurel321c54ff92008-10-13 21:08:44 +00003184 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3185 ret = -TARGET_EFAULT;
3186 break;
ths1bc012f2007-06-03 14:27:49 +00003187 }
aurel321c54ff92008-10-13 21:08:44 +00003188
3189 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3190
3191 unlock_user_struct(tmp, ptr, 0);
3192 break;
3193 }
3194 default:
3195 ret = do_msgrcv(first, ptr, second, fifth, third);
3196 }
3197 break;
thsd96372e2007-02-02 22:05:44 +00003198
bellard8853f862004-02-22 14:57:26 +00003199 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003200 switch (version) {
3201 default:
bellard5a4a8982007-11-11 17:39:18 +00003202 {
3203 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003204 raddr = do_shmat(first, ptr, second);
3205 if (is_error(raddr))
3206 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003207 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003208 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003209 break;
3210 }
3211 case 1:
3212 ret = -TARGET_EINVAL;
3213 break;
bellard5a4a8982007-11-11 17:39:18 +00003214 }
bellard8853f862004-02-22 14:57:26 +00003215 break;
3216 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003217 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003218 break;
3219
3220 case IPCOP_shmget:
3221 /* IPC_* flag values are the same on all linux platforms */
3222 ret = get_errno(shmget(first, second, third));
3223 break;
3224
3225 /* IPC_* and SHM_* command values are the same on all linux platforms */
3226 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003227 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003228 break;
3229 default:
j_mayer32407102007-09-26 23:01:49 +00003230 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003231 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003232 break;
3233 }
3234 return ret;
3235}
j_mayer32407102007-09-26 23:01:49 +00003236#endif
bellard8853f862004-02-22 14:57:26 +00003237
bellard31e31b82003-02-18 22:55:36 +00003238/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003239
Blue Swirl001faf32009-05-13 17:53:17 +00003240#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003241#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3242enum {
3243#include "syscall_types.h"
3244};
3245#undef STRUCT
3246#undef STRUCT_SPECIAL
3247
Blue Swirl001faf32009-05-13 17:53:17 +00003248#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003249#define STRUCT_SPECIAL(name)
3250#include "syscall_types.h"
3251#undef STRUCT
3252#undef STRUCT_SPECIAL
3253
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003254typedef struct IOCTLEntry IOCTLEntry;
3255
3256typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3257 int fd, abi_long cmd, abi_long arg);
3258
3259struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003260 unsigned int target_cmd;
3261 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003262 const char *name;
3263 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003264 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003265 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003266};
bellard31e31b82003-02-18 22:55:36 +00003267
3268#define IOC_R 0x0001
3269#define IOC_W 0x0002
3270#define IOC_RW (IOC_R | IOC_W)
3271
3272#define MAX_STRUCT_SIZE 4096
3273
Peter Maydelldace20d2011-01-10 13:11:24 +00003274#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003275/* So fiemap access checks don't overflow on 32 bit systems.
3276 * This is very slightly smaller than the limit imposed by
3277 * the underlying kernel.
3278 */
3279#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3280 / sizeof(struct fiemap_extent))
3281
3282static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3283 int fd, abi_long cmd, abi_long arg)
3284{
3285 /* The parameter for this ioctl is a struct fiemap followed
3286 * by an array of struct fiemap_extent whose size is set
3287 * in fiemap->fm_extent_count. The array is filled in by the
3288 * ioctl.
3289 */
3290 int target_size_in, target_size_out;
3291 struct fiemap *fm;
3292 const argtype *arg_type = ie->arg_type;
3293 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3294 void *argptr, *p;
3295 abi_long ret;
3296 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3297 uint32_t outbufsz;
3298 int free_fm = 0;
3299
3300 assert(arg_type[0] == TYPE_PTR);
3301 assert(ie->access == IOC_RW);
3302 arg_type++;
3303 target_size_in = thunk_type_size(arg_type, 0);
3304 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3305 if (!argptr) {
3306 return -TARGET_EFAULT;
3307 }
3308 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3309 unlock_user(argptr, arg, 0);
3310 fm = (struct fiemap *)buf_temp;
3311 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3312 return -TARGET_EINVAL;
3313 }
3314
3315 outbufsz = sizeof (*fm) +
3316 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3317
3318 if (outbufsz > MAX_STRUCT_SIZE) {
3319 /* We can't fit all the extents into the fixed size buffer.
3320 * Allocate one that is large enough and use it instead.
3321 */
3322 fm = malloc(outbufsz);
3323 if (!fm) {
3324 return -TARGET_ENOMEM;
3325 }
3326 memcpy(fm, buf_temp, sizeof(struct fiemap));
3327 free_fm = 1;
3328 }
3329 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3330 if (!is_error(ret)) {
3331 target_size_out = target_size_in;
3332 /* An extent_count of 0 means we were only counting the extents
3333 * so there are no structs to copy
3334 */
3335 if (fm->fm_extent_count != 0) {
3336 target_size_out += fm->fm_mapped_extents * extent_size;
3337 }
3338 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3339 if (!argptr) {
3340 ret = -TARGET_EFAULT;
3341 } else {
3342 /* Convert the struct fiemap */
3343 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3344 if (fm->fm_extent_count != 0) {
3345 p = argptr + target_size_in;
3346 /* ...and then all the struct fiemap_extents */
3347 for (i = 0; i < fm->fm_mapped_extents; i++) {
3348 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3349 THUNK_TARGET);
3350 p += extent_size;
3351 }
3352 }
3353 unlock_user(argptr, arg, target_size_out);
3354 }
3355 }
3356 if (free_fm) {
3357 free(fm);
3358 }
3359 return ret;
3360}
Peter Maydelldace20d2011-01-10 13:11:24 +00003361#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003362
Laurent Vivier059c2f22011-03-30 00:12:12 +02003363static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3364 int fd, abi_long cmd, abi_long arg)
3365{
3366 const argtype *arg_type = ie->arg_type;
3367 int target_size;
3368 void *argptr;
3369 int ret;
3370 struct ifconf *host_ifconf;
3371 uint32_t outbufsz;
3372 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3373 int target_ifreq_size;
3374 int nb_ifreq;
3375 int free_buf = 0;
3376 int i;
3377 int target_ifc_len;
3378 abi_long target_ifc_buf;
3379 int host_ifc_len;
3380 char *host_ifc_buf;
3381
3382 assert(arg_type[0] == TYPE_PTR);
3383 assert(ie->access == IOC_RW);
3384
3385 arg_type++;
3386 target_size = thunk_type_size(arg_type, 0);
3387
3388 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3389 if (!argptr)
3390 return -TARGET_EFAULT;
3391 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3392 unlock_user(argptr, arg, 0);
3393
3394 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3395 target_ifc_len = host_ifconf->ifc_len;
3396 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3397
3398 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3399 nb_ifreq = target_ifc_len / target_ifreq_size;
3400 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3401
3402 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3403 if (outbufsz > MAX_STRUCT_SIZE) {
3404 /* We can't fit all the extents into the fixed size buffer.
3405 * Allocate one that is large enough and use it instead.
3406 */
3407 host_ifconf = malloc(outbufsz);
3408 if (!host_ifconf) {
3409 return -TARGET_ENOMEM;
3410 }
3411 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3412 free_buf = 1;
3413 }
3414 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3415
3416 host_ifconf->ifc_len = host_ifc_len;
3417 host_ifconf->ifc_buf = host_ifc_buf;
3418
3419 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3420 if (!is_error(ret)) {
3421 /* convert host ifc_len to target ifc_len */
3422
3423 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3424 target_ifc_len = nb_ifreq * target_ifreq_size;
3425 host_ifconf->ifc_len = target_ifc_len;
3426
3427 /* restore target ifc_buf */
3428
3429 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3430
3431 /* copy struct ifconf to target user */
3432
3433 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3434 if (!argptr)
3435 return -TARGET_EFAULT;
3436 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3437 unlock_user(argptr, arg, target_size);
3438
3439 /* copy ifreq[] to target user */
3440
3441 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3442 for (i = 0; i < nb_ifreq ; i++) {
3443 thunk_convert(argptr + i * target_ifreq_size,
3444 host_ifc_buf + i * sizeof(struct ifreq),
3445 ifreq_arg_type, THUNK_TARGET);
3446 }
3447 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3448 }
3449
3450 if (free_buf) {
3451 free(host_ifconf);
3452 }
3453
3454 return ret;
3455}
3456
Alexander Graf56e904e2012-01-31 18:42:06 +01003457static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3458 abi_long cmd, abi_long arg)
3459{
3460 void *argptr;
3461 struct dm_ioctl *host_dm;
3462 abi_long guest_data;
3463 uint32_t guest_data_size;
3464 int target_size;
3465 const argtype *arg_type = ie->arg_type;
3466 abi_long ret;
3467 void *big_buf = NULL;
3468 char *host_data;
3469
3470 arg_type++;
3471 target_size = thunk_type_size(arg_type, 0);
3472 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3473 if (!argptr) {
3474 ret = -TARGET_EFAULT;
3475 goto out;
3476 }
3477 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3478 unlock_user(argptr, arg, 0);
3479
3480 /* buf_temp is too small, so fetch things into a bigger buffer */
3481 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3482 memcpy(big_buf, buf_temp, target_size);
3483 buf_temp = big_buf;
3484 host_dm = big_buf;
3485
3486 guest_data = arg + host_dm->data_start;
3487 if ((guest_data - arg) < 0) {
3488 ret = -EINVAL;
3489 goto out;
3490 }
3491 guest_data_size = host_dm->data_size - host_dm->data_start;
3492 host_data = (char*)host_dm + host_dm->data_start;
3493
3494 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3495 switch (ie->host_cmd) {
3496 case DM_REMOVE_ALL:
3497 case DM_LIST_DEVICES:
3498 case DM_DEV_CREATE:
3499 case DM_DEV_REMOVE:
3500 case DM_DEV_SUSPEND:
3501 case DM_DEV_STATUS:
3502 case DM_DEV_WAIT:
3503 case DM_TABLE_STATUS:
3504 case DM_TABLE_CLEAR:
3505 case DM_TABLE_DEPS:
3506 case DM_LIST_VERSIONS:
3507 /* no input data */
3508 break;
3509 case DM_DEV_RENAME:
3510 case DM_DEV_SET_GEOMETRY:
3511 /* data contains only strings */
3512 memcpy(host_data, argptr, guest_data_size);
3513 break;
3514 case DM_TARGET_MSG:
3515 memcpy(host_data, argptr, guest_data_size);
3516 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3517 break;
3518 case DM_TABLE_LOAD:
3519 {
3520 void *gspec = argptr;
3521 void *cur_data = host_data;
3522 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3523 int spec_size = thunk_type_size(arg_type, 0);
3524 int i;
3525
3526 for (i = 0; i < host_dm->target_count; i++) {
3527 struct dm_target_spec *spec = cur_data;
3528 uint32_t next;
3529 int slen;
3530
3531 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3532 slen = strlen((char*)gspec + spec_size) + 1;
3533 next = spec->next;
3534 spec->next = sizeof(*spec) + slen;
3535 strcpy((char*)&spec[1], gspec + spec_size);
3536 gspec += next;
3537 cur_data += spec->next;
3538 }
3539 break;
3540 }
3541 default:
3542 ret = -TARGET_EINVAL;
3543 goto out;
3544 }
3545 unlock_user(argptr, guest_data, 0);
3546
3547 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3548 if (!is_error(ret)) {
3549 guest_data = arg + host_dm->data_start;
3550 guest_data_size = host_dm->data_size - host_dm->data_start;
3551 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3552 switch (ie->host_cmd) {
3553 case DM_REMOVE_ALL:
3554 case DM_DEV_CREATE:
3555 case DM_DEV_REMOVE:
3556 case DM_DEV_RENAME:
3557 case DM_DEV_SUSPEND:
3558 case DM_DEV_STATUS:
3559 case DM_TABLE_LOAD:
3560 case DM_TABLE_CLEAR:
3561 case DM_TARGET_MSG:
3562 case DM_DEV_SET_GEOMETRY:
3563 /* no return data */
3564 break;
3565 case DM_LIST_DEVICES:
3566 {
3567 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3568 uint32_t remaining_data = guest_data_size;
3569 void *cur_data = argptr;
3570 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3571 int nl_size = 12; /* can't use thunk_size due to alignment */
3572
3573 while (1) {
3574 uint32_t next = nl->next;
3575 if (next) {
3576 nl->next = nl_size + (strlen(nl->name) + 1);
3577 }
3578 if (remaining_data < nl->next) {
3579 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3580 break;
3581 }
3582 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3583 strcpy(cur_data + nl_size, nl->name);
3584 cur_data += nl->next;
3585 remaining_data -= nl->next;
3586 if (!next) {
3587 break;
3588 }
3589 nl = (void*)nl + next;
3590 }
3591 break;
3592 }
3593 case DM_DEV_WAIT:
3594 case DM_TABLE_STATUS:
3595 {
3596 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3597 void *cur_data = argptr;
3598 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3599 int spec_size = thunk_type_size(arg_type, 0);
3600 int i;
3601
3602 for (i = 0; i < host_dm->target_count; i++) {
3603 uint32_t next = spec->next;
3604 int slen = strlen((char*)&spec[1]) + 1;
3605 spec->next = (cur_data - argptr) + spec_size + slen;
3606 if (guest_data_size < spec->next) {
3607 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3608 break;
3609 }
3610 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3611 strcpy(cur_data + spec_size, (char*)&spec[1]);
3612 cur_data = argptr + spec->next;
3613 spec = (void*)host_dm + host_dm->data_start + next;
3614 }
3615 break;
3616 }
3617 case DM_TABLE_DEPS:
3618 {
3619 void *hdata = (void*)host_dm + host_dm->data_start;
3620 int count = *(uint32_t*)hdata;
3621 uint64_t *hdev = hdata + 8;
3622 uint64_t *gdev = argptr + 8;
3623 int i;
3624
3625 *(uint32_t*)argptr = tswap32(count);
3626 for (i = 0; i < count; i++) {
3627 *gdev = tswap64(*hdev);
3628 gdev++;
3629 hdev++;
3630 }
3631 break;
3632 }
3633 case DM_LIST_VERSIONS:
3634 {
3635 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3636 uint32_t remaining_data = guest_data_size;
3637 void *cur_data = argptr;
3638 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3639 int vers_size = thunk_type_size(arg_type, 0);
3640
3641 while (1) {
3642 uint32_t next = vers->next;
3643 if (next) {
3644 vers->next = vers_size + (strlen(vers->name) + 1);
3645 }
3646 if (remaining_data < vers->next) {
3647 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3648 break;
3649 }
3650 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3651 strcpy(cur_data + vers_size, vers->name);
3652 cur_data += vers->next;
3653 remaining_data -= vers->next;
3654 if (!next) {
3655 break;
3656 }
3657 vers = (void*)vers + next;
3658 }
3659 break;
3660 }
3661 default:
3662 ret = -TARGET_EINVAL;
3663 goto out;
3664 }
3665 unlock_user(argptr, guest_data, guest_data_size);
3666
3667 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3668 if (!argptr) {
3669 ret = -TARGET_EFAULT;
3670 goto out;
3671 }
3672 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3673 unlock_user(argptr, arg, target_size);
3674 }
3675out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003676 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003677 return ret;
3678}
3679
blueswir19f106a72008-10-05 10:52:52 +00003680static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003681#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003682 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3683#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3684 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003685#include "ioctls.h"
3686 { 0, 0, },
3687};
3688
pbrook53a59602006-03-25 19:31:22 +00003689/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003690/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003691static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003692{
3693 const IOCTLEntry *ie;
3694 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003695 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003696 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003697 int target_size;
3698 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003699
3700 ie = ioctl_entries;
3701 for(;;) {
3702 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003703 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003704 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003705 }
3706 if (ie->target_cmd == cmd)
3707 break;
3708 ie++;
3709 }
3710 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003711#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003712 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003713#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003714 if (ie->do_ioctl) {
3715 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3716 }
3717
bellard31e31b82003-02-18 22:55:36 +00003718 switch(arg_type[0]) {
3719 case TYPE_NULL:
3720 /* no argument */
3721 ret = get_errno(ioctl(fd, ie->host_cmd));
3722 break;
3723 case TYPE_PTRVOID:
3724 case TYPE_INT:
3725 /* int argment */
3726 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3727 break;
3728 case TYPE_PTR:
3729 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003730 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003731 switch(ie->access) {
3732 case IOC_R:
3733 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3734 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003735 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3736 if (!argptr)
3737 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003738 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3739 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003740 }
3741 break;
3742 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003743 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3744 if (!argptr)
3745 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003746 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3747 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003748 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3749 break;
3750 default:
3751 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003752 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3753 if (!argptr)
3754 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003755 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3756 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003757 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3758 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003759 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3760 if (!argptr)
3761 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003762 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3763 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003764 }
3765 break;
3766 }
3767 break;
3768 default:
j_mayer32407102007-09-26 23:01:49 +00003769 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3770 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003771 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003772 break;
3773 }
3774 return ret;
3775}
3776
blueswir1b39bc502008-10-05 10:51:10 +00003777static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003778 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3779 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3780 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3781 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3782 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3783 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3784 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3785 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3786 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3787 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3788 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3789 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3790 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3791 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3792 { 0, 0, 0, 0 }
3793};
3794
blueswir1b39bc502008-10-05 10:51:10 +00003795static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003796 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3797 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3798 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3799 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3800 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3801 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3802 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3803 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3804 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3805 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3806 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3807 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3808 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3809 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3810 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3811 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3812 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3813 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3814 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3815 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3816 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3817 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3818 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3819 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3820 { 0, 0, 0, 0 }
3821};
3822
blueswir1b39bc502008-10-05 10:51:10 +00003823static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003824 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3825 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3826 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3827 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3828 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3829 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3830 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3831 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3832 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3833 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3834 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3835 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3836 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3837 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3838 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3839 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3840 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3841 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3842 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3843 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3844 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3845 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3846 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3847 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3848 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3849 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3850 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3851 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3852 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3853 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3854 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3855 { 0, 0, 0, 0 }
3856};
3857
blueswir1b39bc502008-10-05 10:51:10 +00003858static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003859 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3860 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3861 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3862 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3863 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3864 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3865 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3866 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3867 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3868 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3869 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3870 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3871 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3872 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3873 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3874 { 0, 0, 0, 0 }
3875};
3876
3877static void target_to_host_termios (void *dst, const void *src)
3878{
3879 struct host_termios *host = dst;
3880 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003881
ths5fafdf22007-09-16 21:08:06 +00003882 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003883 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003884 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003885 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003886 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003887 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003888 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003889 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3890 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003891
Arnaud Patard44607122009-04-21 17:39:08 +03003892 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003893 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3894 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003895 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003896 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003897 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003898 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003899 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003900 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003901 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003902 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3903 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003904 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3905 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3906 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3907 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3908 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003909 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003910}
ths3b46e622007-09-17 08:09:54 +00003911
bellard31e31b82003-02-18 22:55:36 +00003912static void host_to_target_termios (void *dst, const void *src)
3913{
3914 struct target_termios *target = dst;
3915 const struct host_termios *host = src;
3916
ths5fafdf22007-09-16 21:08:06 +00003917 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003918 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003919 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003920 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003921 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003922 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003923 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003924 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3925 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003926
Arnaud Patard44607122009-04-21 17:39:08 +03003927 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003928 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3929 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3930 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3931 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3932 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3933 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3934 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3935 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3936 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3937 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3938 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3939 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3940 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3941 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3942 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3943 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3944 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3945}
3946
blueswir18e853dc2008-10-05 10:49:32 +00003947static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003948 .convert = { host_to_target_termios, target_to_host_termios },
3949 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3950 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3951};
3952
bellard5286db72003-06-05 00:57:30 +00003953static bitmask_transtbl mmap_flags_tbl[] = {
3954 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3955 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3956 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3957 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3958 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3959 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3960 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3961 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3962 { 0, 0, 0, 0 }
3963};
3964
bellard2ab83ea2003-06-15 19:56:46 +00003965#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003966
3967/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003968static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003969
bellard03acab62007-11-11 14:57:14 +00003970static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003971{
3972 int size;
pbrook53a59602006-03-25 19:31:22 +00003973 void *p;
bellard6dbad632003-03-16 18:05:05 +00003974
3975 if (!ldt_table)
3976 return 0;
3977 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3978 if (size > bytecount)
3979 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003980 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3981 if (!p)
bellard03acab62007-11-11 14:57:14 +00003982 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003983 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003984 memcpy(p, ldt_table, size);
3985 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003986 return size;
3987}
3988
3989/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003990static abi_long write_ldt(CPUX86State *env,
3991 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003992{
3993 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003994 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003995 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003996 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003997 uint32_t *lp, entry_1, entry_2;
3998
3999 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004000 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004001 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004002 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004003 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004004 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004005 ldt_info.limit = tswap32(target_ldt_info->limit);
4006 ldt_info.flags = tswap32(target_ldt_info->flags);
4007 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004008
bellard6dbad632003-03-16 18:05:05 +00004009 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004010 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004011 seg_32bit = ldt_info.flags & 1;
4012 contents = (ldt_info.flags >> 1) & 3;
4013 read_exec_only = (ldt_info.flags >> 3) & 1;
4014 limit_in_pages = (ldt_info.flags >> 4) & 1;
4015 seg_not_present = (ldt_info.flags >> 5) & 1;
4016 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004017#ifdef TARGET_ABI32
4018 lm = 0;
4019#else
4020 lm = (ldt_info.flags >> 7) & 1;
4021#endif
bellard6dbad632003-03-16 18:05:05 +00004022 if (contents == 3) {
4023 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004024 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004025 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004026 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004027 }
4028 /* allocate the LDT */
4029 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004030 env->ldt.base = target_mmap(0,
4031 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4032 PROT_READ|PROT_WRITE,
4033 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4034 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004035 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004036 memset(g2h(env->ldt.base), 0,
4037 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004038 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004039 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004040 }
4041
4042 /* NOTE: same code as Linux kernel */
4043 /* Allow LDTs to be cleared by the user. */
4044 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4045 if (oldmode ||
4046 (contents == 0 &&
4047 read_exec_only == 1 &&
4048 seg_32bit == 0 &&
4049 limit_in_pages == 0 &&
4050 seg_not_present == 1 &&
4051 useable == 0 )) {
4052 entry_1 = 0;
4053 entry_2 = 0;
4054 goto install;
4055 }
4056 }
ths3b46e622007-09-17 08:09:54 +00004057
bellard6dbad632003-03-16 18:05:05 +00004058 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4059 (ldt_info.limit & 0x0ffff);
4060 entry_2 = (ldt_info.base_addr & 0xff000000) |
4061 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4062 (ldt_info.limit & 0xf0000) |
4063 ((read_exec_only ^ 1) << 9) |
4064 (contents << 10) |
4065 ((seg_not_present ^ 1) << 15) |
4066 (seg_32bit << 22) |
4067 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004068 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004069 0x7000;
4070 if (!oldmode)
4071 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004072
bellard6dbad632003-03-16 18:05:05 +00004073 /* Install the new entry ... */
4074install:
4075 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4076 lp[0] = tswap32(entry_1);
4077 lp[1] = tswap32(entry_2);
4078 return 0;
4079}
4080
4081/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004082static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4083 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004084{
bellard03acab62007-11-11 14:57:14 +00004085 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004086
bellard6dbad632003-03-16 18:05:05 +00004087 switch (func) {
4088 case 0:
4089 ret = read_ldt(ptr, bytecount);
4090 break;
4091 case 1:
4092 ret = write_ldt(env, ptr, bytecount, 1);
4093 break;
4094 case 0x11:
4095 ret = write_ldt(env, ptr, bytecount, 0);
4096 break;
bellard03acab62007-11-11 14:57:14 +00004097 default:
4098 ret = -TARGET_ENOSYS;
4099 break;
bellard6dbad632003-03-16 18:05:05 +00004100 }
4101 return ret;
4102}
bellard1b6b0292003-03-22 17:31:38 +00004103
blueswir14583f582008-08-24 10:35:55 +00004104#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00004105static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004106{
4107 uint64_t *gdt_table = g2h(env->gdt.base);
4108 struct target_modify_ldt_ldt_s ldt_info;
4109 struct target_modify_ldt_ldt_s *target_ldt_info;
4110 int seg_32bit, contents, read_exec_only, limit_in_pages;
4111 int seg_not_present, useable, lm;
4112 uint32_t *lp, entry_1, entry_2;
4113 int i;
4114
4115 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4116 if (!target_ldt_info)
4117 return -TARGET_EFAULT;
4118 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004119 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004120 ldt_info.limit = tswap32(target_ldt_info->limit);
4121 ldt_info.flags = tswap32(target_ldt_info->flags);
4122 if (ldt_info.entry_number == -1) {
4123 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4124 if (gdt_table[i] == 0) {
4125 ldt_info.entry_number = i;
4126 target_ldt_info->entry_number = tswap32(i);
4127 break;
4128 }
4129 }
4130 }
4131 unlock_user_struct(target_ldt_info, ptr, 1);
4132
4133 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4134 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4135 return -TARGET_EINVAL;
4136 seg_32bit = ldt_info.flags & 1;
4137 contents = (ldt_info.flags >> 1) & 3;
4138 read_exec_only = (ldt_info.flags >> 3) & 1;
4139 limit_in_pages = (ldt_info.flags >> 4) & 1;
4140 seg_not_present = (ldt_info.flags >> 5) & 1;
4141 useable = (ldt_info.flags >> 6) & 1;
4142#ifdef TARGET_ABI32
4143 lm = 0;
4144#else
4145 lm = (ldt_info.flags >> 7) & 1;
4146#endif
4147
4148 if (contents == 3) {
4149 if (seg_not_present == 0)
4150 return -TARGET_EINVAL;
4151 }
4152
4153 /* NOTE: same code as Linux kernel */
4154 /* Allow LDTs to be cleared by the user. */
4155 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4156 if ((contents == 0 &&
4157 read_exec_only == 1 &&
4158 seg_32bit == 0 &&
4159 limit_in_pages == 0 &&
4160 seg_not_present == 1 &&
4161 useable == 0 )) {
4162 entry_1 = 0;
4163 entry_2 = 0;
4164 goto install;
4165 }
4166 }
4167
4168 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4169 (ldt_info.limit & 0x0ffff);
4170 entry_2 = (ldt_info.base_addr & 0xff000000) |
4171 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4172 (ldt_info.limit & 0xf0000) |
4173 ((read_exec_only ^ 1) << 9) |
4174 (contents << 10) |
4175 ((seg_not_present ^ 1) << 15) |
4176 (seg_32bit << 22) |
4177 (limit_in_pages << 23) |
4178 (useable << 20) |
4179 (lm << 21) |
4180 0x7000;
4181
4182 /* Install the new entry ... */
4183install:
4184 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4185 lp[0] = tswap32(entry_1);
4186 lp[1] = tswap32(entry_2);
4187 return 0;
4188}
4189
blueswir18fcd3692008-08-17 20:26:25 +00004190static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004191{
4192 struct target_modify_ldt_ldt_s *target_ldt_info;
4193 uint64_t *gdt_table = g2h(env->gdt.base);
4194 uint32_t base_addr, limit, flags;
4195 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4196 int seg_not_present, useable, lm;
4197 uint32_t *lp, entry_1, entry_2;
4198
4199 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4200 if (!target_ldt_info)
4201 return -TARGET_EFAULT;
4202 idx = tswap32(target_ldt_info->entry_number);
4203 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4204 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4205 unlock_user_struct(target_ldt_info, ptr, 1);
4206 return -TARGET_EINVAL;
4207 }
4208 lp = (uint32_t *)(gdt_table + idx);
4209 entry_1 = tswap32(lp[0]);
4210 entry_2 = tswap32(lp[1]);
4211
4212 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4213 contents = (entry_2 >> 10) & 3;
4214 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4215 seg_32bit = (entry_2 >> 22) & 1;
4216 limit_in_pages = (entry_2 >> 23) & 1;
4217 useable = (entry_2 >> 20) & 1;
4218#ifdef TARGET_ABI32
4219 lm = 0;
4220#else
4221 lm = (entry_2 >> 21) & 1;
4222#endif
4223 flags = (seg_32bit << 0) | (contents << 1) |
4224 (read_exec_only << 3) | (limit_in_pages << 4) |
4225 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4226 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4227 base_addr = (entry_1 >> 16) |
4228 (entry_2 & 0xff000000) |
4229 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004230 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004231 target_ldt_info->limit = tswap32(limit);
4232 target_ldt_info->flags = tswap32(flags);
4233 unlock_user_struct(target_ldt_info, ptr, 1);
4234 return 0;
4235}
blueswir14583f582008-08-24 10:35:55 +00004236#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004237
bellardd2fd1af2007-11-14 18:08:56 +00004238#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004239static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004240{
Juan Quintela1add8692011-06-16 17:37:09 +01004241 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004242 abi_ulong val;
4243 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004244
bellardd2fd1af2007-11-14 18:08:56 +00004245 switch(code) {
4246 case TARGET_ARCH_SET_GS:
4247 case TARGET_ARCH_SET_FS:
4248 if (code == TARGET_ARCH_SET_GS)
4249 idx = R_GS;
4250 else
4251 idx = R_FS;
4252 cpu_x86_load_seg(env, idx, 0);
4253 env->segs[idx].base = addr;
4254 break;
4255 case TARGET_ARCH_GET_GS:
4256 case TARGET_ARCH_GET_FS:
4257 if (code == TARGET_ARCH_GET_GS)
4258 idx = R_GS;
4259 else
4260 idx = R_FS;
4261 val = env->segs[idx].base;
4262 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004263 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004264 break;
4265 default:
4266 ret = -TARGET_EINVAL;
4267 break;
4268 }
Juan Quintela1add8692011-06-16 17:37:09 +01004269 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004270}
4271#endif
4272
bellard2ab83ea2003-06-15 19:56:46 +00004273#endif /* defined(TARGET_I386) */
4274
Riku Voipio05098a92011-03-04 15:27:29 +02004275#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004276
Riku Voipio05098a92011-03-04 15:27:29 +02004277#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004278
4279static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4280typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004281 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004282 pthread_mutex_t mutex;
4283 pthread_cond_t cond;
4284 pthread_t thread;
4285 uint32_t tid;
4286 abi_ulong child_tidptr;
4287 abi_ulong parent_tidptr;
4288 sigset_t sigmask;
4289} new_thread_info;
4290
4291static void *clone_func(void *arg)
4292{
4293 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004294 CPUArchState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004295 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004296
4297 env = info->env;
4298 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004299 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004300 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004301 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004302 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004303 if (info->child_tidptr)
4304 put_user_u32(info->tid, info->child_tidptr);
4305 if (info->parent_tidptr)
4306 put_user_u32(info->tid, info->parent_tidptr);
4307 /* Enable signals. */
4308 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4309 /* Signal to the parent that we're ready. */
4310 pthread_mutex_lock(&info->mutex);
4311 pthread_cond_broadcast(&info->cond);
4312 pthread_mutex_unlock(&info->mutex);
4313 /* Wait until the parent has finshed initializing the tls state. */
4314 pthread_mutex_lock(&clone_lock);
4315 pthread_mutex_unlock(&clone_lock);
4316 cpu_loop(env);
4317 /* never exits */
4318 return NULL;
4319}
4320#else
bellard1b6b0292003-03-22 17:31:38 +00004321
4322static int clone_func(void *arg)
4323{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004324 CPUArchState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00004325 cpu_loop(env);
4326 /* never exits */
4327 return 0;
4328}
pbrookd865bab2008-06-07 22:12:17 +00004329#endif
bellard1b6b0292003-03-22 17:31:38 +00004330
ths0da46a62007-10-20 20:23:07 +00004331/* do_fork() Must return host values and target errnos (unlike most
4332 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004333static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004334 abi_ulong parent_tidptr, target_ulong newtls,
4335 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004336{
4337 int ret;
bellard5cd43932003-03-29 16:54:36 +00004338 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004339 CPUArchState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004340#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004341 unsigned int nptl_flags;
4342 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02004343#else
4344 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00004345#endif
ths3b46e622007-09-17 08:09:54 +00004346
balrog436d1242008-09-21 02:39:45 +00004347 /* Emulate vfork() with fork() */
4348 if (flags & CLONE_VFORK)
4349 flags &= ~(CLONE_VFORK | CLONE_VM);
4350
bellard1b6b0292003-03-22 17:31:38 +00004351 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004352 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004353#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004354 new_thread_info info;
4355 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004356#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004357 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004358 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004359 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004360 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004361#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färberff18b762012-05-05 14:47:34 +02004362 cpu_reset(ENV_GET_CPU(new_env));
Blue Swirlb4558d72009-11-07 16:34:12 +00004363#endif
pbrook6e68e072008-05-30 17:22:15 +00004364 /* Init regs that differ from the parent. */
4365 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004366 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004367 ts->bprm = parent_ts->bprm;
4368 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004369#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004370 nptl_flags = flags;
4371 flags &= ~CLONE_NPTL_FLAGS2;
4372
pbrookc2764712009-03-07 15:24:59 +00004373 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4374 ts->child_tidptr = child_tidptr;
4375 }
4376
pbrookd865bab2008-06-07 22:12:17 +00004377 if (nptl_flags & CLONE_SETTLS)
4378 cpu_set_tls (new_env, newtls);
4379
4380 /* Grab a mutex so that thread setup appears atomic. */
4381 pthread_mutex_lock(&clone_lock);
4382
4383 memset(&info, 0, sizeof(info));
4384 pthread_mutex_init(&info.mutex, NULL);
4385 pthread_mutex_lock(&info.mutex);
4386 pthread_cond_init(&info.cond, NULL);
4387 info.env = new_env;
4388 if (nptl_flags & CLONE_CHILD_SETTID)
4389 info.child_tidptr = child_tidptr;
4390 if (nptl_flags & CLONE_PARENT_SETTID)
4391 info.parent_tidptr = parent_tidptr;
4392
4393 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004394 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4395 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004396 /* It is not safe to deliver signals until the child has finished
4397 initializing, so temporarily block all signals. */
4398 sigfillset(&sigmask);
4399 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4400
4401 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004402 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004403
4404 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4405 pthread_attr_destroy(&attr);
4406 if (ret == 0) {
4407 /* Wait for the child to initialize. */
4408 pthread_cond_wait(&info.cond, &info.mutex);
4409 ret = info.tid;
4410 if (flags & CLONE_PARENT_SETTID)
4411 put_user_u32(ret, parent_tidptr);
4412 } else {
4413 ret = -1;
4414 }
4415 pthread_mutex_unlock(&info.mutex);
4416 pthread_cond_destroy(&info.cond);
4417 pthread_mutex_destroy(&info.mutex);
4418 pthread_mutex_unlock(&clone_lock);
4419#else
4420 if (flags & CLONE_NPTL_FLAGS2)
4421 return -EINVAL;
4422 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004423 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004424#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004425 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004426#else
4427 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4428#endif
pbrookd865bab2008-06-07 22:12:17 +00004429#endif
bellard1b6b0292003-03-22 17:31:38 +00004430 } else {
4431 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004432 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004433 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004434 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004435 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004436 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004437 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004438 cpu_clone_regs(env, newsp);
4439 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004440#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004441 /* There is a race condition here. The parent process could
4442 theoretically read the TID in the child process before the child
4443 tid is set. This would require using either ptrace
4444 (not implemented) or having *_tidptr to point at a shared memory
4445 mapping. We can't repeat the spinlock hack used above because
4446 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004447 if (flags & CLONE_CHILD_SETTID)
4448 put_user_u32(gettid(), child_tidptr);
4449 if (flags & CLONE_PARENT_SETTID)
4450 put_user_u32(gettid(), parent_tidptr);
4451 ts = (TaskState *)env->opaque;
4452 if (flags & CLONE_SETTLS)
4453 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004454 if (flags & CLONE_CHILD_CLEARTID)
4455 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004456#endif
pbrookd865bab2008-06-07 22:12:17 +00004457 } else {
4458 fork_end(0);
4459 }
bellard1b6b0292003-03-22 17:31:38 +00004460 }
4461 return ret;
4462}
4463
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004464/* warning : doesn't handle linux specific flags... */
4465static int target_to_host_fcntl_cmd(int cmd)
4466{
4467 switch(cmd) {
4468 case TARGET_F_DUPFD:
4469 case TARGET_F_GETFD:
4470 case TARGET_F_SETFD:
4471 case TARGET_F_GETFL:
4472 case TARGET_F_SETFL:
4473 return cmd;
4474 case TARGET_F_GETLK:
4475 return F_GETLK;
4476 case TARGET_F_SETLK:
4477 return F_SETLK;
4478 case TARGET_F_SETLKW:
4479 return F_SETLKW;
4480 case TARGET_F_GETOWN:
4481 return F_GETOWN;
4482 case TARGET_F_SETOWN:
4483 return F_SETOWN;
4484 case TARGET_F_GETSIG:
4485 return F_GETSIG;
4486 case TARGET_F_SETSIG:
4487 return F_SETSIG;
4488#if TARGET_ABI_BITS == 32
4489 case TARGET_F_GETLK64:
4490 return F_GETLK64;
4491 case TARGET_F_SETLK64:
4492 return F_SETLK64;
4493 case TARGET_F_SETLKW64:
4494 return F_SETLKW64;
4495#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004496 case TARGET_F_SETLEASE:
4497 return F_SETLEASE;
4498 case TARGET_F_GETLEASE:
4499 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004500#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004501 case TARGET_F_DUPFD_CLOEXEC:
4502 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004503#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004504 case TARGET_F_NOTIFY:
4505 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004506 default:
4507 return -TARGET_EINVAL;
4508 }
4509 return -TARGET_EINVAL;
4510}
4511
blueswir1992f48a2007-10-14 16:27:31 +00004512static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004513{
4514 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004515 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004516 struct flock64 fl64;
4517 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004518 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004519 int host_cmd = target_to_host_fcntl_cmd(cmd);
4520
4521 if (host_cmd == -TARGET_EINVAL)
4522 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004523
bellard7775e9e2003-05-14 22:46:48 +00004524 switch(cmd) {
4525 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004526 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4527 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004528 fl.l_type = tswap16(target_fl->l_type);
4529 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004530 fl.l_start = tswapal(target_fl->l_start);
4531 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004532 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004533 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004534 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004535 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004536 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4537 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004538 target_fl->l_type = tswap16(fl.l_type);
4539 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004540 target_fl->l_start = tswapal(fl.l_start);
4541 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004542 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004543 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004544 }
4545 break;
ths3b46e622007-09-17 08:09:54 +00004546
bellard7775e9e2003-05-14 22:46:48 +00004547 case TARGET_F_SETLK:
4548 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004549 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4550 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004551 fl.l_type = tswap16(target_fl->l_type);
4552 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004553 fl.l_start = tswapal(target_fl->l_start);
4554 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004555 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004556 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004557 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004558 break;
ths3b46e622007-09-17 08:09:54 +00004559
bellard7775e9e2003-05-14 22:46:48 +00004560 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004561 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4562 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004563 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4564 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004565 fl64.l_start = tswap64(target_fl64->l_start);
4566 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004567 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004568 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004569 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004570 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004571 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4572 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004573 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4574 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004575 target_fl64->l_start = tswap64(fl64.l_start);
4576 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004577 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004578 unlock_user_struct(target_fl64, arg, 1);
4579 }
bellard9ee1fa22007-11-11 15:11:19 +00004580 break;
bellard7775e9e2003-05-14 22:46:48 +00004581 case TARGET_F_SETLK64:
4582 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004583 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4584 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004585 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4586 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004587 fl64.l_start = tswap64(target_fl64->l_start);
4588 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004589 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004590 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004591 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004592 break;
4593
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004594 case TARGET_F_GETFL:
4595 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004596 if (ret >= 0) {
4597 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4598 }
bellardffa65c32004-01-04 23:57:22 +00004599 break;
4600
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004601 case TARGET_F_SETFL:
4602 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4603 break;
4604
4605 case TARGET_F_SETOWN:
4606 case TARGET_F_GETOWN:
4607 case TARGET_F_SETSIG:
4608 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004609 case TARGET_F_SETLEASE:
4610 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004611 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004612 break;
4613
bellard7775e9e2003-05-14 22:46:48 +00004614 default:
bellard9ee1fa22007-11-11 15:11:19 +00004615 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004616 break;
4617 }
4618 return ret;
4619}
4620
bellard67867302003-11-23 17:05:30 +00004621#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004622
bellard67867302003-11-23 17:05:30 +00004623static inline int high2lowuid(int uid)
4624{
4625 if (uid > 65535)
4626 return 65534;
4627 else
4628 return uid;
4629}
4630
4631static inline int high2lowgid(int gid)
4632{
4633 if (gid > 65535)
4634 return 65534;
4635 else
4636 return gid;
4637}
4638
4639static inline int low2highuid(int uid)
4640{
4641 if ((int16_t)uid == -1)
4642 return -1;
4643 else
4644 return uid;
4645}
4646
4647static inline int low2highgid(int gid)
4648{
4649 if ((int16_t)gid == -1)
4650 return -1;
4651 else
4652 return gid;
4653}
Riku Voipio0c866a72011-04-18 15:23:06 +03004654static inline int tswapid(int id)
4655{
4656 return tswap16(id);
4657}
4658#else /* !USE_UID16 */
4659static inline int high2lowuid(int uid)
4660{
4661 return uid;
4662}
4663static inline int high2lowgid(int gid)
4664{
4665 return gid;
4666}
4667static inline int low2highuid(int uid)
4668{
4669 return uid;
4670}
4671static inline int low2highgid(int gid)
4672{
4673 return gid;
4674}
4675static inline int tswapid(int id)
4676{
4677 return tswap32(id);
4678}
bellard67867302003-11-23 17:05:30 +00004679#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004680
bellard31e31b82003-02-18 22:55:36 +00004681void syscall_init(void)
4682{
bellard2ab83ea2003-06-15 19:56:46 +00004683 IOCTLEntry *ie;
4684 const argtype *arg_type;
4685 int size;
thsb92c47c2007-11-01 00:07:38 +00004686 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004687
Blue Swirl001faf32009-05-13 17:53:17 +00004688#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004689#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004690#include "syscall_types.h"
4691#undef STRUCT
4692#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004693
Peter Maydelldd6e9572012-07-23 08:07:22 +00004694 /* Build target_to_host_errno_table[] table from
4695 * host_to_target_errno_table[]. */
4696 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4697 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4698 }
4699
bellard2ab83ea2003-06-15 19:56:46 +00004700 /* we patch the ioctl size if necessary. We rely on the fact that
4701 no ioctl has all the bits at '1' in the size field */
4702 ie = ioctl_entries;
4703 while (ie->target_cmd != 0) {
4704 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4705 TARGET_IOC_SIZEMASK) {
4706 arg_type = ie->arg_type;
4707 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004708 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004709 ie->target_cmd);
4710 exit(1);
4711 }
4712 arg_type++;
4713 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004714 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004715 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4716 (size << TARGET_IOC_SIZESHIFT);
4717 }
thsb92c47c2007-11-01 00:07:38 +00004718
bellard2ab83ea2003-06-15 19:56:46 +00004719 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004720#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4721 (defined(__x86_64__) && defined(TARGET_X86_64))
4722 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4723 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4724 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004725 }
4726#endif
4727 ie++;
4728 }
bellard31e31b82003-02-18 22:55:36 +00004729}
bellardc573ff62004-01-04 15:51:36 +00004730
blueswir1992f48a2007-10-14 16:27:31 +00004731#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004732static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4733{
thsaf325d32008-06-10 15:29:15 +00004734#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004735 return ((uint64_t)word0 << 32) | word1;
4736#else
4737 return ((uint64_t)word1 << 32) | word0;
4738#endif
4739}
blueswir1992f48a2007-10-14 16:27:31 +00004740#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004741static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4742{
4743 return word0;
4744}
blueswir1992f48a2007-10-14 16:27:31 +00004745#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004746
4747#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004748static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4749 abi_long arg2,
4750 abi_long arg3,
4751 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004752{
Riku Voipio48e515d2011-07-12 15:40:51 +03004753 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004754 arg2 = arg3;
4755 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004756 }
pbrookce4defa2006-02-09 16:49:55 +00004757 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4758}
4759#endif
4760
4761#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004762static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4763 abi_long arg2,
4764 abi_long arg3,
4765 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004766{
Riku Voipio48e515d2011-07-12 15:40:51 +03004767 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004768 arg2 = arg3;
4769 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004770 }
pbrookce4defa2006-02-09 16:49:55 +00004771 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4772}
4773#endif
4774
bellard579a97f2007-11-11 14:26:47 +00004775static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4776 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004777{
4778 struct target_timespec *target_ts;
4779
bellard579a97f2007-11-11 14:26:47 +00004780 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4781 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004782 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4783 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004784 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004785 return 0;
pbrook53a59602006-03-25 19:31:22 +00004786}
4787
bellard579a97f2007-11-11 14:26:47 +00004788static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4789 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004790{
4791 struct target_timespec *target_ts;
4792
bellard579a97f2007-11-11 14:26:47 +00004793 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4794 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004795 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4796 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004797 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004798 return 0;
pbrook53a59602006-03-25 19:31:22 +00004799}
4800
aurel329d33b762009-04-08 23:07:05 +00004801#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004802static inline abi_long host_to_target_stat64(void *cpu_env,
4803 abi_ulong target_addr,
4804 struct stat *host_st)
4805{
4806#ifdef TARGET_ARM
4807 if (((CPUARMState *)cpu_env)->eabi) {
4808 struct target_eabi_stat64 *target_st;
4809
4810 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4811 return -TARGET_EFAULT;
4812 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4813 __put_user(host_st->st_dev, &target_st->st_dev);
4814 __put_user(host_st->st_ino, &target_st->st_ino);
4815#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4816 __put_user(host_st->st_ino, &target_st->__st_ino);
4817#endif
4818 __put_user(host_st->st_mode, &target_st->st_mode);
4819 __put_user(host_st->st_nlink, &target_st->st_nlink);
4820 __put_user(host_st->st_uid, &target_st->st_uid);
4821 __put_user(host_st->st_gid, &target_st->st_gid);
4822 __put_user(host_st->st_rdev, &target_st->st_rdev);
4823 __put_user(host_st->st_size, &target_st->st_size);
4824 __put_user(host_st->st_blksize, &target_st->st_blksize);
4825 __put_user(host_st->st_blocks, &target_st->st_blocks);
4826 __put_user(host_st->st_atime, &target_st->target_st_atime);
4827 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4828 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4829 unlock_user_struct(target_st, target_addr, 1);
4830 } else
4831#endif
4832 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004833#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004834 struct target_stat *target_st;
4835#else
balrog6a24a772008-09-20 02:23:36 +00004836 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004837#endif
balrog6a24a772008-09-20 02:23:36 +00004838
4839 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4840 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004841 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004842 __put_user(host_st->st_dev, &target_st->st_dev);
4843 __put_user(host_st->st_ino, &target_st->st_ino);
4844#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4845 __put_user(host_st->st_ino, &target_st->__st_ino);
4846#endif
4847 __put_user(host_st->st_mode, &target_st->st_mode);
4848 __put_user(host_st->st_nlink, &target_st->st_nlink);
4849 __put_user(host_st->st_uid, &target_st->st_uid);
4850 __put_user(host_st->st_gid, &target_st->st_gid);
4851 __put_user(host_st->st_rdev, &target_st->st_rdev);
4852 /* XXX: better use of kernel struct */
4853 __put_user(host_st->st_size, &target_st->st_size);
4854 __put_user(host_st->st_blksize, &target_st->st_blksize);
4855 __put_user(host_st->st_blocks, &target_st->st_blocks);
4856 __put_user(host_st->st_atime, &target_st->target_st_atime);
4857 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4858 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4859 unlock_user_struct(target_st, target_addr, 1);
4860 }
4861
4862 return 0;
4863}
4864#endif
4865
Juan Quintela2f7bb872009-07-27 16:13:24 +02004866#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004867/* ??? Using host futex calls even when target atomic operations
4868 are not really atomic probably breaks things. However implementing
4869 futexes locally would make futexes shared between multiple processes
4870 tricky. However they're probably useless because guest atomic
4871 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004872static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4873 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004874{
4875 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004876 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004877
4878 /* ??? We assume FUTEX_* constants are the same on both host
4879 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004880#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004881 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004882#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004883 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004884#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004885 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004886 case FUTEX_WAIT:
4887 if (timeout) {
4888 pts = &ts;
4889 target_to_host_timespec(pts, timeout);
4890 } else {
4891 pts = NULL;
4892 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004893 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004894 pts, NULL, 0));
4895 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004896 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004897 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004898 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004899 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004900 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004901 case FUTEX_WAKE_OP:
4902 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4903 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4904 But the prototype takes a `struct timespec *'; insert casts
4905 to satisfy the compiler. We do not need to tswap TIMEOUT
4906 since it's not compared to guest memory. */
4907 pts = (struct timespec *)(uintptr_t) timeout;
4908 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4909 g2h(uaddr2),
4910 (base_op == FUTEX_CMP_REQUEUE
4911 ? tswap32(val3)
4912 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004913 default:
4914 return -TARGET_ENOSYS;
4915 }
4916}
4917#endif
4918
pbrook1d9d8b52009-04-16 15:17:02 +00004919/* Map host to target signal numbers for the wait family of syscalls.
4920 Assume all other status bits are the same. */
4921static int host_to_target_waitstatus(int status)
4922{
4923 if (WIFSIGNALED(status)) {
4924 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4925 }
4926 if (WIFSTOPPED(status)) {
4927 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4928 | (status & 0xff);
4929 }
4930 return status;
4931}
4932
pbrooka745ec62008-05-06 15:36:17 +00004933int get_osversion(void)
4934{
4935 static int osversion;
4936 struct new_utsname buf;
4937 const char *s;
4938 int i, n, tmp;
4939 if (osversion)
4940 return osversion;
4941 if (qemu_uname_release && *qemu_uname_release) {
4942 s = qemu_uname_release;
4943 } else {
4944 if (sys_uname(&buf))
4945 return 0;
4946 s = buf.release;
4947 }
4948 tmp = 0;
4949 for (i = 0; i < 3; i++) {
4950 n = 0;
4951 while (*s >= '0' && *s <= '9') {
4952 n *= 10;
4953 n += *s - '0';
4954 s++;
4955 }
4956 tmp = (tmp << 8) + n;
4957 if (*s == '.')
4958 s++;
4959 }
4960 osversion = tmp;
4961 return osversion;
4962}
4963
Alexander Graf36c08d42011-11-02 20:23:24 +01004964
4965static int open_self_maps(void *cpu_env, int fd)
4966{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004967#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01004968 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004969#endif
4970 FILE *fp;
4971 char *line = NULL;
4972 size_t len = 0;
4973 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004974
Alexander Graf1a49ef22012-05-01 16:30:28 +01004975 fp = fopen("/proc/self/maps", "r");
4976 if (fp == NULL) {
4977 return -EACCES;
4978 }
4979
4980 while ((read = getline(&line, &len, fp)) != -1) {
4981 int fields, dev_maj, dev_min, inode;
4982 uint64_t min, max, offset;
4983 char flag_r, flag_w, flag_x, flag_p;
4984 char path[512] = "";
4985 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4986 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4987 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4988
4989 if ((fields < 10) || (fields > 11)) {
4990 continue;
4991 }
4992 if (!strncmp(path, "[stack]", 7)) {
4993 continue;
4994 }
4995 if (h2g_valid(min) && h2g_valid(max)) {
4996 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
4997 " %c%c%c%c %08" PRIx64 " %02x:%02x %d%s%s\n",
4998 h2g(min), h2g(max), flag_r, flag_w,
4999 flag_x, flag_p, offset, dev_maj, dev_min, inode,
5000 path[0] ? " " : "", path);
5001 }
5002 }
5003
5004 free(line);
5005 fclose(fp);
5006
5007#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005008 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5009 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005010 (unsigned long long)(ts->info->start_stack +
5011 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005012 (unsigned long long)0);
5013#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005014
5015 return 0;
5016}
5017
Alexander Graf480b8e72011-11-02 20:23:25 +01005018static int open_self_stat(void *cpu_env, int fd)
5019{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005020 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005021 abi_ulong start_stack = ts->info->start_stack;
5022 int i;
5023
5024 for (i = 0; i < 44; i++) {
5025 char buf[128];
5026 int len;
5027 uint64_t val = 0;
5028
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005029 if (i == 0) {
5030 /* pid */
5031 val = getpid();
5032 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5033 } else if (i == 1) {
5034 /* app name */
5035 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5036 } else if (i == 27) {
5037 /* stack bottom */
5038 val = start_stack;
5039 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5040 } else {
5041 /* for the rest, there is MasterCard */
5042 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005043 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005044
Alexander Graf480b8e72011-11-02 20:23:25 +01005045 len = strlen(buf);
5046 if (write(fd, buf, len) != len) {
5047 return -1;
5048 }
5049 }
5050
5051 return 0;
5052}
5053
Alexander Graf257450e2011-11-02 20:23:26 +01005054static int open_self_auxv(void *cpu_env, int fd)
5055{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005056 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005057 abi_ulong auxv = ts->info->saved_auxv;
5058 abi_ulong len = ts->info->auxv_len;
5059 char *ptr;
5060
5061 /*
5062 * Auxiliary vector is stored in target process stack.
5063 * read in whole auxv vector and copy it to file
5064 */
5065 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5066 if (ptr != NULL) {
5067 while (len > 0) {
5068 ssize_t r;
5069 r = write(fd, ptr, len);
5070 if (r <= 0) {
5071 break;
5072 }
5073 len -= r;
5074 ptr += r;
5075 }
5076 lseek(fd, 0, SEEK_SET);
5077 unlock_user(ptr, auxv, len);
5078 }
5079
5080 return 0;
5081}
5082
Alexander Graf3be14d02011-11-02 20:23:23 +01005083static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5084{
5085 struct fake_open {
5086 const char *filename;
5087 int (*fill)(void *cpu_env, int fd);
5088 };
5089 const struct fake_open *fake_open;
5090 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01005091 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01005092 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01005093 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01005094 { NULL, NULL }
5095 };
5096
5097 for (fake_open = fakes; fake_open->filename; fake_open++) {
5098 if (!strncmp(pathname, fake_open->filename,
5099 strlen(fake_open->filename))) {
5100 break;
5101 }
5102 }
5103
5104 if (fake_open->filename) {
5105 const char *tmpdir;
5106 char filename[PATH_MAX];
5107 int fd, r;
5108
5109 /* create temporary file to map stat to */
5110 tmpdir = getenv("TMPDIR");
5111 if (!tmpdir)
5112 tmpdir = "/tmp";
5113 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5114 fd = mkstemp(filename);
5115 if (fd < 0) {
5116 return fd;
5117 }
5118 unlink(filename);
5119
5120 if ((r = fake_open->fill(cpu_env, fd))) {
5121 close(fd);
5122 return r;
5123 }
5124 lseek(fd, 0, SEEK_SET);
5125
5126 return fd;
5127 }
5128
5129 return get_errno(open(path(pathname), flags, mode));
5130}
5131
ths0da46a62007-10-20 20:23:07 +00005132/* do_syscall() should always have a single exit point at the end so
5133 that actions, such as logging of syscall results, can be performed.
5134 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005135abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5136 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005137 abi_long arg5, abi_long arg6, abi_long arg7,
5138 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005139{
blueswir1992f48a2007-10-14 16:27:31 +00005140 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005141 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005142 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005143 void *p;
ths3b46e622007-09-17 08:09:54 +00005144
bellard72f03902003-02-18 23:33:18 +00005145#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005146 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005147#endif
thsb92c47c2007-11-01 00:07:38 +00005148 if(do_strace)
5149 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5150
bellard31e31b82003-02-18 22:55:36 +00005151 switch(num) {
5152 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02005153#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00005154 /* In old applications this may be used to implement _exit(2).
5155 However in threaded applictions it is used for thread termination,
5156 and _exit_group is used for application termination.
5157 Do thread termination if we have more then one thread. */
5158 /* FIXME: This probably breaks if a signal arrives. We should probably
5159 be disabling signals. */
5160 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07005161 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005162 CPUArchState **lastp;
5163 CPUArchState *p;
pbrookc2764712009-03-07 15:24:59 +00005164
5165 cpu_list_lock();
5166 lastp = &first_cpu;
5167 p = first_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005168 while (p && p != (CPUArchState *)cpu_env) {
pbrookc2764712009-03-07 15:24:59 +00005169 lastp = &p->next_cpu;
5170 p = p->next_cpu;
5171 }
5172 /* If we didn't find the CPU for this thread then something is
5173 horribly wrong. */
5174 if (!p)
5175 abort();
5176 /* Remove the CPU from the list. */
5177 *lastp = p->next_cpu;
5178 cpu_list_unlock();
Andreas Färber9349b4f2012-03-14 01:38:32 +01005179 ts = ((CPUArchState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00005180 if (ts->child_tidptr) {
5181 put_user_u32(0, ts->child_tidptr);
5182 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5183 NULL, NULL, 0);
5184 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005185 thread_env = NULL;
Andreas Färber11ea4092012-04-15 18:51:01 +02005186 object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
Anthony Liguori7267c092011-08-20 22:09:37 -05005187 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00005188 pthread_exit(NULL);
5189 }
5190#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02005191#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005192 _mcleanup();
5193#endif
bellarde9009672005-04-26 20:42:36 +00005194 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005195 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005196 ret = 0; /* avoid warning */
5197 break;
5198 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005199 if (arg3 == 0)
5200 ret = 0;
5201 else {
5202 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5203 goto efault;
5204 ret = get_errno(read(arg1, p, arg3));
5205 unlock_user(p, arg2, ret);
5206 }
bellard31e31b82003-02-18 22:55:36 +00005207 break;
5208 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005209 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5210 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005211 ret = get_errno(write(arg1, p, arg3));
5212 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005213 break;
5214 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005215 if (!(p = lock_user_string(arg1)))
5216 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005217 ret = get_errno(do_open(cpu_env, p,
5218 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5219 arg3));
pbrook53a59602006-03-25 19:31:22 +00005220 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005221 break;
ths82424832007-09-24 09:21:55 +00005222#if defined(TARGET_NR_openat) && defined(__NR_openat)
5223 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005224 if (!(p = lock_user_string(arg2)))
5225 goto efault;
5226 ret = get_errno(sys_openat(arg1,
5227 path(p),
5228 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5229 arg4));
5230 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005231 break;
5232#endif
bellard31e31b82003-02-18 22:55:36 +00005233 case TARGET_NR_close:
5234 ret = get_errno(close(arg1));
5235 break;
5236 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005237 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005238 break;
5239 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005240 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005241 break;
thse5febef2007-04-01 18:31:35 +00005242#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005243 case TARGET_NR_waitpid:
5244 {
pbrook53a59602006-03-25 19:31:22 +00005245 int status;
5246 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005247 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005248 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005249 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005250 }
5251 break;
thse5febef2007-04-01 18:31:35 +00005252#endif
pbrookf0cbb612008-05-30 18:20:05 +00005253#ifdef TARGET_NR_waitid
5254 case TARGET_NR_waitid:
5255 {
5256 siginfo_t info;
5257 info.si_pid = 0;
5258 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5259 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005260 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005261 goto efault;
5262 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005263 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005264 }
5265 }
5266 break;
5267#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005268#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005269 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005270 if (!(p = lock_user_string(arg1)))
5271 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005272 ret = get_errno(creat(p, arg2));
5273 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005274 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005275#endif
bellard31e31b82003-02-18 22:55:36 +00005276 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005277 {
5278 void * p2;
5279 p = lock_user_string(arg1);
5280 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005281 if (!p || !p2)
5282 ret = -TARGET_EFAULT;
5283 else
5284 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005285 unlock_user(p2, arg2, 0);
5286 unlock_user(p, arg1, 0);
5287 }
bellard31e31b82003-02-18 22:55:36 +00005288 break;
ths64f0ce42007-09-24 09:25:06 +00005289#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
5290 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005291 {
5292 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005293 if (!arg2 || !arg4)
5294 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005295 p = lock_user_string(arg2);
5296 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005297 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005298 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005299 else
5300 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005301 unlock_user(p, arg2, 0);
5302 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005303 }
5304 break;
5305#endif
bellard31e31b82003-02-18 22:55:36 +00005306 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005307 if (!(p = lock_user_string(arg1)))
5308 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005309 ret = get_errno(unlink(p));
5310 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005311 break;
ths8170f562007-09-24 09:24:11 +00005312#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
5313 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005314 if (!(p = lock_user_string(arg2)))
5315 goto efault;
5316 ret = get_errno(sys_unlinkat(arg1, p, arg3));
5317 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005318 break;
balrogb7d35e62007-12-12 00:40:24 +00005319#endif
bellard31e31b82003-02-18 22:55:36 +00005320 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005321 {
5322 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005323 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005324 abi_ulong gp;
5325 abi_ulong guest_argp;
5326 abi_ulong guest_envp;
5327 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005328 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005329 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005330
bellardf7341ff2003-03-30 21:00:25 +00005331 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005332 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005333 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005334 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005335 goto efault;
ths03aa1972007-12-02 06:28:08 +00005336 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005337 break;
bellard7854b052003-03-29 17:22:23 +00005338 argc++;
bellard2f619692007-11-16 10:46:05 +00005339 }
bellardf7341ff2003-03-30 21:00:25 +00005340 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005341 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005342 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005343 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005344 goto efault;
ths03aa1972007-12-02 06:28:08 +00005345 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005346 break;
bellard7854b052003-03-29 17:22:23 +00005347 envc++;
bellard2f619692007-11-16 10:46:05 +00005348 }
bellard7854b052003-03-29 17:22:23 +00005349
bellardf7341ff2003-03-30 21:00:25 +00005350 argp = alloca((argc + 1) * sizeof(void *));
5351 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005352
pbrookda94d262008-05-30 18:24:00 +00005353 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005354 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005355 if (get_user_ual(addr, gp))
5356 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005357 if (!addr)
5358 break;
bellard2f619692007-11-16 10:46:05 +00005359 if (!(*q = lock_user_string(addr)))
5360 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005361 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005362 }
bellardf7341ff2003-03-30 21:00:25 +00005363 *q = NULL;
5364
pbrookda94d262008-05-30 18:24:00 +00005365 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005366 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005367 if (get_user_ual(addr, gp))
5368 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005369 if (!addr)
5370 break;
bellard2f619692007-11-16 10:46:05 +00005371 if (!(*q = lock_user_string(addr)))
5372 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005373 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005374 }
bellardf7341ff2003-03-30 21:00:25 +00005375 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005376
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005377 /* This case will not be caught by the host's execve() if its
5378 page size is bigger than the target's. */
5379 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5380 ret = -TARGET_E2BIG;
5381 goto execve_end;
5382 }
bellard2f619692007-11-16 10:46:05 +00005383 if (!(p = lock_user_string(arg1)))
5384 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005385 ret = get_errno(execve(p, argp, envp));
5386 unlock_user(p, arg1, 0);
5387
bellard2f619692007-11-16 10:46:05 +00005388 goto execve_end;
5389
5390 execve_efault:
5391 ret = -TARGET_EFAULT;
5392
5393 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005394 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005395 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005396 if (get_user_ual(addr, gp)
5397 || !addr)
5398 break;
pbrook53a59602006-03-25 19:31:22 +00005399 unlock_user(*q, addr, 0);
5400 }
5401 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005402 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005403 if (get_user_ual(addr, gp)
5404 || !addr)
5405 break;
pbrook53a59602006-03-25 19:31:22 +00005406 unlock_user(*q, addr, 0);
5407 }
bellard7854b052003-03-29 17:22:23 +00005408 }
bellard31e31b82003-02-18 22:55:36 +00005409 break;
5410 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005411 if (!(p = lock_user_string(arg1)))
5412 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005413 ret = get_errno(chdir(p));
5414 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005415 break;
bellarda315a142005-01-30 22:59:18 +00005416#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005417 case TARGET_NR_time:
5418 {
pbrook53a59602006-03-25 19:31:22 +00005419 time_t host_time;
5420 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005421 if (!is_error(ret)
5422 && arg1
5423 && put_user_sal(host_time, arg1))
5424 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005425 }
5426 break;
bellarda315a142005-01-30 22:59:18 +00005427#endif
bellard31e31b82003-02-18 22:55:36 +00005428 case TARGET_NR_mknod:
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(mknod(p, arg2, arg3));
5432 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005433 break;
ths75ac37a2007-09-24 09:23:05 +00005434#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
5435 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005436 if (!(p = lock_user_string(arg2)))
5437 goto efault;
5438 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
5439 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005440 break;
5441#endif
bellard31e31b82003-02-18 22:55:36 +00005442 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005443 if (!(p = lock_user_string(arg1)))
5444 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005445 ret = get_errno(chmod(p, arg2));
5446 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005447 break;
bellardebc05482003-09-30 21:08:41 +00005448#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005449 case TARGET_NR_break:
5450 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005451#endif
5452#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005453 case TARGET_NR_oldstat:
5454 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005455#endif
bellard31e31b82003-02-18 22:55:36 +00005456 case TARGET_NR_lseek:
5457 ret = get_errno(lseek(arg1, arg2, arg3));
5458 break;
Richard Henderson92317332010-05-03 10:07:53 -07005459#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5460 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005461 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005462 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005463 ret = get_errno(getpid());
5464 break;
Richard Henderson92317332010-05-03 10:07:53 -07005465#endif
5466#ifdef TARGET_NR_getpid
5467 case TARGET_NR_getpid:
5468 ret = get_errno(getpid());
5469 break;
5470#endif
bellard31e31b82003-02-18 22:55:36 +00005471 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005472 {
5473 /* need to look at the data field */
5474 void *p2, *p3;
5475 p = lock_user_string(arg1);
5476 p2 = lock_user_string(arg2);
5477 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005478 if (!p || !p2 || !p3)
5479 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005480 else {
bellard579a97f2007-11-11 14:26:47 +00005481 /* FIXME - arg5 should be locked, but it isn't clear how to
5482 * do that since it's not guaranteed to be a NULL-terminated
5483 * string.
5484 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005485 if ( ! arg5 )
5486 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5487 else
5488 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5489 }
bellard579a97f2007-11-11 14:26:47 +00005490 unlock_user(p, arg1, 0);
5491 unlock_user(p2, arg2, 0);
5492 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005493 break;
5494 }
thse5febef2007-04-01 18:31:35 +00005495#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005496 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005497 if (!(p = lock_user_string(arg1)))
5498 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005499 ret = get_errno(umount(p));
5500 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005501 break;
thse5febef2007-04-01 18:31:35 +00005502#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005503#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005504 case TARGET_NR_stime:
5505 {
pbrook53a59602006-03-25 19:31:22 +00005506 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005507 if (get_user_sal(host_time, arg1))
5508 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005509 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005510 }
5511 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005512#endif
bellard31e31b82003-02-18 22:55:36 +00005513 case TARGET_NR_ptrace:
5514 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005515#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005516 case TARGET_NR_alarm:
5517 ret = alarm(arg1);
5518 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005519#endif
bellardebc05482003-09-30 21:08:41 +00005520#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005521 case TARGET_NR_oldfstat:
5522 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005523#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005524#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005525 case TARGET_NR_pause:
5526 ret = get_errno(pause());
5527 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005528#endif
thse5febef2007-04-01 18:31:35 +00005529#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005530 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005531 {
pbrook53a59602006-03-25 19:31:22 +00005532 struct utimbuf tbuf, *host_tbuf;
5533 struct target_utimbuf *target_tbuf;
5534 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005535 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5536 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005537 tbuf.actime = tswapal(target_tbuf->actime);
5538 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005539 unlock_user_struct(target_tbuf, arg2, 0);
5540 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005541 } else {
pbrook53a59602006-03-25 19:31:22 +00005542 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005543 }
bellard579a97f2007-11-11 14:26:47 +00005544 if (!(p = lock_user_string(arg1)))
5545 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005546 ret = get_errno(utime(p, host_tbuf));
5547 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005548 }
5549 break;
thse5febef2007-04-01 18:31:35 +00005550#endif
bellard978a66f2004-12-06 22:58:05 +00005551 case TARGET_NR_utimes:
5552 {
bellard978a66f2004-12-06 22:58:05 +00005553 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005554 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005555 if (copy_from_user_timeval(&tv[0], arg2)
5556 || copy_from_user_timeval(&tv[1],
5557 arg2 + sizeof(struct target_timeval)))
5558 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005559 tvp = tv;
5560 } else {
5561 tvp = NULL;
5562 }
bellard579a97f2007-11-11 14:26:47 +00005563 if (!(p = lock_user_string(arg1)))
5564 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005565 ret = get_errno(utimes(p, tvp));
5566 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005567 }
5568 break;
balrogac8a6552008-09-20 02:25:39 +00005569#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5570 case TARGET_NR_futimesat:
5571 {
5572 struct timeval *tvp, tv[2];
5573 if (arg3) {
5574 if (copy_from_user_timeval(&tv[0], arg3)
5575 || copy_from_user_timeval(&tv[1],
5576 arg3 + sizeof(struct target_timeval)))
5577 goto efault;
5578 tvp = tv;
5579 } else {
5580 tvp = NULL;
5581 }
5582 if (!(p = lock_user_string(arg2)))
5583 goto efault;
5584 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5585 unlock_user(p, arg2, 0);
5586 }
5587 break;
5588#endif
bellardebc05482003-09-30 21:08:41 +00005589#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005590 case TARGET_NR_stty:
5591 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005592#endif
5593#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005594 case TARGET_NR_gtty:
5595 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005596#endif
bellard31e31b82003-02-18 22:55:36 +00005597 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005598 if (!(p = lock_user_string(arg1)))
5599 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005600 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005601 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005602 break;
ths92a34c12007-09-24 09:27:49 +00005603#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5604 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005605 if (!(p = lock_user_string(arg2)))
5606 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005607 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005608 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005609 break;
5610#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005611#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005612 case TARGET_NR_nice:
5613 ret = get_errno(nice(arg1));
5614 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005615#endif
bellardebc05482003-09-30 21:08:41 +00005616#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005617 case TARGET_NR_ftime:
5618 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005619#endif
bellard31e31b82003-02-18 22:55:36 +00005620 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005621 sync();
5622 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005623 break;
5624 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005625 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005626 break;
5627 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005628 {
5629 void *p2;
5630 p = lock_user_string(arg1);
5631 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005632 if (!p || !p2)
5633 ret = -TARGET_EFAULT;
5634 else
5635 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005636 unlock_user(p2, arg2, 0);
5637 unlock_user(p, arg1, 0);
5638 }
bellard31e31b82003-02-18 22:55:36 +00005639 break;
ths722183f2007-09-24 09:24:37 +00005640#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5641 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005642 {
bellard579a97f2007-11-11 14:26:47 +00005643 void *p2;
ths722183f2007-09-24 09:24:37 +00005644 p = lock_user_string(arg2);
5645 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005646 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005647 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005648 else
5649 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005650 unlock_user(p2, arg4, 0);
5651 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005652 }
5653 break;
5654#endif
bellard31e31b82003-02-18 22:55:36 +00005655 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005656 if (!(p = lock_user_string(arg1)))
5657 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005658 ret = get_errno(mkdir(p, arg2));
5659 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005660 break;
ths4472ad02007-09-24 09:22:32 +00005661#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5662 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005663 if (!(p = lock_user_string(arg2)))
5664 goto efault;
5665 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5666 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005667 break;
5668#endif
bellard31e31b82003-02-18 22:55:36 +00005669 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005670 if (!(p = lock_user_string(arg1)))
5671 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005672 ret = get_errno(rmdir(p));
5673 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005674 break;
5675 case TARGET_NR_dup:
5676 ret = get_errno(dup(arg1));
5677 break;
5678 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005679 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005680 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005681#ifdef TARGET_NR_pipe2
5682 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005683 ret = do_pipe(cpu_env, arg1,
5684 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005685 break;
5686#endif
bellard31e31b82003-02-18 22:55:36 +00005687 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005688 {
pbrook53a59602006-03-25 19:31:22 +00005689 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005690 struct tms tms;
5691 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005692 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005693 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5694 if (!tmsp)
5695 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005696 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5697 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5698 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5699 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005700 }
bellardc596ed12003-07-13 17:32:31 +00005701 if (!is_error(ret))
5702 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005703 }
5704 break;
bellardebc05482003-09-30 21:08:41 +00005705#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005706 case TARGET_NR_prof:
5707 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005708#endif
thse5febef2007-04-01 18:31:35 +00005709#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005710 case TARGET_NR_signal:
5711 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005712#endif
bellard31e31b82003-02-18 22:55:36 +00005713 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005714 if (arg1 == 0) {
5715 ret = get_errno(acct(NULL));
5716 } else {
5717 if (!(p = lock_user_string(arg1)))
5718 goto efault;
5719 ret = get_errno(acct(path(p)));
5720 unlock_user(p, arg1, 0);
5721 }
pbrook24836682006-04-16 14:14:53 +00005722 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005723#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005724 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005725 if (!(p = lock_user_string(arg1)))
5726 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005727 ret = get_errno(umount2(p, arg2));
5728 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005729 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005730#endif
bellardebc05482003-09-30 21:08:41 +00005731#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005732 case TARGET_NR_lock:
5733 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005734#endif
bellard31e31b82003-02-18 22:55:36 +00005735 case TARGET_NR_ioctl:
5736 ret = do_ioctl(arg1, arg2, arg3);
5737 break;
5738 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005739 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005740 break;
bellardebc05482003-09-30 21:08:41 +00005741#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005742 case TARGET_NR_mpx:
5743 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005744#endif
bellard31e31b82003-02-18 22:55:36 +00005745 case TARGET_NR_setpgid:
5746 ret = get_errno(setpgid(arg1, arg2));
5747 break;
bellardebc05482003-09-30 21:08:41 +00005748#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005749 case TARGET_NR_ulimit:
5750 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005751#endif
5752#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005753 case TARGET_NR_oldolduname:
5754 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005755#endif
bellard31e31b82003-02-18 22:55:36 +00005756 case TARGET_NR_umask:
5757 ret = get_errno(umask(arg1));
5758 break;
5759 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005760 if (!(p = lock_user_string(arg1)))
5761 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005762 ret = get_errno(chroot(p));
5763 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005764 break;
5765 case TARGET_NR_ustat:
5766 goto unimplemented;
5767 case TARGET_NR_dup2:
5768 ret = get_errno(dup2(arg1, arg2));
5769 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005770#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5771 case TARGET_NR_dup3:
5772 ret = get_errno(dup3(arg1, arg2, arg3));
5773 break;
5774#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005775#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005776 case TARGET_NR_getppid:
5777 ret = get_errno(getppid());
5778 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005779#endif
bellard31e31b82003-02-18 22:55:36 +00005780 case TARGET_NR_getpgrp:
5781 ret = get_errno(getpgrp());
5782 break;
5783 case TARGET_NR_setsid:
5784 ret = get_errno(setsid());
5785 break;
thse5febef2007-04-01 18:31:35 +00005786#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005787 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005788 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005789#if defined(TARGET_ALPHA)
5790 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005791 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005792 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005793 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5794 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005795 act._sa_handler = old_act->_sa_handler;
5796 target_siginitset(&act.sa_mask, old_act->sa_mask);
5797 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005798 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005799 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005800 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005801 }
5802 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005803 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005804 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5805 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005806 old_act->_sa_handler = oact._sa_handler;
5807 old_act->sa_mask = oact.sa_mask.sig[0];
5808 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005809 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005810 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005811#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005812 struct target_sigaction act, oact, *pact, *old_act;
5813
5814 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005815 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5816 goto efault;
bellard106ec872006-06-27 21:08:10 +00005817 act._sa_handler = old_act->_sa_handler;
5818 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5819 act.sa_flags = old_act->sa_flags;
5820 unlock_user_struct(old_act, arg2, 0);
5821 pact = &act;
5822 } else {
5823 pact = NULL;
5824 }
5825
5826 ret = get_errno(do_sigaction(arg1, pact, &oact));
5827
5828 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005829 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5830 goto efault;
bellard106ec872006-06-27 21:08:10 +00005831 old_act->_sa_handler = oact._sa_handler;
5832 old_act->sa_flags = oact.sa_flags;
5833 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5834 old_act->sa_mask.sig[1] = 0;
5835 old_act->sa_mask.sig[2] = 0;
5836 old_act->sa_mask.sig[3] = 0;
5837 unlock_user_struct(old_act, arg3, 1);
5838 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005839#else
5840 struct target_old_sigaction *old_act;
5841 struct target_sigaction act, oact, *pact;
5842 if (arg2) {
5843 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5844 goto efault;
5845 act._sa_handler = old_act->_sa_handler;
5846 target_siginitset(&act.sa_mask, old_act->sa_mask);
5847 act.sa_flags = old_act->sa_flags;
5848 act.sa_restorer = old_act->sa_restorer;
5849 unlock_user_struct(old_act, arg2, 0);
5850 pact = &act;
5851 } else {
5852 pact = NULL;
5853 }
5854 ret = get_errno(do_sigaction(arg1, pact, &oact));
5855 if (!is_error(ret) && arg3) {
5856 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5857 goto efault;
5858 old_act->_sa_handler = oact._sa_handler;
5859 old_act->sa_mask = oact.sa_mask.sig[0];
5860 old_act->sa_flags = oact.sa_flags;
5861 old_act->sa_restorer = oact.sa_restorer;
5862 unlock_user_struct(old_act, arg3, 1);
5863 }
ths388bb212007-05-13 13:58:00 +00005864#endif
bellard31e31b82003-02-18 22:55:36 +00005865 }
5866 break;
thse5febef2007-04-01 18:31:35 +00005867#endif
bellard66fb9762003-03-23 01:06:05 +00005868 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005869 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005870#if defined(TARGET_ALPHA)
5871 struct target_sigaction act, oact, *pact = 0;
5872 struct target_rt_sigaction *rt_act;
5873 /* ??? arg4 == sizeof(sigset_t). */
5874 if (arg2) {
5875 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5876 goto efault;
5877 act._sa_handler = rt_act->_sa_handler;
5878 act.sa_mask = rt_act->sa_mask;
5879 act.sa_flags = rt_act->sa_flags;
5880 act.sa_restorer = arg5;
5881 unlock_user_struct(rt_act, arg2, 0);
5882 pact = &act;
5883 }
5884 ret = get_errno(do_sigaction(arg1, pact, &oact));
5885 if (!is_error(ret) && arg3) {
5886 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5887 goto efault;
5888 rt_act->_sa_handler = oact._sa_handler;
5889 rt_act->sa_mask = oact.sa_mask;
5890 rt_act->sa_flags = oact.sa_flags;
5891 unlock_user_struct(rt_act, arg3, 1);
5892 }
5893#else
pbrook53a59602006-03-25 19:31:22 +00005894 struct target_sigaction *act;
5895 struct target_sigaction *oact;
5896
bellard579a97f2007-11-11 14:26:47 +00005897 if (arg2) {
5898 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5899 goto efault;
5900 } else
pbrook53a59602006-03-25 19:31:22 +00005901 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005902 if (arg3) {
5903 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5904 ret = -TARGET_EFAULT;
5905 goto rt_sigaction_fail;
5906 }
5907 } else
pbrook53a59602006-03-25 19:31:22 +00005908 oact = NULL;
5909 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005910 rt_sigaction_fail:
5911 if (act)
pbrook53a59602006-03-25 19:31:22 +00005912 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005913 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005914 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005915#endif
pbrook53a59602006-03-25 19:31:22 +00005916 }
bellard66fb9762003-03-23 01:06:05 +00005917 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005918#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005919 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005920 {
5921 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005922 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005923 sigprocmask(0, NULL, &cur_set);
5924 host_to_target_old_sigset(&target_set, &cur_set);
5925 ret = target_set;
5926 }
5927 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005928#endif
5929#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005930 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005931 {
5932 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005933 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005934 sigprocmask(0, NULL, &cur_set);
5935 target_to_host_old_sigset(&set, &target_set);
5936 sigorset(&set, &set, &cur_set);
5937 sigprocmask(SIG_SETMASK, &set, &oset);
5938 host_to_target_old_sigset(&target_set, &oset);
5939 ret = target_set;
5940 }
5941 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005942#endif
thse5febef2007-04-01 18:31:35 +00005943#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005944 case TARGET_NR_sigprocmask:
5945 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005946#if defined(TARGET_ALPHA)
5947 sigset_t set, oldset;
5948 abi_ulong mask;
5949 int how;
5950
5951 switch (arg1) {
5952 case TARGET_SIG_BLOCK:
5953 how = SIG_BLOCK;
5954 break;
5955 case TARGET_SIG_UNBLOCK:
5956 how = SIG_UNBLOCK;
5957 break;
5958 case TARGET_SIG_SETMASK:
5959 how = SIG_SETMASK;
5960 break;
5961 default:
5962 ret = -TARGET_EINVAL;
5963 goto fail;
5964 }
5965 mask = arg2;
5966 target_to_host_old_sigset(&set, &mask);
5967
5968 ret = get_errno(sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07005969 if (!is_error(ret)) {
5970 host_to_target_old_sigset(&mask, &oldset);
5971 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07005972 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07005973 }
5974#else
bellard66fb9762003-03-23 01:06:05 +00005975 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005976 int how;
ths3b46e622007-09-17 08:09:54 +00005977
pbrook53a59602006-03-25 19:31:22 +00005978 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005979 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005980 case TARGET_SIG_BLOCK:
5981 how = SIG_BLOCK;
5982 break;
5983 case TARGET_SIG_UNBLOCK:
5984 how = SIG_UNBLOCK;
5985 break;
5986 case TARGET_SIG_SETMASK:
5987 how = SIG_SETMASK;
5988 break;
5989 default:
ths0da46a62007-10-20 20:23:07 +00005990 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005991 goto fail;
5992 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005993 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005994 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005995 target_to_host_old_sigset(&set, p);
5996 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005997 set_ptr = &set;
5998 } else {
5999 how = 0;
6000 set_ptr = NULL;
6001 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006002 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006003 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006004 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006005 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006006 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006007 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006008 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006009#endif
bellard66fb9762003-03-23 01:06:05 +00006010 }
6011 break;
thse5febef2007-04-01 18:31:35 +00006012#endif
bellard66fb9762003-03-23 01:06:05 +00006013 case TARGET_NR_rt_sigprocmask:
6014 {
6015 int how = arg1;
6016 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006017
pbrook53a59602006-03-25 19:31:22 +00006018 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006019 switch(how) {
6020 case TARGET_SIG_BLOCK:
6021 how = SIG_BLOCK;
6022 break;
6023 case TARGET_SIG_UNBLOCK:
6024 how = SIG_UNBLOCK;
6025 break;
6026 case TARGET_SIG_SETMASK:
6027 how = SIG_SETMASK;
6028 break;
6029 default:
ths0da46a62007-10-20 20:23:07 +00006030 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006031 goto fail;
6032 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006033 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006034 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006035 target_to_host_sigset(&set, p);
6036 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006037 set_ptr = &set;
6038 } else {
6039 how = 0;
6040 set_ptr = NULL;
6041 }
6042 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006043 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006044 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006045 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006046 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006047 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006048 }
6049 }
6050 break;
thse5febef2007-04-01 18:31:35 +00006051#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006052 case TARGET_NR_sigpending:
6053 {
6054 sigset_t set;
6055 ret = get_errno(sigpending(&set));
6056 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006057 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006058 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006059 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006060 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006061 }
6062 }
6063 break;
thse5febef2007-04-01 18:31:35 +00006064#endif
bellard66fb9762003-03-23 01:06:05 +00006065 case TARGET_NR_rt_sigpending:
6066 {
6067 sigset_t set;
6068 ret = get_errno(sigpending(&set));
6069 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006070 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006071 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006072 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006073 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006074 }
6075 }
6076 break;
thse5febef2007-04-01 18:31:35 +00006077#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006078 case TARGET_NR_sigsuspend:
6079 {
6080 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006081#if defined(TARGET_ALPHA)
6082 abi_ulong mask = arg1;
6083 target_to_host_old_sigset(&set, &mask);
6084#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006085 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006086 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006087 target_to_host_old_sigset(&set, p);
6088 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006089#endif
bellard66fb9762003-03-23 01:06:05 +00006090 ret = get_errno(sigsuspend(&set));
6091 }
6092 break;
thse5febef2007-04-01 18:31:35 +00006093#endif
bellard66fb9762003-03-23 01:06:05 +00006094 case TARGET_NR_rt_sigsuspend:
6095 {
6096 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006097 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006098 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006099 target_to_host_sigset(&set, p);
6100 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006101 ret = get_errno(sigsuspend(&set));
6102 }
6103 break;
6104 case TARGET_NR_rt_sigtimedwait:
6105 {
bellard66fb9762003-03-23 01:06:05 +00006106 sigset_t set;
6107 struct timespec uts, *puts;
6108 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006109
Anthony Liguoric227f092009-10-01 16:12:16 -05006110 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006111 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006112 target_to_host_sigset(&set, p);
6113 unlock_user(p, arg1, 0);
6114 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006115 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006116 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006117 } else {
6118 puts = NULL;
6119 }
6120 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00006121 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006122 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006123 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006124 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05006125 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00006126 }
6127 }
6128 break;
6129 case TARGET_NR_rt_sigqueueinfo:
6130 {
6131 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006132 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006133 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006134 target_to_host_siginfo(&uinfo, p);
6135 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006136 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6137 }
6138 break;
thse5febef2007-04-01 18:31:35 +00006139#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006140 case TARGET_NR_sigreturn:
6141 /* NOTE: ret is eax, so not transcoding must be done */
6142 ret = do_sigreturn(cpu_env);
6143 break;
thse5febef2007-04-01 18:31:35 +00006144#endif
bellard66fb9762003-03-23 01:06:05 +00006145 case TARGET_NR_rt_sigreturn:
6146 /* NOTE: ret is eax, so not transcoding must be done */
6147 ret = do_rt_sigreturn(cpu_env);
6148 break;
bellard31e31b82003-02-18 22:55:36 +00006149 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006150 if (!(p = lock_user_string(arg1)))
6151 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006152 ret = get_errno(sethostname(p, arg2));
6153 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006154 break;
6155 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006156 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006157 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006158 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006159 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006160 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6161 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006162 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6163 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006164 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006165 ret = get_errno(setrlimit(resource, &rlim));
6166 }
6167 break;
bellard31e31b82003-02-18 22:55:36 +00006168 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006169 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006170 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006171 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006172 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006173
bellard9de5e442003-03-23 16:49:39 +00006174 ret = get_errno(getrlimit(resource, &rlim));
6175 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006176 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6177 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006178 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6179 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006180 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006181 }
6182 }
6183 break;
bellard31e31b82003-02-18 22:55:36 +00006184 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006185 {
6186 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006187 ret = get_errno(getrusage(arg1, &rusage));
6188 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006189 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006190 }
6191 }
6192 break;
bellard31e31b82003-02-18 22:55:36 +00006193 case TARGET_NR_gettimeofday:
6194 {
bellard31e31b82003-02-18 22:55:36 +00006195 struct timeval tv;
6196 ret = get_errno(gettimeofday(&tv, NULL));
6197 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006198 if (copy_to_user_timeval(arg1, &tv))
6199 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006200 }
6201 }
6202 break;
6203 case TARGET_NR_settimeofday:
6204 {
bellard31e31b82003-02-18 22:55:36 +00006205 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006206 if (copy_from_user_timeval(&tv, arg1))
6207 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006208 ret = get_errno(settimeofday(&tv, NULL));
6209 }
6210 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006211#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00006212 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00006213 {
pbrook53a59602006-03-25 19:31:22 +00006214 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006215 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006216 long nsel;
6217
bellard579a97f2007-11-11 14:26:47 +00006218 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6219 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006220 nsel = tswapal(sel->n);
6221 inp = tswapal(sel->inp);
6222 outp = tswapal(sel->outp);
6223 exp = tswapal(sel->exp);
6224 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006225 unlock_user_struct(sel, arg1, 0);
6226 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006227 }
6228 break;
bellard048f6b42005-11-26 18:47:20 +00006229#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006230#ifdef TARGET_NR_pselect6
6231 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006232 {
6233 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6234 fd_set rfds, wfds, efds;
6235 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6236 struct timespec ts, *ts_ptr;
6237
6238 /*
6239 * The 6th arg is actually two args smashed together,
6240 * so we cannot use the C library.
6241 */
6242 sigset_t set;
6243 struct {
6244 sigset_t *set;
6245 size_t size;
6246 } sig, *sig_ptr;
6247
6248 abi_ulong arg_sigset, arg_sigsize, *arg7;
6249 target_sigset_t *target_sigset;
6250
6251 n = arg1;
6252 rfd_addr = arg2;
6253 wfd_addr = arg3;
6254 efd_addr = arg4;
6255 ts_addr = arg5;
6256
6257 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6258 if (ret) {
6259 goto fail;
6260 }
6261 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6262 if (ret) {
6263 goto fail;
6264 }
6265 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6266 if (ret) {
6267 goto fail;
6268 }
6269
6270 /*
6271 * This takes a timespec, and not a timeval, so we cannot
6272 * use the do_select() helper ...
6273 */
6274 if (ts_addr) {
6275 if (target_to_host_timespec(&ts, ts_addr)) {
6276 goto efault;
6277 }
6278 ts_ptr = &ts;
6279 } else {
6280 ts_ptr = NULL;
6281 }
6282
6283 /* Extract the two packed args for the sigset */
6284 if (arg6) {
6285 sig_ptr = &sig;
6286 sig.size = _NSIG / 8;
6287
6288 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6289 if (!arg7) {
6290 goto efault;
6291 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006292 arg_sigset = tswapal(arg7[0]);
6293 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006294 unlock_user(arg7, arg6, 0);
6295
6296 if (arg_sigset) {
6297 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006298 if (arg_sigsize != sizeof(*target_sigset)) {
6299 /* Like the kernel, we enforce correct size sigsets */
6300 ret = -TARGET_EINVAL;
6301 goto fail;
6302 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006303 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6304 sizeof(*target_sigset), 1);
6305 if (!target_sigset) {
6306 goto efault;
6307 }
6308 target_to_host_sigset(&set, target_sigset);
6309 unlock_user(target_sigset, arg_sigset, 0);
6310 } else {
6311 sig.set = NULL;
6312 }
6313 } else {
6314 sig_ptr = NULL;
6315 }
6316
6317 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6318 ts_ptr, sig_ptr));
6319
6320 if (!is_error(ret)) {
6321 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6322 goto efault;
6323 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6324 goto efault;
6325 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6326 goto efault;
6327
6328 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6329 goto efault;
6330 }
6331 }
6332 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006333#endif
bellard31e31b82003-02-18 22:55:36 +00006334 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006335 {
6336 void *p2;
6337 p = lock_user_string(arg1);
6338 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006339 if (!p || !p2)
6340 ret = -TARGET_EFAULT;
6341 else
6342 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006343 unlock_user(p2, arg2, 0);
6344 unlock_user(p, arg1, 0);
6345 }
bellard31e31b82003-02-18 22:55:36 +00006346 break;
thsf0b62432007-09-24 09:25:40 +00006347#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
6348 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006349 {
bellard579a97f2007-11-11 14:26:47 +00006350 void *p2;
thsf0b62432007-09-24 09:25:40 +00006351 p = lock_user_string(arg1);
6352 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006353 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006354 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006355 else
6356 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006357 unlock_user(p2, arg3, 0);
6358 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006359 }
6360 break;
6361#endif
bellardebc05482003-09-30 21:08:41 +00006362#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006363 case TARGET_NR_oldlstat:
6364 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006365#endif
bellard31e31b82003-02-18 22:55:36 +00006366 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006367 {
aurel32d088d662009-01-30 20:09:01 +00006368 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006369 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006370 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6371 if (!p || !p2)
6372 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006373 else {
6374 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6375 char real[PATH_MAX];
6376 temp = realpath(exec_path,real);
6377 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6378 snprintf((char *)p2, arg3, "%s", real);
6379 }
6380 else
6381 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006382 }
pbrook53a59602006-03-25 19:31:22 +00006383 unlock_user(p2, arg2, ret);
6384 unlock_user(p, arg1, 0);
6385 }
bellard31e31b82003-02-18 22:55:36 +00006386 break;
ths5e0ccb12007-09-24 09:26:10 +00006387#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
6388 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006389 {
bellard579a97f2007-11-11 14:26:47 +00006390 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006391 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006392 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6393 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006394 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006395 else
6396 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006397 unlock_user(p2, arg3, ret);
6398 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006399 }
6400 break;
6401#endif
thse5febef2007-04-01 18:31:35 +00006402#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006403 case TARGET_NR_uselib:
6404 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006405#endif
6406#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006407 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006408 if (!(p = lock_user_string(arg1)))
6409 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006410 ret = get_errno(swapon(p, arg2));
6411 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006412 break;
thse5febef2007-04-01 18:31:35 +00006413#endif
bellard31e31b82003-02-18 22:55:36 +00006414 case TARGET_NR_reboot:
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006415 if (!(p = lock_user_string(arg4)))
6416 goto efault;
6417 ret = reboot(arg1, arg2, arg3, p);
6418 unlock_user(p, arg4, 0);
6419 break;
thse5febef2007-04-01 18:31:35 +00006420#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006421 case TARGET_NR_readdir:
6422 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006423#endif
6424#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006425 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006426#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6427 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6428 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006429 {
blueswir1992f48a2007-10-14 16:27:31 +00006430 abi_ulong *v;
6431 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006432 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6433 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006434 v1 = tswapal(v[0]);
6435 v2 = tswapal(v[1]);
6436 v3 = tswapal(v[2]);
6437 v4 = tswapal(v[3]);
6438 v5 = tswapal(v[4]);
6439 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006440 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006441 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006442 target_to_host_bitmask(v4, mmap_flags_tbl),
6443 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006444 }
bellard31e31b82003-02-18 22:55:36 +00006445#else
ths5fafdf22007-09-16 21:08:06 +00006446 ret = get_errno(target_mmap(arg1, arg2, arg3,
6447 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006448 arg5,
6449 arg6));
bellard31e31b82003-02-18 22:55:36 +00006450#endif
bellard6fb883e2003-07-09 17:12:39 +00006451 break;
thse5febef2007-04-01 18:31:35 +00006452#endif
bellarda315a142005-01-30 22:59:18 +00006453#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006454 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006455#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006456#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006457#endif
ths5fafdf22007-09-16 21:08:06 +00006458 ret = get_errno(target_mmap(arg1, arg2, arg3,
6459 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006460 arg5,
bellardc573ff62004-01-04 15:51:36 +00006461 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006462 break;
bellarda315a142005-01-30 22:59:18 +00006463#endif
bellard31e31b82003-02-18 22:55:36 +00006464 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006465 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006466 break;
bellard9de5e442003-03-23 16:49:39 +00006467 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006468 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006469 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006470 /* Special hack to detect libc making the stack executable. */
6471 if ((arg3 & PROT_GROWSDOWN)
6472 && arg1 >= ts->info->stack_limit
6473 && arg1 <= ts->info->start_stack) {
6474 arg3 &= ~PROT_GROWSDOWN;
6475 arg2 = arg2 + arg1 - ts->info->stack_limit;
6476 arg1 = ts->info->stack_limit;
6477 }
6478 }
bellard54936002003-05-13 00:25:15 +00006479 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006480 break;
thse5febef2007-04-01 18:31:35 +00006481#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006482 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006483 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006484 break;
thse5febef2007-04-01 18:31:35 +00006485#endif
pbrook53a59602006-03-25 19:31:22 +00006486 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006487#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006488 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006489 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006490 break;
thse5febef2007-04-01 18:31:35 +00006491#endif
6492#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006493 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006494 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006495 break;
thse5febef2007-04-01 18:31:35 +00006496#endif
6497#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006498 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006499 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006500 break;
thse5febef2007-04-01 18:31:35 +00006501#endif
6502#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006503 case TARGET_NR_mlockall:
6504 ret = get_errno(mlockall(arg1));
6505 break;
thse5febef2007-04-01 18:31:35 +00006506#endif
6507#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006508 case TARGET_NR_munlockall:
6509 ret = get_errno(munlockall());
6510 break;
thse5febef2007-04-01 18:31:35 +00006511#endif
bellard31e31b82003-02-18 22:55:36 +00006512 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006513 if (!(p = lock_user_string(arg1)))
6514 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006515 ret = get_errno(truncate(p, arg2));
6516 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006517 break;
6518 case TARGET_NR_ftruncate:
6519 ret = get_errno(ftruncate(arg1, arg2));
6520 break;
6521 case TARGET_NR_fchmod:
6522 ret = get_errno(fchmod(arg1, arg2));
6523 break;
ths814d7972007-09-24 09:26:51 +00006524#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
6525 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006526 if (!(p = lock_user_string(arg2)))
6527 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00006528 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006529 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006530 break;
6531#endif
bellard31e31b82003-02-18 22:55:36 +00006532 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006533 /* Note that negative values are valid for getpriority, so we must
6534 differentiate based on errno settings. */
6535 errno = 0;
6536 ret = getpriority(arg1, arg2);
6537 if (ret == -1 && errno != 0) {
6538 ret = -host_to_target_errno(errno);
6539 break;
6540 }
6541#ifdef TARGET_ALPHA
6542 /* Return value is the unbiased priority. Signal no error. */
6543 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6544#else
6545 /* Return value is a biased priority to avoid negative numbers. */
6546 ret = 20 - ret;
6547#endif
bellard31e31b82003-02-18 22:55:36 +00006548 break;
6549 case TARGET_NR_setpriority:
6550 ret = get_errno(setpriority(arg1, arg2, arg3));
6551 break;
bellardebc05482003-09-30 21:08:41 +00006552#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006553 case TARGET_NR_profil:
6554 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006555#endif
bellard31e31b82003-02-18 22:55:36 +00006556 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006557 if (!(p = lock_user_string(arg1)))
6558 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006559 ret = get_errno(statfs(path(p), &stfs));
6560 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006561 convert_statfs:
6562 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006563 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006564
bellard579a97f2007-11-11 14:26:47 +00006565 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6566 goto efault;
6567 __put_user(stfs.f_type, &target_stfs->f_type);
6568 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6569 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6570 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6571 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6572 __put_user(stfs.f_files, &target_stfs->f_files);
6573 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6574 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6575 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6576 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006577 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6578 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006579 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006580 }
6581 break;
6582 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006583 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006584 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006585#ifdef TARGET_NR_statfs64
6586 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006587 if (!(p = lock_user_string(arg1)))
6588 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006589 ret = get_errno(statfs(path(p), &stfs));
6590 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006591 convert_statfs64:
6592 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006593 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006594
bellard579a97f2007-11-11 14:26:47 +00006595 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6596 goto efault;
6597 __put_user(stfs.f_type, &target_stfs->f_type);
6598 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6599 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6600 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6601 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6602 __put_user(stfs.f_files, &target_stfs->f_files);
6603 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6604 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6605 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6606 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006607 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6608 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006609 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006610 }
6611 break;
6612 case TARGET_NR_fstatfs64:
6613 ret = get_errno(fstatfs(arg1, &stfs));
6614 goto convert_statfs64;
6615#endif
bellardebc05482003-09-30 21:08:41 +00006616#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006617 case TARGET_NR_ioperm:
6618 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006619#endif
thse5febef2007-04-01 18:31:35 +00006620#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006621 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006622 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006623 break;
thse5febef2007-04-01 18:31:35 +00006624#endif
bellard3532fa72006-06-24 15:06:03 +00006625#ifdef TARGET_NR_accept
6626 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006627 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006628 break;
6629#endif
6630#ifdef TARGET_NR_bind
6631 case TARGET_NR_bind:
6632 ret = do_bind(arg1, arg2, arg3);
6633 break;
6634#endif
6635#ifdef TARGET_NR_connect
6636 case TARGET_NR_connect:
6637 ret = do_connect(arg1, arg2, arg3);
6638 break;
6639#endif
6640#ifdef TARGET_NR_getpeername
6641 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006642 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006643 break;
6644#endif
6645#ifdef TARGET_NR_getsockname
6646 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006647 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006648 break;
6649#endif
6650#ifdef TARGET_NR_getsockopt
6651 case TARGET_NR_getsockopt:
6652 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6653 break;
6654#endif
6655#ifdef TARGET_NR_listen
6656 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006657 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006658 break;
6659#endif
6660#ifdef TARGET_NR_recv
6661 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006662 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006663 break;
6664#endif
6665#ifdef TARGET_NR_recvfrom
6666 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006667 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006668 break;
6669#endif
6670#ifdef TARGET_NR_recvmsg
6671 case TARGET_NR_recvmsg:
6672 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6673 break;
6674#endif
6675#ifdef TARGET_NR_send
6676 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006677 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006678 break;
6679#endif
6680#ifdef TARGET_NR_sendmsg
6681 case TARGET_NR_sendmsg:
6682 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6683 break;
6684#endif
6685#ifdef TARGET_NR_sendto
6686 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006687 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006688 break;
6689#endif
6690#ifdef TARGET_NR_shutdown
6691 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006692 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006693 break;
6694#endif
6695#ifdef TARGET_NR_socket
6696 case TARGET_NR_socket:
6697 ret = do_socket(arg1, arg2, arg3);
6698 break;
6699#endif
6700#ifdef TARGET_NR_socketpair
6701 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006702 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006703 break;
6704#endif
6705#ifdef TARGET_NR_setsockopt
6706 case TARGET_NR_setsockopt:
6707 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6708 break;
6709#endif
ths7494b0f2007-02-11 18:26:53 +00006710
bellard31e31b82003-02-18 22:55:36 +00006711 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006712 if (!(p = lock_user_string(arg2)))
6713 goto efault;
thse5574482007-02-11 20:03:13 +00006714 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6715 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006716 break;
6717
bellard31e31b82003-02-18 22:55:36 +00006718 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006719 {
bellard66fb9762003-03-23 01:06:05 +00006720 struct itimerval value, ovalue, *pvalue;
6721
pbrook53a59602006-03-25 19:31:22 +00006722 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006723 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006724 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6725 || copy_from_user_timeval(&pvalue->it_value,
6726 arg2 + sizeof(struct target_timeval)))
6727 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006728 } else {
6729 pvalue = NULL;
6730 }
6731 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006732 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006733 if (copy_to_user_timeval(arg3,
6734 &ovalue.it_interval)
6735 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6736 &ovalue.it_value))
6737 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006738 }
6739 }
6740 break;
bellard31e31b82003-02-18 22:55:36 +00006741 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006742 {
bellard66fb9762003-03-23 01:06:05 +00006743 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006744
bellard66fb9762003-03-23 01:06:05 +00006745 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006746 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006747 if (copy_to_user_timeval(arg2,
6748 &value.it_interval)
6749 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6750 &value.it_value))
6751 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006752 }
6753 }
6754 break;
bellard31e31b82003-02-18 22:55:36 +00006755 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006756 if (!(p = lock_user_string(arg1)))
6757 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006758 ret = get_errno(stat(path(p), &st));
6759 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006760 goto do_stat;
6761 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006762 if (!(p = lock_user_string(arg1)))
6763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006764 ret = get_errno(lstat(path(p), &st));
6765 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006766 goto do_stat;
6767 case TARGET_NR_fstat:
6768 {
6769 ret = get_errno(fstat(arg1, &st));
6770 do_stat:
6771 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006772 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006773
bellard579a97f2007-11-11 14:26:47 +00006774 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6775 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006776 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006777 __put_user(st.st_dev, &target_st->st_dev);
6778 __put_user(st.st_ino, &target_st->st_ino);
6779 __put_user(st.st_mode, &target_st->st_mode);
6780 __put_user(st.st_uid, &target_st->st_uid);
6781 __put_user(st.st_gid, &target_st->st_gid);
6782 __put_user(st.st_nlink, &target_st->st_nlink);
6783 __put_user(st.st_rdev, &target_st->st_rdev);
6784 __put_user(st.st_size, &target_st->st_size);
6785 __put_user(st.st_blksize, &target_st->st_blksize);
6786 __put_user(st.st_blocks, &target_st->st_blocks);
6787 __put_user(st.st_atime, &target_st->target_st_atime);
6788 __put_user(st.st_mtime, &target_st->target_st_mtime);
6789 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006790 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006791 }
6792 }
6793 break;
bellardebc05482003-09-30 21:08:41 +00006794#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006795 case TARGET_NR_olduname:
6796 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006797#endif
6798#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006799 case TARGET_NR_iopl:
6800 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006801#endif
bellard31e31b82003-02-18 22:55:36 +00006802 case TARGET_NR_vhangup:
6803 ret = get_errno(vhangup());
6804 break;
bellardebc05482003-09-30 21:08:41 +00006805#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006806 case TARGET_NR_idle:
6807 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006808#endif
bellard42ad6ae2005-01-03 22:48:11 +00006809#ifdef TARGET_NR_syscall
6810 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006811 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6812 arg6, arg7, arg8, 0);
6813 break;
bellard42ad6ae2005-01-03 22:48:11 +00006814#endif
bellard31e31b82003-02-18 22:55:36 +00006815 case TARGET_NR_wait4:
6816 {
6817 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006818 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006819 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006820 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006821 if (target_rusage)
6822 rusage_ptr = &rusage;
6823 else
6824 rusage_ptr = NULL;
6825 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6826 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006827 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006828 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006829 if (put_user_s32(status, status_ptr))
6830 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006831 }
bellard2f619692007-11-16 10:46:05 +00006832 if (target_rusage)
6833 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006834 }
6835 }
6836 break;
thse5febef2007-04-01 18:31:35 +00006837#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006838 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006839 if (!(p = lock_user_string(arg1)))
6840 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006841 ret = get_errno(swapoff(p));
6842 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006843 break;
thse5febef2007-04-01 18:31:35 +00006844#endif
bellard31e31b82003-02-18 22:55:36 +00006845 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006846 {
pbrook53a59602006-03-25 19:31:22 +00006847 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006848 struct sysinfo value;
6849 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006850 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006851 {
bellard579a97f2007-11-11 14:26:47 +00006852 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6853 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006854 __put_user(value.uptime, &target_value->uptime);
6855 __put_user(value.loads[0], &target_value->loads[0]);
6856 __put_user(value.loads[1], &target_value->loads[1]);
6857 __put_user(value.loads[2], &target_value->loads[2]);
6858 __put_user(value.totalram, &target_value->totalram);
6859 __put_user(value.freeram, &target_value->freeram);
6860 __put_user(value.sharedram, &target_value->sharedram);
6861 __put_user(value.bufferram, &target_value->bufferram);
6862 __put_user(value.totalswap, &target_value->totalswap);
6863 __put_user(value.freeswap, &target_value->freeswap);
6864 __put_user(value.procs, &target_value->procs);
6865 __put_user(value.totalhigh, &target_value->totalhigh);
6866 __put_user(value.freehigh, &target_value->freehigh);
6867 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006868 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006869 }
6870 }
6871 break;
thse5febef2007-04-01 18:31:35 +00006872#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006873 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006874 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6875 break;
thse5febef2007-04-01 18:31:35 +00006876#endif
aurel32e5289082009-04-18 16:16:12 +00006877#ifdef TARGET_NR_semget
6878 case TARGET_NR_semget:
6879 ret = get_errno(semget(arg1, arg2, arg3));
6880 break;
6881#endif
6882#ifdef TARGET_NR_semop
6883 case TARGET_NR_semop:
6884 ret = get_errno(do_semop(arg1, arg2, arg3));
6885 break;
6886#endif
6887#ifdef TARGET_NR_semctl
6888 case TARGET_NR_semctl:
6889 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6890 break;
6891#endif
aurel32eeb438c2008-10-13 21:08:55 +00006892#ifdef TARGET_NR_msgctl
6893 case TARGET_NR_msgctl:
6894 ret = do_msgctl(arg1, arg2, arg3);
6895 break;
6896#endif
6897#ifdef TARGET_NR_msgget
6898 case TARGET_NR_msgget:
6899 ret = get_errno(msgget(arg1, arg2));
6900 break;
6901#endif
6902#ifdef TARGET_NR_msgrcv
6903 case TARGET_NR_msgrcv:
6904 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6905 break;
6906#endif
6907#ifdef TARGET_NR_msgsnd
6908 case TARGET_NR_msgsnd:
6909 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6910 break;
6911#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006912#ifdef TARGET_NR_shmget
6913 case TARGET_NR_shmget:
6914 ret = get_errno(shmget(arg1, arg2, arg3));
6915 break;
6916#endif
6917#ifdef TARGET_NR_shmctl
6918 case TARGET_NR_shmctl:
6919 ret = do_shmctl(arg1, arg2, arg3);
6920 break;
6921#endif
6922#ifdef TARGET_NR_shmat
6923 case TARGET_NR_shmat:
6924 ret = do_shmat(arg1, arg2, arg3);
6925 break;
6926#endif
6927#ifdef TARGET_NR_shmdt
6928 case TARGET_NR_shmdt:
6929 ret = do_shmdt(arg1);
6930 break;
6931#endif
bellard31e31b82003-02-18 22:55:36 +00006932 case TARGET_NR_fsync:
6933 ret = get_errno(fsync(arg1));
6934 break;
bellard31e31b82003-02-18 22:55:36 +00006935 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006936#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006937 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006938#elif defined(TARGET_CRIS)
6939 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006940#elif defined(TARGET_S390X)
6941 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006942#else
pbrookd865bab2008-06-07 22:12:17 +00006943 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006944#endif
bellard1b6b0292003-03-22 17:31:38 +00006945 break;
bellardec86b0f2003-04-11 00:15:04 +00006946#ifdef __NR_exit_group
6947 /* new thread calls */
6948 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006949#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006950 _mcleanup();
6951#endif
bellarde9009672005-04-26 20:42:36 +00006952 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006953 ret = get_errno(exit_group(arg1));
6954 break;
6955#endif
bellard31e31b82003-02-18 22:55:36 +00006956 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006957 if (!(p = lock_user_string(arg1)))
6958 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006959 ret = get_errno(setdomainname(p, arg2));
6960 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006961 break;
6962 case TARGET_NR_uname:
6963 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006964 {
6965 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006966
bellard579a97f2007-11-11 14:26:47 +00006967 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6968 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006969 ret = get_errno(sys_uname(buf));
6970 if (!is_error(ret)) {
6971 /* Overrite the native machine name with whatever is being
6972 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006973 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006974 /* Allow the user to override the reported release. */
6975 if (qemu_uname_release && *qemu_uname_release)
6976 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006977 }
pbrook53a59602006-03-25 19:31:22 +00006978 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006979 }
bellard31e31b82003-02-18 22:55:36 +00006980 break;
bellard6dbad632003-03-16 18:05:05 +00006981#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006982 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006983 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006984 break;
j_mayer84409dd2007-04-06 08:56:50 +00006985#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006986 case TARGET_NR_vm86old:
6987 goto unimplemented;
6988 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006989 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006990 break;
6991#endif
j_mayer84409dd2007-04-06 08:56:50 +00006992#endif
bellard31e31b82003-02-18 22:55:36 +00006993 case TARGET_NR_adjtimex:
6994 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006995#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006996 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006997#endif
bellard31e31b82003-02-18 22:55:36 +00006998 case TARGET_NR_init_module:
6999 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007000#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007001 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007002#endif
bellard31e31b82003-02-18 22:55:36 +00007003 goto unimplemented;
7004 case TARGET_NR_quotactl:
7005 goto unimplemented;
7006 case TARGET_NR_getpgid:
7007 ret = get_errno(getpgid(arg1));
7008 break;
7009 case TARGET_NR_fchdir:
7010 ret = get_errno(fchdir(arg1));
7011 break;
j_mayer84409dd2007-04-06 08:56:50 +00007012#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007013 case TARGET_NR_bdflush:
7014 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007015#endif
thse5febef2007-04-01 18:31:35 +00007016#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007017 case TARGET_NR_sysfs:
7018 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007019#endif
bellard31e31b82003-02-18 22:55:36 +00007020 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007021 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007022 break;
thse5febef2007-04-01 18:31:35 +00007023#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007024 case TARGET_NR_afs_syscall:
7025 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007026#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007027#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007028 case TARGET_NR__llseek:
7029 {
7030 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007031#if !defined(__NR_llseek)
7032 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7033 if (res == -1) {
7034 ret = get_errno(res);
7035 } else {
7036 ret = 0;
7037 }
7038#else
bellard31e31b82003-02-18 22:55:36 +00007039 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007040#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007041 if ((ret == 0) && put_user_s64(res, arg4)) {
7042 goto efault;
7043 }
bellard31e31b82003-02-18 22:55:36 +00007044 }
7045 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007046#endif
bellard31e31b82003-02-18 22:55:36 +00007047 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007048#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007049 {
pbrook53a59602006-03-25 19:31:22 +00007050 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007051 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007052 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007053
7054 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007055 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007056 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007057 goto fail;
7058 }
ths3b46e622007-09-17 08:09:54 +00007059
bellard4add45b2003-06-05 01:52:59 +00007060 ret = get_errno(sys_getdents(arg1, dirp, count));
7061 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007062 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007063 struct target_dirent *tde;
7064 int len = ret;
7065 int reclen, treclen;
7066 int count1, tnamelen;
7067
7068 count1 = 0;
7069 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007070 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7071 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007072 tde = target_dirp;
7073 while (len > 0) {
7074 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007075 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7076 assert(tnamelen >= 0);
7077 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7078 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007079 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007080 tde->d_ino = tswapal(de->d_ino);
7081 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007082 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007083 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007084 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007085 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007086 count1 += treclen;
7087 }
7088 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007089 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007090 }
7091 free(dirp);
7092 }
7093#else
bellard31e31b82003-02-18 22:55:36 +00007094 {
aurel326556a832008-10-13 21:08:17 +00007095 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007096 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007097
bellard579a97f2007-11-11 14:26:47 +00007098 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7099 goto efault;
bellard72f03902003-02-18 23:33:18 +00007100 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007101 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007102 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007103 int len = ret;
7104 int reclen;
7105 de = dirp;
7106 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007107 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007108 if (reclen > len)
7109 break;
bellard8083a3e2003-03-24 23:12:16 +00007110 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007111 tswapls(&de->d_ino);
7112 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007113 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007114 len -= reclen;
7115 }
7116 }
pbrook53a59602006-03-25 19:31:22 +00007117 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007118 }
bellard4add45b2003-06-05 01:52:59 +00007119#endif
bellard31e31b82003-02-18 22:55:36 +00007120 break;
ths3ae43202007-09-16 21:39:48 +00007121#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007122 case TARGET_NR_getdents64:
7123 {
aurel326556a832008-10-13 21:08:17 +00007124 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007125 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007126 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7127 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007128 ret = get_errno(sys_getdents64(arg1, dirp, count));
7129 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007130 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007131 int len = ret;
7132 int reclen;
7133 de = dirp;
7134 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007135 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007136 if (reclen > len)
7137 break;
bellard8083a3e2003-03-24 23:12:16 +00007138 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007139 tswap64s((uint64_t *)&de->d_ino);
7140 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007141 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007142 len -= reclen;
7143 }
7144 }
pbrook53a59602006-03-25 19:31:22 +00007145 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007146 }
7147 break;
bellarda541f292004-04-12 20:39:29 +00007148#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007149#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
7150#ifdef TARGET_S390X
7151 case TARGET_NR_select:
7152#else
bellard31e31b82003-02-18 22:55:36 +00007153 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007154#endif
pbrook53a59602006-03-25 19:31:22 +00007155 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007156 break;
thse5febef2007-04-01 18:31:35 +00007157#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007158#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7159# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007160 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007161# endif
7162# ifdef TARGET_NR_ppoll
7163 case TARGET_NR_ppoll:
7164# endif
bellard9de5e442003-03-23 16:49:39 +00007165 {
pbrook53a59602006-03-25 19:31:22 +00007166 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007167 unsigned int nfds = arg2;
7168 int timeout = arg3;
7169 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007170 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007171
bellard579a97f2007-11-11 14:26:47 +00007172 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7173 if (!target_pfd)
7174 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007175
bellard9de5e442003-03-23 16:49:39 +00007176 pfd = alloca(sizeof(struct pollfd) * nfds);
7177 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007178 pfd[i].fd = tswap32(target_pfd[i].fd);
7179 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007180 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007181
7182# ifdef TARGET_NR_ppoll
7183 if (num == TARGET_NR_ppoll) {
7184 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7185 target_sigset_t *target_set;
7186 sigset_t _set, *set = &_set;
7187
7188 if (arg3) {
7189 if (target_to_host_timespec(timeout_ts, arg3)) {
7190 unlock_user(target_pfd, arg1, 0);
7191 goto efault;
7192 }
7193 } else {
7194 timeout_ts = NULL;
7195 }
7196
7197 if (arg4) {
7198 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7199 if (!target_set) {
7200 unlock_user(target_pfd, arg1, 0);
7201 goto efault;
7202 }
7203 target_to_host_sigset(set, target_set);
7204 } else {
7205 set = NULL;
7206 }
7207
7208 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7209
7210 if (!is_error(ret) && arg3) {
7211 host_to_target_timespec(arg3, timeout_ts);
7212 }
7213 if (arg4) {
7214 unlock_user(target_set, arg4, 0);
7215 }
7216 } else
7217# endif
7218 ret = get_errno(poll(pfd, nfds, timeout));
7219
bellard9de5e442003-03-23 16:49:39 +00007220 if (!is_error(ret)) {
7221 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007222 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007223 }
7224 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007225 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007226 }
7227 break;
thse5febef2007-04-01 18:31:35 +00007228#endif
bellard31e31b82003-02-18 22:55:36 +00007229 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007230 /* NOTE: the flock constant seems to be the same for every
7231 Linux platform */
7232 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007233 break;
7234 case TARGET_NR_readv:
7235 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007236 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7237 if (vec != NULL) {
7238 ret = get_errno(readv(arg1, vec, arg3));
7239 unlock_iovec(vec, arg2, arg3, 1);
7240 } else {
7241 ret = -host_to_target_errno(errno);
7242 }
bellard31e31b82003-02-18 22:55:36 +00007243 }
7244 break;
7245 case TARGET_NR_writev:
7246 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007247 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7248 if (vec != NULL) {
7249 ret = get_errno(writev(arg1, vec, arg3));
7250 unlock_iovec(vec, arg2, arg3, 0);
7251 } else {
7252 ret = -host_to_target_errno(errno);
7253 }
bellard31e31b82003-02-18 22:55:36 +00007254 }
7255 break;
7256 case TARGET_NR_getsid:
7257 ret = get_errno(getsid(arg1));
7258 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007259#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007260 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007261 ret = get_errno(fdatasync(arg1));
7262 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007263#endif
bellard31e31b82003-02-18 22:55:36 +00007264 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007265 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007266 return value. */
ths0da46a62007-10-20 20:23:07 +00007267 ret = -TARGET_ENOTDIR;
7268 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007269 case TARGET_NR_sched_getaffinity:
7270 {
7271 unsigned int mask_size;
7272 unsigned long *mask;
7273
7274 /*
7275 * sched_getaffinity needs multiples of ulong, so need to take
7276 * care of mismatches between target ulong and host ulong sizes.
7277 */
7278 if (arg2 & (sizeof(abi_ulong) - 1)) {
7279 ret = -TARGET_EINVAL;
7280 break;
7281 }
7282 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7283
7284 mask = alloca(mask_size);
7285 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7286
7287 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007288 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007289 goto efault;
7290 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007291 }
7292 }
7293 break;
7294 case TARGET_NR_sched_setaffinity:
7295 {
7296 unsigned int mask_size;
7297 unsigned long *mask;
7298
7299 /*
7300 * sched_setaffinity needs multiples of ulong, so need to take
7301 * care of mismatches between target ulong and host ulong sizes.
7302 */
7303 if (arg2 & (sizeof(abi_ulong) - 1)) {
7304 ret = -TARGET_EINVAL;
7305 break;
7306 }
7307 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7308
7309 mask = alloca(mask_size);
7310 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7311 goto efault;
7312 }
7313 memcpy(mask, p, arg2);
7314 unlock_user_struct(p, arg2, 0);
7315
7316 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7317 }
7318 break;
bellard31e31b82003-02-18 22:55:36 +00007319 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007320 {
pbrook53a59602006-03-25 19:31:22 +00007321 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007322 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007323
bellard579a97f2007-11-11 14:26:47 +00007324 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7325 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007326 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007327 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007328 ret = get_errno(sched_setparam(arg1, &schp));
7329 }
7330 break;
bellard31e31b82003-02-18 22:55:36 +00007331 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007332 {
pbrook53a59602006-03-25 19:31:22 +00007333 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007334 struct sched_param schp;
7335 ret = get_errno(sched_getparam(arg1, &schp));
7336 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007337 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7338 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007339 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007340 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007341 }
7342 }
7343 break;
bellard31e31b82003-02-18 22:55:36 +00007344 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007345 {
pbrook53a59602006-03-25 19:31:22 +00007346 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007347 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007348 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7349 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007350 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007351 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007352 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7353 }
7354 break;
bellard31e31b82003-02-18 22:55:36 +00007355 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007356 ret = get_errno(sched_getscheduler(arg1));
7357 break;
bellard31e31b82003-02-18 22:55:36 +00007358 case TARGET_NR_sched_yield:
7359 ret = get_errno(sched_yield());
7360 break;
7361 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007362 ret = get_errno(sched_get_priority_max(arg1));
7363 break;
bellard31e31b82003-02-18 22:55:36 +00007364 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007365 ret = get_errno(sched_get_priority_min(arg1));
7366 break;
bellard31e31b82003-02-18 22:55:36 +00007367 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007368 {
bellard5cd43932003-03-29 16:54:36 +00007369 struct timespec ts;
7370 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7371 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007372 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007373 }
7374 }
7375 break;
bellard31e31b82003-02-18 22:55:36 +00007376 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007377 {
bellard1b6b0292003-03-22 17:31:38 +00007378 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007379 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007380 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007381 if (is_error(ret) && arg2) {
7382 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007383 }
7384 }
7385 break;
thse5febef2007-04-01 18:31:35 +00007386#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007387 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007388 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007389#endif
7390#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007391 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007392 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007393#endif
bellard31e31b82003-02-18 22:55:36 +00007394 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007395 switch (arg1) {
7396 case PR_GET_PDEATHSIG:
7397 {
7398 int deathsig;
7399 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7400 if (!is_error(ret) && arg2
7401 && put_user_ual(deathsig, arg2)) {
7402 goto efault;
thse5574482007-02-11 20:03:13 +00007403 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007404 break;
7405 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007406#ifdef PR_GET_NAME
7407 case PR_GET_NAME:
7408 {
7409 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7410 if (!name) {
7411 goto efault;
7412 }
7413 ret = get_errno(prctl(arg1, (unsigned long)name,
7414 arg3, arg4, arg5));
7415 unlock_user(name, arg2, 16);
7416 break;
7417 }
7418 case PR_SET_NAME:
7419 {
7420 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7421 if (!name) {
7422 goto efault;
7423 }
7424 ret = get_errno(prctl(arg1, (unsigned long)name,
7425 arg3, arg4, arg5));
7426 unlock_user(name, arg2, 0);
7427 break;
7428 }
7429#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007430 default:
7431 /* Most prctl options have no pointer arguments */
7432 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7433 break;
7434 }
ths39b9aae2007-02-11 18:36:44 +00007435 break;
bellardd2fd1af2007-11-14 18:08:56 +00007436#ifdef TARGET_NR_arch_prctl
7437 case TARGET_NR_arch_prctl:
7438#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7439 ret = do_arch_prctl(cpu_env, arg1, arg2);
7440 break;
7441#else
7442 goto unimplemented;
7443#endif
7444#endif
bellard67867302003-11-23 17:05:30 +00007445#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00007446 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03007447 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007448 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007449 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7450 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007451 ret = get_errno(pread(arg1, p, arg3, arg4));
7452 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00007453 break;
bellard31e31b82003-02-18 22:55:36 +00007454 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03007455 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00007456 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00007457 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7458 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007459 ret = get_errno(pwrite(arg1, p, arg3, arg4));
7460 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00007461 break;
bellard67867302003-11-23 17:05:30 +00007462#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007463#ifdef TARGET_NR_pread64
7464 case TARGET_NR_pread64:
7465 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7466 goto efault;
7467 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7468 unlock_user(p, arg2, ret);
7469 break;
7470 case TARGET_NR_pwrite64:
7471 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7472 goto efault;
7473 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7474 unlock_user(p, arg2, 0);
7475 break;
7476#endif
bellard31e31b82003-02-18 22:55:36 +00007477 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007478 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7479 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007480 ret = get_errno(sys_getcwd1(p, arg2));
7481 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007482 break;
7483 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007484 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007485 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007486 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007487 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007488#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007489 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007490 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007491 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007492 break;
7493#else
bellard5cd43932003-03-29 16:54:36 +00007494 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007495#endif
bellard31e31b82003-02-18 22:55:36 +00007496 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00007497 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007498#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007499 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007500 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007501#endif
7502#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007503 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007504 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007505#endif
bellard048f6b42005-11-26 18:47:20 +00007506#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007507 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007508 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7509 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007510 break;
bellard048f6b42005-11-26 18:47:20 +00007511#endif
bellardebc05482003-09-30 21:08:41 +00007512#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007513 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007514 {
7515 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007516 int resource = target_to_host_resource(arg1);
7517 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007518 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007519 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007520 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7521 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007522 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7523 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007524 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007525 }
7526 break;
7527 }
bellardebc05482003-09-30 21:08:41 +00007528#endif
bellarda315a142005-01-30 22:59:18 +00007529#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007530 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007531 if (!(p = lock_user_string(arg1)))
7532 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007533 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7534 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007535 break;
bellarda315a142005-01-30 22:59:18 +00007536#endif
7537#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007538 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007539 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007540 break;
bellarda315a142005-01-30 22:59:18 +00007541#endif
7542#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007543 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007544 if (!(p = lock_user_string(arg1)))
7545 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007546 ret = get_errno(stat(path(p), &st));
7547 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007548 if (!is_error(ret))
7549 ret = host_to_target_stat64(cpu_env, arg2, &st);
7550 break;
bellarda315a142005-01-30 22:59:18 +00007551#endif
7552#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007553 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007554 if (!(p = lock_user_string(arg1)))
7555 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007556 ret = get_errno(lstat(path(p), &st));
7557 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007558 if (!is_error(ret))
7559 ret = host_to_target_stat64(cpu_env, arg2, &st);
7560 break;
bellarda315a142005-01-30 22:59:18 +00007561#endif
7562#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007563 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007564 ret = get_errno(fstat(arg1, &st));
7565 if (!is_error(ret))
7566 ret = host_to_target_stat64(cpu_env, arg2, &st);
7567 break;
bellardec86b0f2003-04-11 00:15:04 +00007568#endif
aurel329d33b762009-04-08 23:07:05 +00007569#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7570 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7571#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007572 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007573#endif
7574#ifdef TARGET_NR_newfstatat
7575 case TARGET_NR_newfstatat:
7576#endif
balrog6a24a772008-09-20 02:23:36 +00007577 if (!(p = lock_user_string(arg2)))
7578 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007579#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007580 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007581#else
7582 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7583#endif
balrog6a24a772008-09-20 02:23:36 +00007584 if (!is_error(ret))
7585 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007586 break;
bellarda315a142005-01-30 22:59:18 +00007587#endif
bellard67867302003-11-23 17:05:30 +00007588 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007589 if (!(p = lock_user_string(arg1)))
7590 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007591 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7592 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007593 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007594#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007595 case TARGET_NR_getuid:
7596 ret = get_errno(high2lowuid(getuid()));
7597 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007598#endif
7599#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007600 case TARGET_NR_getgid:
7601 ret = get_errno(high2lowgid(getgid()));
7602 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007603#endif
7604#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007605 case TARGET_NR_geteuid:
7606 ret = get_errno(high2lowuid(geteuid()));
7607 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007608#endif
7609#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007610 case TARGET_NR_getegid:
7611 ret = get_errno(high2lowgid(getegid()));
7612 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007613#endif
bellard67867302003-11-23 17:05:30 +00007614 case TARGET_NR_setreuid:
7615 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7616 break;
7617 case TARGET_NR_setregid:
7618 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7619 break;
7620 case TARGET_NR_getgroups:
7621 {
7622 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007623 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007624 gid_t *grouplist;
7625 int i;
7626
7627 grouplist = alloca(gidsetsize * sizeof(gid_t));
7628 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007629 if (gidsetsize == 0)
7630 break;
bellard67867302003-11-23 17:05:30 +00007631 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007632 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7633 if (!target_grouplist)
7634 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007635 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007636 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007637 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007638 }
7639 }
7640 break;
7641 case TARGET_NR_setgroups:
7642 {
7643 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007644 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007645 gid_t *grouplist;
7646 int i;
7647
7648 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007649 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7650 if (!target_grouplist) {
7651 ret = -TARGET_EFAULT;
7652 goto fail;
7653 }
bellard67867302003-11-23 17:05:30 +00007654 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007655 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007656 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007657 ret = get_errno(setgroups(gidsetsize, grouplist));
7658 }
7659 break;
7660 case TARGET_NR_fchown:
7661 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7662 break;
thsccfa72b2007-09-24 09:23:34 +00007663#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7664 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007665 if (!(p = lock_user_string(arg2)))
7666 goto efault;
7667 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7668 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007669 break;
7670#endif
bellard67867302003-11-23 17:05:30 +00007671#ifdef TARGET_NR_setresuid
7672 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007673 ret = get_errno(setresuid(low2highuid(arg1),
7674 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007675 low2highuid(arg3)));
7676 break;
7677#endif
7678#ifdef TARGET_NR_getresuid
7679 case TARGET_NR_getresuid:
7680 {
pbrook53a59602006-03-25 19:31:22 +00007681 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007682 ret = get_errno(getresuid(&ruid, &euid, &suid));
7683 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007684 if (put_user_u16(high2lowuid(ruid), arg1)
7685 || put_user_u16(high2lowuid(euid), arg2)
7686 || put_user_u16(high2lowuid(suid), arg3))
7687 goto efault;
bellard67867302003-11-23 17:05:30 +00007688 }
7689 }
7690 break;
7691#endif
7692#ifdef TARGET_NR_getresgid
7693 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007694 ret = get_errno(setresgid(low2highgid(arg1),
7695 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007696 low2highgid(arg3)));
7697 break;
7698#endif
7699#ifdef TARGET_NR_getresgid
7700 case TARGET_NR_getresgid:
7701 {
pbrook53a59602006-03-25 19:31:22 +00007702 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007703 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7704 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007705 if (put_user_u16(high2lowgid(rgid), arg1)
7706 || put_user_u16(high2lowgid(egid), arg2)
7707 || put_user_u16(high2lowgid(sgid), arg3))
7708 goto efault;
bellard67867302003-11-23 17:05:30 +00007709 }
7710 }
7711 break;
7712#endif
7713 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007714 if (!(p = lock_user_string(arg1)))
7715 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007716 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7717 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007718 break;
7719 case TARGET_NR_setuid:
7720 ret = get_errno(setuid(low2highuid(arg1)));
7721 break;
7722 case TARGET_NR_setgid:
7723 ret = get_errno(setgid(low2highgid(arg1)));
7724 break;
7725 case TARGET_NR_setfsuid:
7726 ret = get_errno(setfsuid(arg1));
7727 break;
7728 case TARGET_NR_setfsgid:
7729 ret = get_errno(setfsgid(arg1));
7730 break;
bellard67867302003-11-23 17:05:30 +00007731
bellarda315a142005-01-30 22:59:18 +00007732#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007733 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007734 if (!(p = lock_user_string(arg1)))
7735 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007736 ret = get_errno(lchown(p, arg2, arg3));
7737 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007738 break;
bellarda315a142005-01-30 22:59:18 +00007739#endif
7740#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007741 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007742 ret = get_errno(getuid());
7743 break;
bellarda315a142005-01-30 22:59:18 +00007744#endif
aurel3264b4d282008-11-14 17:20:15 +00007745
7746#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7747 /* Alpha specific */
7748 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007749 {
7750 uid_t euid;
7751 euid=geteuid();
7752 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7753 }
aurel3264b4d282008-11-14 17:20:15 +00007754 ret = get_errno(getuid());
7755 break;
7756#endif
7757#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7758 /* Alpha specific */
7759 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007760 {
7761 uid_t egid;
7762 egid=getegid();
7763 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7764 }
aurel3264b4d282008-11-14 17:20:15 +00007765 ret = get_errno(getgid());
7766 break;
7767#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007768#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7769 /* Alpha specific */
7770 case TARGET_NR_osf_getsysinfo:
7771 ret = -TARGET_EOPNOTSUPP;
7772 switch (arg1) {
7773 case TARGET_GSI_IEEE_FP_CONTROL:
7774 {
7775 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7776
7777 /* Copied from linux ieee_fpcr_to_swcr. */
7778 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7779 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7780 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7781 | SWCR_TRAP_ENABLE_DZE
7782 | SWCR_TRAP_ENABLE_OVF);
7783 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7784 | SWCR_TRAP_ENABLE_INE);
7785 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7786 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7787
7788 if (put_user_u64 (swcr, arg2))
7789 goto efault;
7790 ret = 0;
7791 }
7792 break;
7793
7794 /* case GSI_IEEE_STATE_AT_SIGNAL:
7795 -- Not implemented in linux kernel.
7796 case GSI_UACPROC:
7797 -- Retrieves current unaligned access state; not much used.
7798 case GSI_PROC_TYPE:
7799 -- Retrieves implver information; surely not used.
7800 case GSI_GET_HWRPB:
7801 -- Grabs a copy of the HWRPB; surely not used.
7802 */
7803 }
7804 break;
7805#endif
7806#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7807 /* Alpha specific */
7808 case TARGET_NR_osf_setsysinfo:
7809 ret = -TARGET_EOPNOTSUPP;
7810 switch (arg1) {
7811 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007812 {
7813 uint64_t swcr, fpcr, orig_fpcr;
7814
Richard Henderson6e06d512012-06-01 09:08:21 -07007815 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08007816 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07007817 }
7818 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007819 fpcr = orig_fpcr & FPCR_DYN_MASK;
7820
7821 /* Copied from linux ieee_swcr_to_fpcr. */
7822 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7823 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7824 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7825 | SWCR_TRAP_ENABLE_DZE
7826 | SWCR_TRAP_ENABLE_OVF)) << 48;
7827 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7828 | SWCR_TRAP_ENABLE_INE)) << 57;
7829 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7830 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7831
Richard Henderson6e06d512012-06-01 09:08:21 -07007832 cpu_alpha_store_fpcr(cpu_env, fpcr);
7833 ret = 0;
7834 }
7835 break;
7836
7837 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7838 {
7839 uint64_t exc, fpcr, orig_fpcr;
7840 int si_code;
7841
7842 if (get_user_u64(exc, arg2)) {
7843 goto efault;
7844 }
7845
7846 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
7847
7848 /* We only add to the exception status here. */
7849 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
7850
7851 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007852 ret = 0;
7853
Richard Henderson6e06d512012-06-01 09:08:21 -07007854 /* Old exceptions are not signaled. */
7855 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007856
Richard Henderson6e06d512012-06-01 09:08:21 -07007857 /* If any exceptions set by this call,
7858 and are unmasked, send a signal. */
7859 si_code = 0;
7860 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
7861 si_code = TARGET_FPE_FLTRES;
7862 }
7863 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
7864 si_code = TARGET_FPE_FLTUND;
7865 }
7866 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
7867 si_code = TARGET_FPE_FLTOVF;
7868 }
7869 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
7870 si_code = TARGET_FPE_FLTDIV;
7871 }
7872 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
7873 si_code = TARGET_FPE_FLTINV;
7874 }
7875 if (si_code != 0) {
7876 target_siginfo_t info;
7877 info.si_signo = SIGFPE;
7878 info.si_errno = 0;
7879 info.si_code = si_code;
7880 info._sifields._sigfault._addr
7881 = ((CPUArchState *)cpu_env)->pc;
7882 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007883 }
7884 }
7885 break;
7886
7887 /* case SSI_NVPAIRS:
7888 -- Used with SSIN_UACPROC to enable unaligned accesses.
7889 case SSI_IEEE_STATE_AT_SIGNAL:
7890 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7891 -- Not implemented in linux kernel
7892 */
7893 }
7894 break;
7895#endif
7896#ifdef TARGET_NR_osf_sigprocmask
7897 /* Alpha specific. */
7898 case TARGET_NR_osf_sigprocmask:
7899 {
7900 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007901 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007902 sigset_t set, oldset;
7903
7904 switch(arg1) {
7905 case TARGET_SIG_BLOCK:
7906 how = SIG_BLOCK;
7907 break;
7908 case TARGET_SIG_UNBLOCK:
7909 how = SIG_UNBLOCK;
7910 break;
7911 case TARGET_SIG_SETMASK:
7912 how = SIG_SETMASK;
7913 break;
7914 default:
7915 ret = -TARGET_EINVAL;
7916 goto fail;
7917 }
7918 mask = arg2;
7919 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007920 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007921 host_to_target_old_sigset(&mask, &oldset);
7922 ret = mask;
7923 }
7924 break;
7925#endif
aurel3264b4d282008-11-14 17:20:15 +00007926
bellarda315a142005-01-30 22:59:18 +00007927#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007928 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007929 ret = get_errno(getgid());
7930 break;
bellarda315a142005-01-30 22:59:18 +00007931#endif
7932#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007933 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007934 ret = get_errno(geteuid());
7935 break;
bellarda315a142005-01-30 22:59:18 +00007936#endif
7937#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007938 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007939 ret = get_errno(getegid());
7940 break;
bellarda315a142005-01-30 22:59:18 +00007941#endif
7942#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007943 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007944 ret = get_errno(setreuid(arg1, arg2));
7945 break;
bellarda315a142005-01-30 22:59:18 +00007946#endif
7947#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007948 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007949 ret = get_errno(setregid(arg1, arg2));
7950 break;
bellarda315a142005-01-30 22:59:18 +00007951#endif
7952#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007953 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007954 {
7955 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007956 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007957 gid_t *grouplist;
7958 int i;
7959
7960 grouplist = alloca(gidsetsize * sizeof(gid_t));
7961 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007962 if (gidsetsize == 0)
7963 break;
bellard99c475a2005-01-31 20:45:13 +00007964 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007965 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7966 if (!target_grouplist) {
7967 ret = -TARGET_EFAULT;
7968 goto fail;
7969 }
balroga2155fc2008-09-20 02:12:08 +00007970 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007971 target_grouplist[i] = tswap32(grouplist[i]);
7972 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007973 }
7974 }
7975 break;
bellarda315a142005-01-30 22:59:18 +00007976#endif
7977#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007978 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007979 {
7980 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007981 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007982 gid_t *grouplist;
7983 int i;
ths3b46e622007-09-17 08:09:54 +00007984
bellard99c475a2005-01-31 20:45:13 +00007985 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007986 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7987 if (!target_grouplist) {
7988 ret = -TARGET_EFAULT;
7989 goto fail;
7990 }
bellard99c475a2005-01-31 20:45:13 +00007991 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007992 grouplist[i] = tswap32(target_grouplist[i]);
7993 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007994 ret = get_errno(setgroups(gidsetsize, grouplist));
7995 }
7996 break;
bellarda315a142005-01-30 22:59:18 +00007997#endif
7998#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007999 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008000 ret = get_errno(fchown(arg1, arg2, arg3));
8001 break;
bellarda315a142005-01-30 22:59:18 +00008002#endif
8003#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008004 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008005 ret = get_errno(setresuid(arg1, arg2, arg3));
8006 break;
bellarda315a142005-01-30 22:59:18 +00008007#endif
8008#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008009 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008010 {
pbrook53a59602006-03-25 19:31:22 +00008011 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008012 ret = get_errno(getresuid(&ruid, &euid, &suid));
8013 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008014 if (put_user_u32(ruid, arg1)
8015 || put_user_u32(euid, arg2)
8016 || put_user_u32(suid, arg3))
8017 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008018 }
8019 }
8020 break;
bellarda315a142005-01-30 22:59:18 +00008021#endif
8022#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008023 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008024 ret = get_errno(setresgid(arg1, arg2, arg3));
8025 break;
bellarda315a142005-01-30 22:59:18 +00008026#endif
8027#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008028 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008029 {
pbrook53a59602006-03-25 19:31:22 +00008030 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008031 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8032 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008033 if (put_user_u32(rgid, arg1)
8034 || put_user_u32(egid, arg2)
8035 || put_user_u32(sgid, arg3))
8036 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008037 }
8038 }
8039 break;
bellarda315a142005-01-30 22:59:18 +00008040#endif
8041#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008042 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008043 if (!(p = lock_user_string(arg1)))
8044 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008045 ret = get_errno(chown(p, arg2, arg3));
8046 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008047 break;
bellarda315a142005-01-30 22:59:18 +00008048#endif
8049#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008050 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008051 ret = get_errno(setuid(arg1));
8052 break;
bellarda315a142005-01-30 22:59:18 +00008053#endif
8054#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008055 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008056 ret = get_errno(setgid(arg1));
8057 break;
bellarda315a142005-01-30 22:59:18 +00008058#endif
8059#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008060 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008061 ret = get_errno(setfsuid(arg1));
8062 break;
bellarda315a142005-01-30 22:59:18 +00008063#endif
8064#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008065 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008066 ret = get_errno(setfsgid(arg1));
8067 break;
bellarda315a142005-01-30 22:59:18 +00008068#endif
bellard67867302003-11-23 17:05:30 +00008069
bellard31e31b82003-02-18 22:55:36 +00008070 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008071 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008072#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008073 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008074 {
8075 void *a;
8076 ret = -TARGET_EFAULT;
8077 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8078 goto efault;
8079 if (!(p = lock_user_string(arg3)))
8080 goto mincore_fail;
8081 ret = get_errno(mincore(a, arg2, p));
8082 unlock_user(p, arg3, ret);
8083 mincore_fail:
8084 unlock_user(a, arg1, 0);
8085 }
8086 break;
bellardffa65c32004-01-04 23:57:22 +00008087#endif
aurel32408321b2008-10-01 21:46:32 +00008088#ifdef TARGET_NR_arm_fadvise64_64
8089 case TARGET_NR_arm_fadvise64_64:
8090 {
8091 /*
8092 * arm_fadvise64_64 looks like fadvise64_64 but
8093 * with different argument order
8094 */
8095 abi_long temp;
8096 temp = arg3;
8097 arg3 = arg4;
8098 arg4 = temp;
8099 }
8100#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008101#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008102#ifdef TARGET_NR_fadvise64_64
8103 case TARGET_NR_fadvise64_64:
8104#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008105#ifdef TARGET_NR_fadvise64
8106 case TARGET_NR_fadvise64:
8107#endif
8108#ifdef TARGET_S390X
8109 switch (arg4) {
8110 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8111 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8112 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8113 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8114 default: break;
8115 }
8116#endif
8117 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008118 break;
8119#endif
bellardffa65c32004-01-04 23:57:22 +00008120#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008121 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008122 /* A straight passthrough may not be safe because qemu sometimes
8123 turns private flie-backed mappings into anonymous mappings.
8124 This will break MADV_DONTNEED.
8125 This is a hint, so ignoring and returning success is ok. */
8126 ret = get_errno(0);
8127 break;
bellardffa65c32004-01-04 23:57:22 +00008128#endif
blueswir1992f48a2007-10-14 16:27:31 +00008129#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008130 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008131 {
thsb1e341e2007-03-20 21:50:52 +00008132 int cmd;
bellard77e46722003-04-29 20:39:06 +00008133 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008134 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008135#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008136 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008137#endif
bellard77e46722003-04-29 20:39:06 +00008138
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008139 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008140 if (cmd == -TARGET_EINVAL) {
8141 ret = cmd;
8142 break;
8143 }
thsb1e341e2007-03-20 21:50:52 +00008144
bellard60cd49d2003-03-16 22:53:56 +00008145 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008146 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008147#ifdef TARGET_ARM
8148 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008149 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8150 goto efault;
ths58134272007-03-31 18:59:32 +00008151 fl.l_type = tswap16(target_efl->l_type);
8152 fl.l_whence = tswap16(target_efl->l_whence);
8153 fl.l_start = tswap64(target_efl->l_start);
8154 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008155 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008156 unlock_user_struct(target_efl, arg3, 0);
8157 } else
8158#endif
8159 {
bellard9ee1fa22007-11-11 15:11:19 +00008160 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8161 goto efault;
ths58134272007-03-31 18:59:32 +00008162 fl.l_type = tswap16(target_fl->l_type);
8163 fl.l_whence = tswap16(target_fl->l_whence);
8164 fl.l_start = tswap64(target_fl->l_start);
8165 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008166 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008167 unlock_user_struct(target_fl, arg3, 0);
8168 }
thsb1e341e2007-03-20 21:50:52 +00008169 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008170 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008171#ifdef TARGET_ARM
8172 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008173 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8174 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008175 target_efl->l_type = tswap16(fl.l_type);
8176 target_efl->l_whence = tswap16(fl.l_whence);
8177 target_efl->l_start = tswap64(fl.l_start);
8178 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008179 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008180 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008181 } else
8182#endif
8183 {
bellard9ee1fa22007-11-11 15:11:19 +00008184 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8185 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008186 target_fl->l_type = tswap16(fl.l_type);
8187 target_fl->l_whence = tswap16(fl.l_whence);
8188 target_fl->l_start = tswap64(fl.l_start);
8189 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008190 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008191 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008192 }
bellard77e46722003-04-29 20:39:06 +00008193 }
8194 break;
8195
thsb1e341e2007-03-20 21:50:52 +00008196 case TARGET_F_SETLK64:
8197 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008198#ifdef TARGET_ARM
8199 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008200 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8201 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008202 fl.l_type = tswap16(target_efl->l_type);
8203 fl.l_whence = tswap16(target_efl->l_whence);
8204 fl.l_start = tswap64(target_efl->l_start);
8205 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008206 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008207 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008208 } else
8209#endif
8210 {
bellard9ee1fa22007-11-11 15:11:19 +00008211 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8212 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008213 fl.l_type = tswap16(target_fl->l_type);
8214 fl.l_whence = tswap16(target_fl->l_whence);
8215 fl.l_start = tswap64(target_fl->l_start);
8216 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008217 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008218 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008219 }
thsb1e341e2007-03-20 21:50:52 +00008220 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008221 break;
bellard60cd49d2003-03-16 22:53:56 +00008222 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008223 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008224 break;
8225 }
bellard77e46722003-04-29 20:39:06 +00008226 break;
8227 }
bellard60cd49d2003-03-16 22:53:56 +00008228#endif
ths7d600c82006-12-08 01:32:58 +00008229#ifdef TARGET_NR_cacheflush
8230 case TARGET_NR_cacheflush:
8231 /* self-modifying code is handled automatically, so nothing needed */
8232 ret = 0;
8233 break;
8234#endif
bellardebc05482003-09-30 21:08:41 +00008235#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008236 case TARGET_NR_security:
8237 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008238#endif
bellardc573ff62004-01-04 15:51:36 +00008239#ifdef TARGET_NR_getpagesize
8240 case TARGET_NR_getpagesize:
8241 ret = TARGET_PAGE_SIZE;
8242 break;
8243#endif
bellard31e31b82003-02-18 22:55:36 +00008244 case TARGET_NR_gettid:
8245 ret = get_errno(gettid());
8246 break;
thse5febef2007-04-01 18:31:35 +00008247#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008248 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008249#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008250 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008251 arg2 = arg3;
8252 arg3 = arg4;
8253 arg4 = arg5;
8254 }
aurel322054ac92008-10-13 21:08:07 +00008255 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8256#else
8257 ret = get_errno(readahead(arg1, arg2, arg3));
8258#endif
8259 break;
thse5febef2007-04-01 18:31:35 +00008260#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008261#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008262#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008263 case TARGET_NR_listxattr:
8264 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008265 {
8266 void *p, *b = 0;
8267 if (arg2) {
8268 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8269 if (!b) {
8270 ret = -TARGET_EFAULT;
8271 break;
8272 }
8273 }
8274 p = lock_user_string(arg1);
8275 if (p) {
8276 if (num == TARGET_NR_listxattr) {
8277 ret = get_errno(listxattr(p, b, arg3));
8278 } else {
8279 ret = get_errno(llistxattr(p, b, arg3));
8280 }
8281 } else {
8282 ret = -TARGET_EFAULT;
8283 }
8284 unlock_user(p, arg1, 0);
8285 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008286 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008287 }
8288 case TARGET_NR_flistxattr:
8289 {
8290 void *b = 0;
8291 if (arg2) {
8292 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8293 if (!b) {
8294 ret = -TARGET_EFAULT;
8295 break;
8296 }
8297 }
8298 ret = get_errno(flistxattr(arg1, b, arg3));
8299 unlock_user(b, arg2, arg3);
8300 break;
8301 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008302 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008303 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008304 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008305 void *p, *n, *v = 0;
8306 if (arg3) {
8307 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8308 if (!v) {
8309 ret = -TARGET_EFAULT;
8310 break;
8311 }
8312 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008313 p = lock_user_string(arg1);
8314 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008315 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008316 if (num == TARGET_NR_setxattr) {
8317 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8318 } else {
8319 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8320 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008321 } else {
8322 ret = -TARGET_EFAULT;
8323 }
8324 unlock_user(p, arg1, 0);
8325 unlock_user(n, arg2, 0);
8326 unlock_user(v, arg3, 0);
8327 }
8328 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008329 case TARGET_NR_fsetxattr:
8330 {
8331 void *n, *v = 0;
8332 if (arg3) {
8333 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8334 if (!v) {
8335 ret = -TARGET_EFAULT;
8336 break;
8337 }
8338 }
8339 n = lock_user_string(arg2);
8340 if (n) {
8341 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8342 } else {
8343 ret = -TARGET_EFAULT;
8344 }
8345 unlock_user(n, arg2, 0);
8346 unlock_user(v, arg3, 0);
8347 }
8348 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008349 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008350 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008351 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008352 void *p, *n, *v = 0;
8353 if (arg3) {
8354 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8355 if (!v) {
8356 ret = -TARGET_EFAULT;
8357 break;
8358 }
8359 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008360 p = lock_user_string(arg1);
8361 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008362 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008363 if (num == TARGET_NR_getxattr) {
8364 ret = get_errno(getxattr(p, n, v, arg4));
8365 } else {
8366 ret = get_errno(lgetxattr(p, n, v, arg4));
8367 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008368 } else {
8369 ret = -TARGET_EFAULT;
8370 }
8371 unlock_user(p, arg1, 0);
8372 unlock_user(n, arg2, 0);
8373 unlock_user(v, arg3, arg4);
8374 }
8375 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008376 case TARGET_NR_fgetxattr:
8377 {
8378 void *n, *v = 0;
8379 if (arg3) {
8380 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8381 if (!v) {
8382 ret = -TARGET_EFAULT;
8383 break;
8384 }
8385 }
8386 n = lock_user_string(arg2);
8387 if (n) {
8388 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8389 } else {
8390 ret = -TARGET_EFAULT;
8391 }
8392 unlock_user(n, arg2, 0);
8393 unlock_user(v, arg3, arg4);
8394 }
8395 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008396 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008397 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008398 {
8399 void *p, *n;
8400 p = lock_user_string(arg1);
8401 n = lock_user_string(arg2);
8402 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008403 if (num == TARGET_NR_removexattr) {
8404 ret = get_errno(removexattr(p, n));
8405 } else {
8406 ret = get_errno(lremovexattr(p, n));
8407 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008408 } else {
8409 ret = -TARGET_EFAULT;
8410 }
8411 unlock_user(p, arg1, 0);
8412 unlock_user(n, arg2, 0);
8413 }
8414 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008415 case TARGET_NR_fremovexattr:
8416 {
8417 void *n;
8418 n = lock_user_string(arg2);
8419 if (n) {
8420 ret = get_errno(fremovexattr(arg1, n));
8421 } else {
8422 ret = -TARGET_EFAULT;
8423 }
8424 unlock_user(n, arg2, 0);
8425 }
8426 break;
bellardebc05482003-09-30 21:08:41 +00008427#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008428#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008429#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008430 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008431#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008432 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8433 ret = 0;
8434 break;
edgar_iglef967792009-01-07 14:19:38 +00008435#elif defined(TARGET_CRIS)
8436 if (arg1 & 0xff)
8437 ret = -TARGET_EINVAL;
8438 else {
8439 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8440 ret = 0;
8441 }
8442 break;
bellard8d18e892007-11-14 15:18:40 +00008443#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8444 ret = do_set_thread_area(cpu_env, arg1);
8445 break;
ths6f5b89a2007-03-02 20:48:00 +00008446#else
8447 goto unimplemented_nowarn;
8448#endif
8449#endif
8450#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008451 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008452#if defined(TARGET_I386) && defined(TARGET_ABI32)
8453 ret = do_get_thread_area(cpu_env, arg1);
8454#else
bellard5cd43932003-03-29 16:54:36 +00008455 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008456#endif
bellard8d18e892007-11-14 15:18:40 +00008457#endif
bellard48dc41e2006-06-21 18:15:50 +00008458#ifdef TARGET_NR_getdomainname
8459 case TARGET_NR_getdomainname:
8460 goto unimplemented_nowarn;
8461#endif
ths6f5b89a2007-03-02 20:48:00 +00008462
thsb5906f92007-03-19 13:32:45 +00008463#ifdef TARGET_NR_clock_gettime
8464 case TARGET_NR_clock_gettime:
8465 {
8466 struct timespec ts;
8467 ret = get_errno(clock_gettime(arg1, &ts));
8468 if (!is_error(ret)) {
8469 host_to_target_timespec(arg2, &ts);
8470 }
8471 break;
8472 }
8473#endif
8474#ifdef TARGET_NR_clock_getres
8475 case TARGET_NR_clock_getres:
8476 {
8477 struct timespec ts;
8478 ret = get_errno(clock_getres(arg1, &ts));
8479 if (!is_error(ret)) {
8480 host_to_target_timespec(arg2, &ts);
8481 }
8482 break;
8483 }
8484#endif
pbrook63d76512008-05-29 13:43:29 +00008485#ifdef TARGET_NR_clock_nanosleep
8486 case TARGET_NR_clock_nanosleep:
8487 {
8488 struct timespec ts;
8489 target_to_host_timespec(&ts, arg3);
8490 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8491 if (arg4)
8492 host_to_target_timespec(arg4, &ts);
8493 break;
8494 }
8495#endif
thsb5906f92007-03-19 13:32:45 +00008496
ths6f5b89a2007-03-02 20:48:00 +00008497#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8498 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008499 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8500 break;
ths6f5b89a2007-03-02 20:48:00 +00008501#endif
8502
ths3ae43202007-09-16 21:39:48 +00008503#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008504 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008505 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008506 break;
8507#endif
8508
ths3ae43202007-09-16 21:39:48 +00008509#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008510 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008511 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8512 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008513 break;
8514#endif
8515
ths4f2b1fe2007-06-21 21:57:12 +00008516#ifdef TARGET_NR_set_robust_list
8517 case TARGET_NR_set_robust_list:
8518 goto unimplemented_nowarn;
8519#endif
8520
ths9007f0e2007-09-25 17:50:37 +00008521#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8522 case TARGET_NR_utimensat:
8523 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008524 struct timespec *tsp, ts[2];
8525 if (!arg3) {
8526 tsp = NULL;
8527 } else {
8528 target_to_host_timespec(ts, arg3);
8529 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8530 tsp = ts;
8531 }
ths9007f0e2007-09-25 17:50:37 +00008532 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008533 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008534 else {
bellard579a97f2007-11-11 14:26:47 +00008535 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008536 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008537 goto fail;
8538 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008539 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008540 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008541 }
8542 }
8543 break;
8544#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02008545#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00008546 case TARGET_NR_futex:
8547 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8548 break;
8549#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008550#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008551 case TARGET_NR_inotify_init:
8552 ret = get_errno(sys_inotify_init());
8553 break;
8554#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008555#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008556#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8557 case TARGET_NR_inotify_init1:
8558 ret = get_errno(sys_inotify_init1(arg1));
8559 break;
8560#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008561#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008562#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008563 case TARGET_NR_inotify_add_watch:
8564 p = lock_user_string(arg2);
8565 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8566 unlock_user(p, arg2, 0);
8567 break;
8568#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008569#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008570 case TARGET_NR_inotify_rm_watch:
8571 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8572 break;
8573#endif
ths9007f0e2007-09-25 17:50:37 +00008574
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008575#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008576 case TARGET_NR_mq_open:
8577 {
8578 struct mq_attr posix_mq_attr;
8579
8580 p = lock_user_string(arg1 - 1);
8581 if (arg4 != 0)
8582 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8583 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8584 unlock_user (p, arg1, 0);
8585 }
8586 break;
8587
8588 case TARGET_NR_mq_unlink:
8589 p = lock_user_string(arg1 - 1);
8590 ret = get_errno(mq_unlink(p));
8591 unlock_user (p, arg1, 0);
8592 break;
8593
8594 case TARGET_NR_mq_timedsend:
8595 {
8596 struct timespec ts;
8597
8598 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8599 if (arg5 != 0) {
8600 target_to_host_timespec(&ts, arg5);
8601 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8602 host_to_target_timespec(arg5, &ts);
8603 }
8604 else
8605 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8606 unlock_user (p, arg2, arg3);
8607 }
8608 break;
8609
8610 case TARGET_NR_mq_timedreceive:
8611 {
8612 struct timespec ts;
8613 unsigned int prio;
8614
8615 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8616 if (arg5 != 0) {
8617 target_to_host_timespec(&ts, arg5);
8618 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8619 host_to_target_timespec(arg5, &ts);
8620 }
8621 else
8622 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8623 unlock_user (p, arg2, arg3);
8624 if (arg4 != 0)
8625 put_user_u32(prio, arg4);
8626 }
8627 break;
8628
8629 /* Not implemented for now... */
8630/* case TARGET_NR_mq_notify: */
8631/* break; */
8632
8633 case TARGET_NR_mq_getsetattr:
8634 {
8635 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8636 ret = 0;
8637 if (arg3 != 0) {
8638 ret = mq_getattr(arg1, &posix_mq_attr_out);
8639 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8640 }
8641 if (arg2 != 0) {
8642 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8643 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8644 }
8645
8646 }
8647 break;
8648#endif
8649
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308650#ifdef CONFIG_SPLICE
8651#ifdef TARGET_NR_tee
8652 case TARGET_NR_tee:
8653 {
8654 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8655 }
8656 break;
8657#endif
8658#ifdef TARGET_NR_splice
8659 case TARGET_NR_splice:
8660 {
8661 loff_t loff_in, loff_out;
8662 loff_t *ploff_in = NULL, *ploff_out = NULL;
8663 if(arg2) {
8664 get_user_u64(loff_in, arg2);
8665 ploff_in = &loff_in;
8666 }
8667 if(arg4) {
8668 get_user_u64(loff_out, arg2);
8669 ploff_out = &loff_out;
8670 }
8671 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8672 }
8673 break;
8674#endif
8675#ifdef TARGET_NR_vmsplice
8676 case TARGET_NR_vmsplice:
8677 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008678 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8679 if (vec != NULL) {
8680 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8681 unlock_iovec(vec, arg2, arg3, 0);
8682 } else {
8683 ret = -host_to_target_errno(errno);
8684 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308685 }
8686 break;
8687#endif
8688#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008689#ifdef CONFIG_EVENTFD
8690#if defined(TARGET_NR_eventfd)
8691 case TARGET_NR_eventfd:
8692 ret = get_errno(eventfd(arg1, 0));
8693 break;
8694#endif
8695#if defined(TARGET_NR_eventfd2)
8696 case TARGET_NR_eventfd2:
8697 ret = get_errno(eventfd(arg1, arg2));
8698 break;
8699#endif
8700#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008701#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8702 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008703#if TARGET_ABI_BITS == 32
8704 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8705 target_offset64(arg5, arg6)));
8706#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008707 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008708#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008709 break;
8710#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008711#if defined(CONFIG_SYNC_FILE_RANGE)
8712#if defined(TARGET_NR_sync_file_range)
8713 case TARGET_NR_sync_file_range:
8714#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008715#if defined(TARGET_MIPS)
8716 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8717 target_offset64(arg5, arg6), arg7));
8718#else
Peter Maydellc727f472011-01-06 11:05:10 +00008719 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8720 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008721#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008722#else
8723 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8724#endif
8725 break;
8726#endif
8727#if defined(TARGET_NR_sync_file_range2)
8728 case TARGET_NR_sync_file_range2:
8729 /* This is like sync_file_range but the arguments are reordered */
8730#if TARGET_ABI_BITS == 32
8731 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8732 target_offset64(arg5, arg6), arg2));
8733#else
8734 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8735#endif
8736 break;
8737#endif
8738#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008739#if defined(CONFIG_EPOLL)
8740#if defined(TARGET_NR_epoll_create)
8741 case TARGET_NR_epoll_create:
8742 ret = get_errno(epoll_create(arg1));
8743 break;
8744#endif
8745#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8746 case TARGET_NR_epoll_create1:
8747 ret = get_errno(epoll_create1(arg1));
8748 break;
8749#endif
8750#if defined(TARGET_NR_epoll_ctl)
8751 case TARGET_NR_epoll_ctl:
8752 {
8753 struct epoll_event ep;
8754 struct epoll_event *epp = 0;
8755 if (arg4) {
8756 struct target_epoll_event *target_ep;
8757 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8758 goto efault;
8759 }
8760 ep.events = tswap32(target_ep->events);
8761 /* The epoll_data_t union is just opaque data to the kernel,
8762 * so we transfer all 64 bits across and need not worry what
8763 * actual data type it is.
8764 */
8765 ep.data.u64 = tswap64(target_ep->data.u64);
8766 unlock_user_struct(target_ep, arg4, 0);
8767 epp = &ep;
8768 }
8769 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8770 break;
8771 }
8772#endif
8773
8774#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8775#define IMPLEMENT_EPOLL_PWAIT
8776#endif
8777#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8778#if defined(TARGET_NR_epoll_wait)
8779 case TARGET_NR_epoll_wait:
8780#endif
8781#if defined(IMPLEMENT_EPOLL_PWAIT)
8782 case TARGET_NR_epoll_pwait:
8783#endif
8784 {
8785 struct target_epoll_event *target_ep;
8786 struct epoll_event *ep;
8787 int epfd = arg1;
8788 int maxevents = arg3;
8789 int timeout = arg4;
8790
8791 target_ep = lock_user(VERIFY_WRITE, arg2,
8792 maxevents * sizeof(struct target_epoll_event), 1);
8793 if (!target_ep) {
8794 goto efault;
8795 }
8796
8797 ep = alloca(maxevents * sizeof(struct epoll_event));
8798
8799 switch (num) {
8800#if defined(IMPLEMENT_EPOLL_PWAIT)
8801 case TARGET_NR_epoll_pwait:
8802 {
8803 target_sigset_t *target_set;
8804 sigset_t _set, *set = &_set;
8805
8806 if (arg5) {
8807 target_set = lock_user(VERIFY_READ, arg5,
8808 sizeof(target_sigset_t), 1);
8809 if (!target_set) {
8810 unlock_user(target_ep, arg2, 0);
8811 goto efault;
8812 }
8813 target_to_host_sigset(set, target_set);
8814 unlock_user(target_set, arg5, 0);
8815 } else {
8816 set = NULL;
8817 }
8818
8819 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8820 break;
8821 }
8822#endif
8823#if defined(TARGET_NR_epoll_wait)
8824 case TARGET_NR_epoll_wait:
8825 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8826 break;
8827#endif
8828 default:
8829 ret = -TARGET_ENOSYS;
8830 }
8831 if (!is_error(ret)) {
8832 int i;
8833 for (i = 0; i < ret; i++) {
8834 target_ep[i].events = tswap32(ep[i].events);
8835 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8836 }
8837 }
8838 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8839 break;
8840 }
8841#endif
8842#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008843#ifdef TARGET_NR_prlimit64
8844 case TARGET_NR_prlimit64:
8845 {
8846 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8847 struct target_rlimit64 *target_rnew, *target_rold;
8848 struct host_rlimit64 rnew, rold, *rnewp = 0;
8849 if (arg3) {
8850 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8851 goto efault;
8852 }
8853 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8854 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8855 unlock_user_struct(target_rnew, arg3, 0);
8856 rnewp = &rnew;
8857 }
8858
8859 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8860 if (!is_error(ret) && arg4) {
8861 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8862 goto efault;
8863 }
8864 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8865 target_rold->rlim_max = tswap64(rold.rlim_max);
8866 unlock_user_struct(target_rold, arg4, 1);
8867 }
8868 break;
8869 }
8870#endif
bellard31e31b82003-02-18 22:55:36 +00008871 default:
8872 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008873 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008874#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 +00008875 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008876#endif
ths0da46a62007-10-20 20:23:07 +00008877 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008878 break;
8879 }
bellard579a97f2007-11-11 14:26:47 +00008880fail:
bellardc573ff62004-01-04 15:51:36 +00008881#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008882 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008883#endif
thsb92c47c2007-11-01 00:07:38 +00008884 if(do_strace)
8885 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008886 return ret;
bellard579a97f2007-11-11 14:26:47 +00008887efault:
8888 ret = -TARGET_EFAULT;
8889 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008890}