blob: 9a633571a7c3bd4e22efce8805faf520668e6d7f [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
bellard31e31b82003-02-18 22:55:36 +000031#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000032#include <sys/ipc.h>
33#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/wait.h>
35#include <sys/time.h>
36#include <sys/stat.h>
37#include <sys/mount.h>
ths39b9aae2007-02-11 18:36:44 +000038#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/resource.h>
40#include <sys/mman.h>
41#include <sys/swap.h>
42#include <signal.h>
43#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020044#ifdef __ia64__
45int __clone2(int (*fn)(void *), void *child_stack_base,
46 size_t stack_size, int flags, void *arg, ...);
47#endif
bellard31e31b82003-02-18 22:55:36 +000048#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000049#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000050#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000051#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000052#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000053#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000054#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000055#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000056#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000057#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000058#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000059//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000060#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000061#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020062#include <linux/wireless.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020063#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020064#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000065#include <sys/gmon.h>
66#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030067#ifdef CONFIG_EVENTFD
68#include <sys/eventfd.h>
69#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000070#ifdef CONFIG_EPOLL
71#include <sys/epoll.h>
72#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#ifdef CONFIG_ATTR
74#include <attr/xattr.h>
75#endif
bellard31e31b82003-02-18 22:55:36 +000076
77#define termios host_termios
78#define winsize host_winsize
79#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000080#define sgttyb host_sgttyb /* same as target */
81#define tchars host_tchars /* same as target */
82#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000083
84#include <linux/termios.h>
85#include <linux/unistd.h>
86#include <linux/utsname.h>
87#include <linux/cdrom.h>
88#include <linux/hdreg.h>
89#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000090#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000091#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030092#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000093#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000094#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020096#include <linux/fb.h>
97#include <linux/vt.h>
pbrookd7e40362008-05-23 16:06:43 +000098#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +010099#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000100
bellard3ef693a2003-03-23 20:17:16 +0000101#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000102
Juan Quintela2f7bb872009-07-27 16:13:24 +0200103#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000104#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
105 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
106#else
107/* XXX: Hardcode the above values. */
108#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000109#endif
110
bellard72f03902003-02-18 23:33:18 +0000111//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000112
bellard1a9353d2003-03-16 20:28:50 +0000113//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000114#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
115#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000116
bellard70a194b2003-08-11 22:20:16 +0000117
bellard70a194b2003-08-11 22:20:16 +0000118#undef _syscall0
119#undef _syscall1
120#undef _syscall2
121#undef _syscall3
122#undef _syscall4
123#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000124#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000125
bellard83fcb512006-06-14 13:37:16 +0000126#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000127static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000128{ \
129 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000130}
131
bellard83fcb512006-06-14 13:37:16 +0000132#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000133static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000134{ \
135 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000136}
137
bellard83fcb512006-06-14 13:37:16 +0000138#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000139static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000140{ \
141 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000142}
143
bellard83fcb512006-06-14 13:37:16 +0000144#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000145static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000146{ \
147 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000148}
149
bellard83fcb512006-06-14 13:37:16 +0000150#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000151static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000152{ \
153 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000154}
155
bellard83fcb512006-06-14 13:37:16 +0000156#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
157 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000158static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000159{ \
160 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000161}
bellard83fcb512006-06-14 13:37:16 +0000162
163
164#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
165 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000166static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
167 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000168{ \
169 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
170}
171
bellard70a194b2003-08-11 22:20:16 +0000172
bellard31e31b82003-02-18 22:55:36 +0000173#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000174#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000175#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000176#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000177#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000178#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000179#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000180#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000181#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000182#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000183#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000184#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000185#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000186#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000187#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000188#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000189#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000190#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000191#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000192#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000193#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000194#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000195#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000196#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000197#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000198#define __NR_sys_inotify_init __NR_inotify_init
199#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
200#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000201
Alexander Graf42a39fb2011-04-15 17:32:45 +0200202#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
203 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000204#define __NR__llseek __NR_lseek
205#endif
206
bellard72f03902003-02-18 23:33:18 +0000207#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000208_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000209#else
ths0da46a62007-10-20 20:23:07 +0000210/* This is a replacement for the host gettid() and must return a host
211 errno. */
bellard72f03902003-02-18 23:33:18 +0000212static int gettid(void) {
213 return -ENOSYS;
214}
215#endif
aurel323b3f24a2009-04-15 16:12:13 +0000216_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000217#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
218_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
219#endif
220_syscall2(int, sys_getpriority, int, which, int, who);
Richard Hendersond35b2612010-06-04 12:14:10 -0700221#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000222_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
223 loff_t *, res, uint, wh);
224#endif
225_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
226_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
227#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
228_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
229#endif
230#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
231_syscall2(int,sys_tkill,int,tid,int,sig)
232#endif
233#ifdef __NR_exit_group
234_syscall1(int,exit_group,int,error_code)
235#endif
236#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
237_syscall1(int,set_tid_address,int *,tidptr)
238#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200239#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000240#if defined(TARGET_NR_futex) && defined(__NR_futex)
241_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
242 const struct timespec *,timeout,int *,uaddr2,int,val3)
243#endif
244#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500245#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
246_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
247 unsigned long *, user_mask_ptr);
248#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
249_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
250 unsigned long *, user_mask_ptr);
aurel323b3f24a2009-04-15 16:12:13 +0000251
252static bitmask_transtbl fcntl_flags_tbl[] = {
253 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
254 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
255 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
256 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
257 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
258 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
259 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
260 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
261 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
262 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
263 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
264 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
265 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
266#if defined(O_DIRECT)
267 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
268#endif
269 { 0, 0, 0, 0 }
270};
271
272#define COPY_UTSNAME_FIELD(dest, src) \
273 do { \
274 /* __NEW_UTS_LEN doesn't include terminating null */ \
275 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
276 (dest)[__NEW_UTS_LEN] = '\0'; \
277 } while (0)
278
279static int sys_uname(struct new_utsname *buf)
280{
281 struct utsname uts_buf;
282
283 if (uname(&uts_buf) < 0)
284 return (-1);
285
286 /*
287 * Just in case these have some differences, we
288 * translate utsname to new_utsname (which is the
289 * struct linux kernel uses).
290 */
291
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200292 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000293 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
294 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
295 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
296 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
297 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
298#ifdef _GNU_SOURCE
299 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
300#endif
301 return (0);
302
303#undef COPY_UTSNAME_FIELD
304}
305
306static int sys_getcwd1(char *buf, size_t size)
307{
308 if (getcwd(buf, size) == NULL) {
309 /* getcwd() sets errno */
310 return (-1);
311 }
aurel32aaf4ad32009-04-16 14:17:14 +0000312 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000313}
314
315#ifdef CONFIG_ATFILE
316/*
317 * Host system seems to have atfile syscall stubs available. We
318 * now enable them one by one as specified by target syscall_nr.h.
319 */
320
321#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000322static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000323{
aurel32465c9f02009-04-19 08:52:17 +0000324 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000325}
326#endif
327#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000328static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000329{
aurel32465c9f02009-04-19 08:52:17 +0000330 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000331}
332#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300333#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000334static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
335 gid_t group, int flags)
336{
337 return (fchownat(dirfd, pathname, owner, group, flags));
338}
339#endif
340#ifdef __NR_fstatat64
341static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
342 int flags)
343{
344 return (fstatat(dirfd, pathname, buf, flags));
345}
346#endif
347#ifdef __NR_newfstatat
348static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
349 int flags)
350{
351 return (fstatat(dirfd, pathname, buf, flags));
352}
353#endif
354#ifdef TARGET_NR_futimesat
355static int sys_futimesat(int dirfd, const char *pathname,
356 const struct timeval times[2])
357{
358 return (futimesat(dirfd, pathname, times));
359}
360#endif
361#ifdef TARGET_NR_linkat
362static int sys_linkat(int olddirfd, const char *oldpath,
363 int newdirfd, const char *newpath, int flags)
364{
365 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
366}
367#endif
368#ifdef TARGET_NR_mkdirat
369static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
370{
371 return (mkdirat(dirfd, pathname, mode));
372}
373#endif
374#ifdef TARGET_NR_mknodat
375static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
376 dev_t dev)
377{
378 return (mknodat(dirfd, pathname, mode, dev));
379}
380#endif
381#ifdef TARGET_NR_openat
382static int sys_openat(int dirfd, const char *pathname, int flags, ...)
383{
384 /*
385 * open(2) has extra parameter 'mode' when called with
386 * flag O_CREAT.
387 */
388 if ((flags & O_CREAT) != 0) {
389 va_list ap;
390 mode_t mode;
391
392 /*
393 * Get the 'mode' parameter and translate it to
394 * host bits.
395 */
396 va_start(ap, flags);
397 mode = va_arg(ap, mode_t);
398 mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
399 va_end(ap);
400
401 return (openat(dirfd, pathname, flags, mode));
402 }
403 return (openat(dirfd, pathname, flags));
404}
405#endif
406#ifdef TARGET_NR_readlinkat
407static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
408{
409 return (readlinkat(dirfd, pathname, buf, bufsiz));
410}
411#endif
412#ifdef TARGET_NR_renameat
413static int sys_renameat(int olddirfd, const char *oldpath,
414 int newdirfd, const char *newpath)
415{
416 return (renameat(olddirfd, oldpath, newdirfd, newpath));
417}
418#endif
419#ifdef TARGET_NR_symlinkat
420static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
421{
422 return (symlinkat(oldpath, newdirfd, newpath));
423}
424#endif
425#ifdef TARGET_NR_unlinkat
426static int sys_unlinkat(int dirfd, const char *pathname, int flags)
427{
428 return (unlinkat(dirfd, pathname, flags));
429}
430#endif
aurel323b3f24a2009-04-15 16:12:13 +0000431#else /* !CONFIG_ATFILE */
432
433/*
434 * Try direct syscalls instead
435 */
ths92a34c12007-09-24 09:27:49 +0000436#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000437_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000438#endif
ths814d7972007-09-24 09:26:51 +0000439#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000440_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000441#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300442#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000443_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
444 uid_t,owner,gid_t,group,int,flags)
445#endif
aurel329d33b762009-04-08 23:07:05 +0000446#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
447 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000448_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
449 struct stat *,buf,int,flags)
450#endif
balrogac8a6552008-09-20 02:25:39 +0000451#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
452_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
453 const struct timeval *,times)
454#endif
aurel323b3f24a2009-04-15 16:12:13 +0000455#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
456 defined(__NR_newfstatat)
457_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
458 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000459#endif
ths64f0ce42007-09-24 09:25:06 +0000460#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
461_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000462 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000463#endif
ths4472ad02007-09-24 09:22:32 +0000464#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
465_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
466#endif
ths75ac37a2007-09-24 09:23:05 +0000467#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
468_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
469 mode_t,mode,dev_t,dev)
470#endif
ths82424832007-09-24 09:21:55 +0000471#if defined(TARGET_NR_openat) && defined(__NR_openat)
472_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
473#endif
ths5e0ccb12007-09-24 09:26:10 +0000474#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
475_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
476 char *,buf,size_t,bufsize)
477#endif
ths722183f2007-09-24 09:24:37 +0000478#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
479_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
480 int,newdirfd,const char *,newpath)
481#endif
thsb51eaa82007-09-25 16:09:22 +0000482#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000483_syscall3(int,sys_symlinkat,const char *,oldpath,
484 int,newdirfd,const char *,newpath)
485#endif
ths8170f562007-09-24 09:24:11 +0000486#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
487_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
488#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300489
490#endif /* CONFIG_ATFILE */
491
492#ifdef CONFIG_UTIMENSAT
493static int sys_utimensat(int dirfd, const char *pathname,
494 const struct timespec times[2], int flags)
495{
496 if (pathname == NULL)
497 return futimens(dirfd, times);
498 else
499 return utimensat(dirfd, pathname, times, flags);
500}
501#else
ths9007f0e2007-09-25 17:50:37 +0000502#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
503_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
504 const struct timespec *,tsp,int,flags)
505#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300506#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000507
508#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000509#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000510
aurel3239b59762008-10-01 21:46:50 +0000511#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000512static int sys_inotify_init(void)
513{
514 return (inotify_init());
515}
aurel3239b59762008-10-01 21:46:50 +0000516#endif
517#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000518static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
519{
520 return (inotify_add_watch(fd, pathname, mask));
521}
aurel3239b59762008-10-01 21:46:50 +0000522#endif
523#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000524static int sys_inotify_rm_watch(int fd, int32_t wd)
525{
aurel328690e422009-04-17 13:50:32 +0000526 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000527}
aurel3239b59762008-10-01 21:46:50 +0000528#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000529#ifdef CONFIG_INOTIFY1
530#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
531static int sys_inotify_init1(int flags)
532{
533 return (inotify_init1(flags));
534}
535#endif
536#endif
aurel323b3f24a2009-04-15 16:12:13 +0000537#else
538/* Userspace can usually survive runtime without inotify */
539#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000540#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000541#undef TARGET_NR_inotify_add_watch
542#undef TARGET_NR_inotify_rm_watch
543#endif /* CONFIG_INOTIFY */
544
Mike Frysingerd8035d42011-02-07 01:05:51 -0500545#if defined(TARGET_NR_ppoll)
546#ifndef __NR_ppoll
547# define __NR_ppoll -1
548#endif
549#define __NR_sys_ppoll __NR_ppoll
550_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
551 struct timespec *, timeout, const __sigset_t *, sigmask,
552 size_t, sigsetsize)
553#endif
bellard66fb9762003-03-23 01:06:05 +0000554
Mike Frysinger055e0902011-06-03 17:01:49 -0400555#if defined(TARGET_NR_pselect6)
556#ifndef __NR_pselect6
557# define __NR_pselect6 -1
558#endif
559#define __NR_sys_pselect6 __NR_pselect6
560_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
561 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
562#endif
563
Peter Maydell163a05a2011-06-27 17:44:52 +0100564#if defined(TARGET_NR_prlimit64)
565#ifndef __NR_prlimit64
566# define __NR_prlimit64 -1
567#endif
568#define __NR_sys_prlimit64 __NR_prlimit64
569/* The glibc rlimit structure may not be that used by the underlying syscall */
570struct host_rlimit64 {
571 uint64_t rlim_cur;
572 uint64_t rlim_max;
573};
574_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
575 const struct host_rlimit64 *, new_limit,
576 struct host_rlimit64 *, old_limit)
577#endif
578
bellard66fb9762003-03-23 01:06:05 +0000579extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000580extern int flock(int, int);
581extern int setfsuid(int);
582extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000583extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000584
Riku Voipio48e515d2011-07-12 15:40:51 +0300585/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
586#ifdef TARGET_ARM
587static inline int regpairs_aligned(void *cpu_env) {
588 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
589}
590#elif defined(TARGET_MIPS)
591static inline int regpairs_aligned(void *cpu_env) { return 1; }
592#else
593static inline int regpairs_aligned(void *cpu_env) { return 0; }
594#endif
595
thsb92c47c2007-11-01 00:07:38 +0000596#define ERRNO_TABLE_SIZE 1200
597
598/* target_to_host_errno_table[] is initialized from
599 * host_to_target_errno_table[] in syscall_init(). */
600static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
601};
602
ths637947f2007-06-01 12:09:19 +0000603/*
thsfe8f0962007-07-12 10:59:21 +0000604 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000605 * minus the errnos that are not actually generic to all archs.
606 */
thsb92c47c2007-11-01 00:07:38 +0000607static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000608 [EIDRM] = TARGET_EIDRM,
609 [ECHRNG] = TARGET_ECHRNG,
610 [EL2NSYNC] = TARGET_EL2NSYNC,
611 [EL3HLT] = TARGET_EL3HLT,
612 [EL3RST] = TARGET_EL3RST,
613 [ELNRNG] = TARGET_ELNRNG,
614 [EUNATCH] = TARGET_EUNATCH,
615 [ENOCSI] = TARGET_ENOCSI,
616 [EL2HLT] = TARGET_EL2HLT,
617 [EDEADLK] = TARGET_EDEADLK,
618 [ENOLCK] = TARGET_ENOLCK,
619 [EBADE] = TARGET_EBADE,
620 [EBADR] = TARGET_EBADR,
621 [EXFULL] = TARGET_EXFULL,
622 [ENOANO] = TARGET_ENOANO,
623 [EBADRQC] = TARGET_EBADRQC,
624 [EBADSLT] = TARGET_EBADSLT,
625 [EBFONT] = TARGET_EBFONT,
626 [ENOSTR] = TARGET_ENOSTR,
627 [ENODATA] = TARGET_ENODATA,
628 [ETIME] = TARGET_ETIME,
629 [ENOSR] = TARGET_ENOSR,
630 [ENONET] = TARGET_ENONET,
631 [ENOPKG] = TARGET_ENOPKG,
632 [EREMOTE] = TARGET_EREMOTE,
633 [ENOLINK] = TARGET_ENOLINK,
634 [EADV] = TARGET_EADV,
635 [ESRMNT] = TARGET_ESRMNT,
636 [ECOMM] = TARGET_ECOMM,
637 [EPROTO] = TARGET_EPROTO,
638 [EDOTDOT] = TARGET_EDOTDOT,
639 [EMULTIHOP] = TARGET_EMULTIHOP,
640 [EBADMSG] = TARGET_EBADMSG,
641 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
642 [EOVERFLOW] = TARGET_EOVERFLOW,
643 [ENOTUNIQ] = TARGET_ENOTUNIQ,
644 [EBADFD] = TARGET_EBADFD,
645 [EREMCHG] = TARGET_EREMCHG,
646 [ELIBACC] = TARGET_ELIBACC,
647 [ELIBBAD] = TARGET_ELIBBAD,
648 [ELIBSCN] = TARGET_ELIBSCN,
649 [ELIBMAX] = TARGET_ELIBMAX,
650 [ELIBEXEC] = TARGET_ELIBEXEC,
651 [EILSEQ] = TARGET_EILSEQ,
652 [ENOSYS] = TARGET_ENOSYS,
653 [ELOOP] = TARGET_ELOOP,
654 [ERESTART] = TARGET_ERESTART,
655 [ESTRPIPE] = TARGET_ESTRPIPE,
656 [ENOTEMPTY] = TARGET_ENOTEMPTY,
657 [EUSERS] = TARGET_EUSERS,
658 [ENOTSOCK] = TARGET_ENOTSOCK,
659 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
660 [EMSGSIZE] = TARGET_EMSGSIZE,
661 [EPROTOTYPE] = TARGET_EPROTOTYPE,
662 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
663 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
664 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
665 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
666 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
667 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
668 [EADDRINUSE] = TARGET_EADDRINUSE,
669 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
670 [ENETDOWN] = TARGET_ENETDOWN,
671 [ENETUNREACH] = TARGET_ENETUNREACH,
672 [ENETRESET] = TARGET_ENETRESET,
673 [ECONNABORTED] = TARGET_ECONNABORTED,
674 [ECONNRESET] = TARGET_ECONNRESET,
675 [ENOBUFS] = TARGET_ENOBUFS,
676 [EISCONN] = TARGET_EISCONN,
677 [ENOTCONN] = TARGET_ENOTCONN,
678 [EUCLEAN] = TARGET_EUCLEAN,
679 [ENOTNAM] = TARGET_ENOTNAM,
680 [ENAVAIL] = TARGET_ENAVAIL,
681 [EISNAM] = TARGET_EISNAM,
682 [EREMOTEIO] = TARGET_EREMOTEIO,
683 [ESHUTDOWN] = TARGET_ESHUTDOWN,
684 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
685 [ETIMEDOUT] = TARGET_ETIMEDOUT,
686 [ECONNREFUSED] = TARGET_ECONNREFUSED,
687 [EHOSTDOWN] = TARGET_EHOSTDOWN,
688 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
689 [EALREADY] = TARGET_EALREADY,
690 [EINPROGRESS] = TARGET_EINPROGRESS,
691 [ESTALE] = TARGET_ESTALE,
692 [ECANCELED] = TARGET_ECANCELED,
693 [ENOMEDIUM] = TARGET_ENOMEDIUM,
694 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000695#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000696 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000697#endif
698#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000699 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000700#endif
701#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000702 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000703#endif
704#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000705 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000706#endif
707#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000708 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000709#endif
710#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000711 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000712#endif
thsb92c47c2007-11-01 00:07:38 +0000713};
ths637947f2007-06-01 12:09:19 +0000714
715static inline int host_to_target_errno(int err)
716{
717 if(host_to_target_errno_table[err])
718 return host_to_target_errno_table[err];
719 return err;
720}
721
thsb92c47c2007-11-01 00:07:38 +0000722static inline int target_to_host_errno(int err)
723{
724 if (target_to_host_errno_table[err])
725 return target_to_host_errno_table[err];
726 return err;
727}
728
blueswir1992f48a2007-10-14 16:27:31 +0000729static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000730{
731 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000732 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000733 else
734 return ret;
735}
736
blueswir1992f48a2007-10-14 16:27:31 +0000737static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000738{
blueswir1992f48a2007-10-14 16:27:31 +0000739 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000740}
741
thsb92c47c2007-11-01 00:07:38 +0000742char *target_strerror(int err)
743{
744 return strerror(target_to_host_errno(err));
745}
746
blueswir1992f48a2007-10-14 16:27:31 +0000747static abi_ulong target_brk;
748static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000749static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000750
blueswir1992f48a2007-10-14 16:27:31 +0000751void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000752{
blueswir14c1de732007-07-07 20:45:44 +0000753 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000754 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000755}
756
vincent4d1de872011-06-14 21:56:33 +0000757//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
758#define DEBUGF_BRK(message, args...)
759
ths0da46a62007-10-20 20:23:07 +0000760/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000761abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000762{
blueswir1992f48a2007-10-14 16:27:31 +0000763 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000764 int new_alloc_size;
765
vincent4d1de872011-06-14 21:56:33 +0000766 DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000767
vincent4d1de872011-06-14 21:56:33 +0000768 if (!new_brk) {
769 DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
770 return target_brk;
771 }
772 if (new_brk < target_original_brk) {
773 DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
774 return target_brk;
775 }
bellard31e31b82003-02-18 22:55:36 +0000776
vincent4d1de872011-06-14 21:56:33 +0000777 /* If the new brk is less than the highest page reserved to the
778 * target heap allocation, set it and we're almost done... */
779 if (new_brk <= brk_page) {
780 /* Heap contents are initialized to zero, as for anonymous
781 * mapped pages. */
782 if (new_brk > target_brk) {
783 memset(g2h(target_brk), 0, new_brk - target_brk);
784 }
bellard31e31b82003-02-18 22:55:36 +0000785 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000786 DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000787 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000788 }
789
Peter Maydell00faf082011-04-18 16:34:24 +0100790 /* We need to allocate more memory after the brk... Note that
791 * we don't use MAP_FIXED because that will map over the top of
792 * any existing mapping (like the one with the host libc or qemu
793 * itself); instead we treat "mapped but at wrong address" as
794 * a failure and unmap again.
795 */
vincent4d1de872011-06-14 21:56:33 +0000796 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000797 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000798 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100799 MAP_ANON|MAP_PRIVATE, 0, 0));
800
801 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200802 /* Heap contents are initialized to zero, as for anonymous
803 * mapped pages. Technically the new pages are already
804 * initialized to zero since they *are* anonymous mapped
805 * pages, however we have to take care with the contents that
806 * come from the remaining part of the previous page: it may
807 * contains garbage data due to a previous heap usage (grown
808 * then shrunken). */
809 memset(g2h(target_brk), 0, brk_page - target_brk);
810
Peter Maydell00faf082011-04-18 16:34:24 +0100811 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000812 brk_page = HOST_PAGE_ALIGN(target_brk);
813 DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100814 return target_brk;
815 } else if (mapped_addr != -1) {
816 /* Mapped but at wrong address, meaning there wasn't actually
817 * enough space for this brk.
818 */
819 target_munmap(mapped_addr, new_alloc_size);
820 mapped_addr = -1;
vincent4d1de872011-06-14 21:56:33 +0000821 DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
822 }
823 else {
824 DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100825 }
balrog7ab240a2008-04-26 12:17:34 +0000826
Richard Henderson7dd46c02010-05-03 10:07:49 -0700827#if defined(TARGET_ALPHA)
828 /* We (partially) emulate OSF/1 on Alpha, which requires we
829 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100830 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700831#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100832 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000833 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000834}
835
ths26edcf42007-12-09 02:25:24 +0000836static inline abi_long copy_from_user_fdset(fd_set *fds,
837 abi_ulong target_fds_addr,
838 int n)
bellard31e31b82003-02-18 22:55:36 +0000839{
ths26edcf42007-12-09 02:25:24 +0000840 int i, nw, j, k;
841 abi_ulong b, *target_fds;
842
843 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
844 if (!(target_fds = lock_user(VERIFY_READ,
845 target_fds_addr,
846 sizeof(abi_ulong) * nw,
847 1)))
848 return -TARGET_EFAULT;
849
850 FD_ZERO(fds);
851 k = 0;
852 for (i = 0; i < nw; i++) {
853 /* grab the abi_ulong */
854 __get_user(b, &target_fds[i]);
855 for (j = 0; j < TARGET_ABI_BITS; j++) {
856 /* check the bit inside the abi_ulong */
857 if ((b >> j) & 1)
858 FD_SET(k, fds);
859 k++;
bellard31e31b82003-02-18 22:55:36 +0000860 }
bellard31e31b82003-02-18 22:55:36 +0000861 }
ths26edcf42007-12-09 02:25:24 +0000862
863 unlock_user(target_fds, target_fds_addr, 0);
864
865 return 0;
bellard31e31b82003-02-18 22:55:36 +0000866}
867
Mike Frysinger055e0902011-06-03 17:01:49 -0400868static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
869 abi_ulong target_fds_addr,
870 int n)
871{
872 if (target_fds_addr) {
873 if (copy_from_user_fdset(fds, target_fds_addr, n))
874 return -TARGET_EFAULT;
875 *fds_ptr = fds;
876 } else {
877 *fds_ptr = NULL;
878 }
879 return 0;
880}
881
ths26edcf42007-12-09 02:25:24 +0000882static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
883 const fd_set *fds,
884 int n)
bellard31e31b82003-02-18 22:55:36 +0000885{
bellard31e31b82003-02-18 22:55:36 +0000886 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000887 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000888 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000889
ths26edcf42007-12-09 02:25:24 +0000890 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
891 if (!(target_fds = lock_user(VERIFY_WRITE,
892 target_fds_addr,
893 sizeof(abi_ulong) * nw,
894 0)))
895 return -TARGET_EFAULT;
896
897 k = 0;
898 for (i = 0; i < nw; i++) {
899 v = 0;
900 for (j = 0; j < TARGET_ABI_BITS; j++) {
901 v |= ((FD_ISSET(k, fds) != 0) << j);
902 k++;
bellard31e31b82003-02-18 22:55:36 +0000903 }
ths26edcf42007-12-09 02:25:24 +0000904 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000905 }
ths26edcf42007-12-09 02:25:24 +0000906
907 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
908
909 return 0;
bellard31e31b82003-02-18 22:55:36 +0000910}
911
bellardc596ed12003-07-13 17:32:31 +0000912#if defined(__alpha__)
913#define HOST_HZ 1024
914#else
915#define HOST_HZ 100
916#endif
917
blueswir1992f48a2007-10-14 16:27:31 +0000918static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000919{
920#if HOST_HZ == TARGET_HZ
921 return ticks;
922#else
923 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
924#endif
925}
926
bellard579a97f2007-11-11 14:26:47 +0000927static inline abi_long host_to_target_rusage(abi_ulong target_addr,
928 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000929{
pbrook53a59602006-03-25 19:31:22 +0000930 struct target_rusage *target_rusage;
931
bellard579a97f2007-11-11 14:26:47 +0000932 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
933 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200934 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
935 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
936 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
937 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
938 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
939 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
940 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
941 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
942 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
943 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
944 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
945 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
946 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
947 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
948 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
949 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
950 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
951 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000952 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000953
954 return 0;
bellardb4091862003-05-16 15:39:34 +0000955}
956
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200957static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900958{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200959 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300960 rlim_t result;
961
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200962 target_rlim_swap = tswapal(target_rlim);
963 if (target_rlim_swap == TARGET_RLIM_INFINITY)
964 return RLIM_INFINITY;
965
966 result = target_rlim_swap;
967 if (target_rlim_swap != (rlim_t)result)
968 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300969
970 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900971}
972
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200973static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900974{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200975 abi_ulong target_rlim_swap;
976 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300977
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200978 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300979 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900980 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300981 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200982 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300983
984 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900985}
986
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300987static inline int target_to_host_resource(int code)
988{
989 switch (code) {
990 case TARGET_RLIMIT_AS:
991 return RLIMIT_AS;
992 case TARGET_RLIMIT_CORE:
993 return RLIMIT_CORE;
994 case TARGET_RLIMIT_CPU:
995 return RLIMIT_CPU;
996 case TARGET_RLIMIT_DATA:
997 return RLIMIT_DATA;
998 case TARGET_RLIMIT_FSIZE:
999 return RLIMIT_FSIZE;
1000 case TARGET_RLIMIT_LOCKS:
1001 return RLIMIT_LOCKS;
1002 case TARGET_RLIMIT_MEMLOCK:
1003 return RLIMIT_MEMLOCK;
1004 case TARGET_RLIMIT_MSGQUEUE:
1005 return RLIMIT_MSGQUEUE;
1006 case TARGET_RLIMIT_NICE:
1007 return RLIMIT_NICE;
1008 case TARGET_RLIMIT_NOFILE:
1009 return RLIMIT_NOFILE;
1010 case TARGET_RLIMIT_NPROC:
1011 return RLIMIT_NPROC;
1012 case TARGET_RLIMIT_RSS:
1013 return RLIMIT_RSS;
1014 case TARGET_RLIMIT_RTPRIO:
1015 return RLIMIT_RTPRIO;
1016 case TARGET_RLIMIT_SIGPENDING:
1017 return RLIMIT_SIGPENDING;
1018 case TARGET_RLIMIT_STACK:
1019 return RLIMIT_STACK;
1020 default:
1021 return code;
1022 }
1023}
1024
ths788f5ec2007-12-09 02:37:05 +00001025static inline abi_long copy_from_user_timeval(struct timeval *tv,
1026 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001027{
pbrook53a59602006-03-25 19:31:22 +00001028 struct target_timeval *target_tv;
1029
ths788f5ec2007-12-09 02:37:05 +00001030 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001031 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001032
1033 __get_user(tv->tv_sec, &target_tv->tv_sec);
1034 __get_user(tv->tv_usec, &target_tv->tv_usec);
1035
1036 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001037
1038 return 0;
bellard31e31b82003-02-18 22:55:36 +00001039}
1040
ths788f5ec2007-12-09 02:37:05 +00001041static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1042 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001043{
pbrook53a59602006-03-25 19:31:22 +00001044 struct target_timeval *target_tv;
1045
ths788f5ec2007-12-09 02:37:05 +00001046 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001047 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001048
1049 __put_user(tv->tv_sec, &target_tv->tv_sec);
1050 __put_user(tv->tv_usec, &target_tv->tv_usec);
1051
1052 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001053
1054 return 0;
bellard31e31b82003-02-18 22:55:36 +00001055}
1056
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001057#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1058#include <mqueue.h>
1059
aurel3224e10032009-04-15 16:11:43 +00001060static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1061 abi_ulong target_mq_attr_addr)
1062{
1063 struct target_mq_attr *target_mq_attr;
1064
1065 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1066 target_mq_attr_addr, 1))
1067 return -TARGET_EFAULT;
1068
1069 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1070 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1071 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1072 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1073
1074 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1075
1076 return 0;
1077}
1078
1079static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1080 const struct mq_attr *attr)
1081{
1082 struct target_mq_attr *target_mq_attr;
1083
1084 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1085 target_mq_attr_addr, 0))
1086 return -TARGET_EFAULT;
1087
1088 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1089 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1090 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1091 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1092
1093 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1094
1095 return 0;
1096}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001097#endif
bellard31e31b82003-02-18 22:55:36 +00001098
Mike Frysinger055e0902011-06-03 17:01:49 -04001099#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001100/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001101static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001102 abi_ulong rfd_addr, abi_ulong wfd_addr,
1103 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001104{
1105 fd_set rfds, wfds, efds;
1106 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1107 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001108 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001109
Mike Frysinger055e0902011-06-03 17:01:49 -04001110 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1111 if (ret) {
1112 return ret;
pbrook53a59602006-03-25 19:31:22 +00001113 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001114 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1115 if (ret) {
1116 return ret;
pbrook53a59602006-03-25 19:31:22 +00001117 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001118 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1119 if (ret) {
1120 return ret;
pbrook53a59602006-03-25 19:31:22 +00001121 }
ths3b46e622007-09-17 08:09:54 +00001122
ths26edcf42007-12-09 02:25:24 +00001123 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001124 if (copy_from_user_timeval(&tv, target_tv_addr))
1125 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001126 tv_ptr = &tv;
1127 } else {
1128 tv_ptr = NULL;
1129 }
ths26edcf42007-12-09 02:25:24 +00001130
bellard31e31b82003-02-18 22:55:36 +00001131 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001132
ths26edcf42007-12-09 02:25:24 +00001133 if (!is_error(ret)) {
1134 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1135 return -TARGET_EFAULT;
1136 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1137 return -TARGET_EFAULT;
1138 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1139 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001140
ths788f5ec2007-12-09 02:37:05 +00001141 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1142 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001143 }
bellard579a97f2007-11-11 14:26:47 +00001144
bellard31e31b82003-02-18 22:55:36 +00001145 return ret;
1146}
Mike Frysinger055e0902011-06-03 17:01:49 -04001147#endif
bellard31e31b82003-02-18 22:55:36 +00001148
Riku Voipio099d6b02009-05-05 12:10:04 +03001149static abi_long do_pipe2(int host_pipe[], int flags)
1150{
1151#ifdef CONFIG_PIPE2
1152 return pipe2(host_pipe, flags);
1153#else
1154 return -ENOSYS;
1155#endif
1156}
1157
Richard Hendersonfb41a662010-05-03 10:07:52 -07001158static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1159 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001160{
1161 int host_pipe[2];
1162 abi_long ret;
1163 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1164
1165 if (is_error(ret))
1166 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001167
1168 /* Several targets have special calling conventions for the original
1169 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1170 if (!is_pipe2) {
1171#if defined(TARGET_ALPHA)
1172 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1173 return host_pipe[0];
1174#elif defined(TARGET_MIPS)
1175 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1176 return host_pipe[0];
1177#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001178 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001179 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001180#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001181 }
1182
Riku Voipio099d6b02009-05-05 12:10:04 +03001183 if (put_user_s32(host_pipe[0], pipedes)
1184 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1185 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001186 return get_errno(ret);
1187}
1188
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001189static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1190 abi_ulong target_addr,
1191 socklen_t len)
1192{
1193 struct target_ip_mreqn *target_smreqn;
1194
1195 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1196 if (!target_smreqn)
1197 return -TARGET_EFAULT;
1198 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1199 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1200 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001201 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001202 unlock_user(target_smreqn, target_addr, 0);
1203
1204 return 0;
1205}
1206
bellard579a97f2007-11-11 14:26:47 +00001207static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1208 abi_ulong target_addr,
1209 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001210{
aurel32607175e2009-04-15 16:11:59 +00001211 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1212 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001213 struct target_sockaddr *target_saddr;
1214
bellard579a97f2007-11-11 14:26:47 +00001215 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1216 if (!target_saddr)
1217 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001218
1219 sa_family = tswap16(target_saddr->sa_family);
1220
1221 /* Oops. The caller might send a incomplete sun_path; sun_path
1222 * must be terminated by \0 (see the manual page), but
1223 * unfortunately it is quite common to specify sockaddr_un
1224 * length as "strlen(x->sun_path)" while it should be
1225 * "strlen(...) + 1". We'll fix that here if needed.
1226 * Linux kernel has a similar feature.
1227 */
1228
1229 if (sa_family == AF_UNIX) {
1230 if (len < unix_maxlen && len > 0) {
1231 char *cp = (char*)target_saddr;
1232
1233 if ( cp[len-1] && !cp[len] )
1234 len++;
1235 }
1236 if (len > unix_maxlen)
1237 len = unix_maxlen;
1238 }
1239
pbrook53a59602006-03-25 19:31:22 +00001240 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001241 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001242 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001243
1244 return 0;
bellard7854b052003-03-29 17:22:23 +00001245}
1246
bellard579a97f2007-11-11 14:26:47 +00001247static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1248 struct sockaddr *addr,
1249 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001250{
pbrook53a59602006-03-25 19:31:22 +00001251 struct target_sockaddr *target_saddr;
1252
bellard579a97f2007-11-11 14:26:47 +00001253 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1254 if (!target_saddr)
1255 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001256 memcpy(target_saddr, addr, len);
1257 target_saddr->sa_family = tswap16(addr->sa_family);
1258 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001259
1260 return 0;
bellard7854b052003-03-29 17:22:23 +00001261}
1262
pbrook53a59602006-03-25 19:31:22 +00001263/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001264static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1265 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001266{
1267 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001268 abi_long msg_controllen;
1269 abi_ulong target_cmsg_addr;
1270 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001271 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001272
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001273 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001274 if (msg_controllen < sizeof (struct target_cmsghdr))
1275 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001276 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001277 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1278 if (!target_cmsg)
1279 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001280
1281 while (cmsg && target_cmsg) {
1282 void *data = CMSG_DATA(cmsg);
1283 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1284
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001285 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001286 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1287
1288 space += CMSG_SPACE(len);
1289 if (space > msgh->msg_controllen) {
1290 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001291 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001292 break;
1293 }
1294
1295 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1296 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1297 cmsg->cmsg_len = CMSG_LEN(len);
1298
bellard3532fa72006-06-24 15:06:03 +00001299 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001300 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1301 memcpy(data, target_data, len);
1302 } else {
1303 int *fd = (int *)data;
1304 int *target_fd = (int *)target_data;
1305 int i, numfds = len / sizeof(int);
1306
1307 for (i = 0; i < numfds; i++)
1308 fd[i] = tswap32(target_fd[i]);
1309 }
1310
1311 cmsg = CMSG_NXTHDR(msgh, cmsg);
1312 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1313 }
bellard5a4a8982007-11-11 17:39:18 +00001314 unlock_user(target_cmsg, target_cmsg_addr, 0);
1315 the_end:
bellard7854b052003-03-29 17:22:23 +00001316 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001317 return 0;
bellard7854b052003-03-29 17:22:23 +00001318}
1319
pbrook53a59602006-03-25 19:31:22 +00001320/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001321static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1322 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001323{
1324 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001325 abi_long msg_controllen;
1326 abi_ulong target_cmsg_addr;
1327 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001328 socklen_t space = 0;
1329
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001330 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001331 if (msg_controllen < sizeof (struct target_cmsghdr))
1332 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001333 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001334 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1335 if (!target_cmsg)
1336 return -TARGET_EFAULT;
1337
bellard7854b052003-03-29 17:22:23 +00001338 while (cmsg && target_cmsg) {
1339 void *data = CMSG_DATA(cmsg);
1340 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1341
1342 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1343
1344 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001345 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001346 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001347 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001348 break;
1349 }
1350
1351 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1352 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001353 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001354
bellard3532fa72006-06-24 15:06:03 +00001355 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001356 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1357 memcpy(target_data, data, len);
1358 } else {
1359 int *fd = (int *)data;
1360 int *target_fd = (int *)target_data;
1361 int i, numfds = len / sizeof(int);
1362
1363 for (i = 0; i < numfds; i++)
1364 target_fd[i] = tswap32(fd[i]);
1365 }
1366
1367 cmsg = CMSG_NXTHDR(msgh, cmsg);
1368 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1369 }
bellard5a4a8982007-11-11 17:39:18 +00001370 unlock_user(target_cmsg, target_cmsg_addr, space);
1371 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001372 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001373 return 0;
bellard7854b052003-03-29 17:22:23 +00001374}
1375
ths0da46a62007-10-20 20:23:07 +00001376/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001377static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001378 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001379{
blueswir1992f48a2007-10-14 16:27:31 +00001380 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001381 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001382 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001383 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001384
bellard8853f862004-02-22 14:57:26 +00001385 switch(level) {
1386 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001387 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001388 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001389 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001390
bellard2f619692007-11-16 10:46:05 +00001391 if (get_user_u32(val, optval_addr))
1392 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001393 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1394 break;
1395 case SOL_IP:
1396 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001397 case IP_TOS:
1398 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001399 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001400 case IP_ROUTER_ALERT:
1401 case IP_RECVOPTS:
1402 case IP_RETOPTS:
1403 case IP_PKTINFO:
1404 case IP_MTU_DISCOVER:
1405 case IP_RECVERR:
1406 case IP_RECVTOS:
1407#ifdef IP_FREEBIND
1408 case IP_FREEBIND:
1409#endif
1410 case IP_MULTICAST_TTL:
1411 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001412 val = 0;
1413 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001414 if (get_user_u32(val, optval_addr))
1415 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001416 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001417 if (get_user_u8(val, optval_addr))
1418 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001419 }
1420 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1421 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001422 case IP_ADD_MEMBERSHIP:
1423 case IP_DROP_MEMBERSHIP:
1424 if (optlen < sizeof (struct target_ip_mreq) ||
1425 optlen > sizeof (struct target_ip_mreqn))
1426 return -TARGET_EINVAL;
1427
1428 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1429 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1430 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1431 break;
1432
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001433 case IP_BLOCK_SOURCE:
1434 case IP_UNBLOCK_SOURCE:
1435 case IP_ADD_SOURCE_MEMBERSHIP:
1436 case IP_DROP_SOURCE_MEMBERSHIP:
1437 if (optlen != sizeof (struct target_ip_mreq_source))
1438 return -TARGET_EINVAL;
1439
1440 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1441 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1442 unlock_user (ip_mreq_source, optval_addr, 0);
1443 break;
1444
bellard8853f862004-02-22 14:57:26 +00001445 default:
1446 goto unimplemented;
1447 }
1448 break;
bellard3532fa72006-06-24 15:06:03 +00001449 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001450 switch (optname) {
1451 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001452 case TARGET_SO_DEBUG:
1453 optname = SO_DEBUG;
1454 break;
1455 case TARGET_SO_REUSEADDR:
1456 optname = SO_REUSEADDR;
1457 break;
1458 case TARGET_SO_TYPE:
1459 optname = SO_TYPE;
1460 break;
1461 case TARGET_SO_ERROR:
1462 optname = SO_ERROR;
1463 break;
1464 case TARGET_SO_DONTROUTE:
1465 optname = SO_DONTROUTE;
1466 break;
1467 case TARGET_SO_BROADCAST:
1468 optname = SO_BROADCAST;
1469 break;
1470 case TARGET_SO_SNDBUF:
1471 optname = SO_SNDBUF;
1472 break;
1473 case TARGET_SO_RCVBUF:
1474 optname = SO_RCVBUF;
1475 break;
1476 case TARGET_SO_KEEPALIVE:
1477 optname = SO_KEEPALIVE;
1478 break;
1479 case TARGET_SO_OOBINLINE:
1480 optname = SO_OOBINLINE;
1481 break;
1482 case TARGET_SO_NO_CHECK:
1483 optname = SO_NO_CHECK;
1484 break;
1485 case TARGET_SO_PRIORITY:
1486 optname = SO_PRIORITY;
1487 break;
bellard5e83e8e2005-03-01 22:32:06 +00001488#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001489 case TARGET_SO_BSDCOMPAT:
1490 optname = SO_BSDCOMPAT;
1491 break;
bellard5e83e8e2005-03-01 22:32:06 +00001492#endif
bellard3532fa72006-06-24 15:06:03 +00001493 case TARGET_SO_PASSCRED:
1494 optname = SO_PASSCRED;
1495 break;
1496 case TARGET_SO_TIMESTAMP:
1497 optname = SO_TIMESTAMP;
1498 break;
1499 case TARGET_SO_RCVLOWAT:
1500 optname = SO_RCVLOWAT;
1501 break;
1502 case TARGET_SO_RCVTIMEO:
1503 optname = SO_RCVTIMEO;
1504 break;
1505 case TARGET_SO_SNDTIMEO:
1506 optname = SO_SNDTIMEO;
1507 break;
bellard8853f862004-02-22 14:57:26 +00001508 break;
1509 default:
1510 goto unimplemented;
1511 }
bellard3532fa72006-06-24 15:06:03 +00001512 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001513 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001514
bellard2f619692007-11-16 10:46:05 +00001515 if (get_user_u32(val, optval_addr))
1516 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001517 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001518 break;
bellard7854b052003-03-29 17:22:23 +00001519 default:
bellard8853f862004-02-22 14:57:26 +00001520 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001521 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001522 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001523 }
bellard8853f862004-02-22 14:57:26 +00001524 return ret;
bellard7854b052003-03-29 17:22:23 +00001525}
1526
ths0da46a62007-10-20 20:23:07 +00001527/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001528static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001529 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001530{
blueswir1992f48a2007-10-14 16:27:31 +00001531 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001532 int len, val;
1533 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001534
1535 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001536 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001537 level = SOL_SOCKET;
1538 switch (optname) {
1539 /* These don't just return a single integer */
1540 case TARGET_SO_LINGER:
1541 case TARGET_SO_RCVTIMEO:
1542 case TARGET_SO_SNDTIMEO:
1543 case TARGET_SO_PEERCRED:
1544 case TARGET_SO_PEERNAME:
1545 goto unimplemented;
1546 /* Options with 'int' argument. */
1547 case TARGET_SO_DEBUG:
1548 optname = SO_DEBUG;
1549 goto int_case;
1550 case TARGET_SO_REUSEADDR:
1551 optname = SO_REUSEADDR;
1552 goto int_case;
1553 case TARGET_SO_TYPE:
1554 optname = SO_TYPE;
1555 goto int_case;
1556 case TARGET_SO_ERROR:
1557 optname = SO_ERROR;
1558 goto int_case;
1559 case TARGET_SO_DONTROUTE:
1560 optname = SO_DONTROUTE;
1561 goto int_case;
1562 case TARGET_SO_BROADCAST:
1563 optname = SO_BROADCAST;
1564 goto int_case;
1565 case TARGET_SO_SNDBUF:
1566 optname = SO_SNDBUF;
1567 goto int_case;
1568 case TARGET_SO_RCVBUF:
1569 optname = SO_RCVBUF;
1570 goto int_case;
1571 case TARGET_SO_KEEPALIVE:
1572 optname = SO_KEEPALIVE;
1573 goto int_case;
1574 case TARGET_SO_OOBINLINE:
1575 optname = SO_OOBINLINE;
1576 goto int_case;
1577 case TARGET_SO_NO_CHECK:
1578 optname = SO_NO_CHECK;
1579 goto int_case;
1580 case TARGET_SO_PRIORITY:
1581 optname = SO_PRIORITY;
1582 goto int_case;
1583#ifdef SO_BSDCOMPAT
1584 case TARGET_SO_BSDCOMPAT:
1585 optname = SO_BSDCOMPAT;
1586 goto int_case;
1587#endif
1588 case TARGET_SO_PASSCRED:
1589 optname = SO_PASSCRED;
1590 goto int_case;
1591 case TARGET_SO_TIMESTAMP:
1592 optname = SO_TIMESTAMP;
1593 goto int_case;
1594 case TARGET_SO_RCVLOWAT:
1595 optname = SO_RCVLOWAT;
1596 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001597 default:
bellard2efbe912005-07-23 15:10:20 +00001598 goto int_case;
1599 }
1600 break;
1601 case SOL_TCP:
1602 /* TCP options all take an 'int' value. */
1603 int_case:
bellard2f619692007-11-16 10:46:05 +00001604 if (get_user_u32(len, optlen))
1605 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001606 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001607 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001608 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001609 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1610 if (ret < 0)
1611 return ret;
bellard2efbe912005-07-23 15:10:20 +00001612 if (len > lv)
1613 len = lv;
bellard2f619692007-11-16 10:46:05 +00001614 if (len == 4) {
1615 if (put_user_u32(val, optval_addr))
1616 return -TARGET_EFAULT;
1617 } else {
1618 if (put_user_u8(val, optval_addr))
1619 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001620 }
bellard2f619692007-11-16 10:46:05 +00001621 if (put_user_u32(len, optlen))
1622 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001623 break;
1624 case SOL_IP:
1625 switch(optname) {
1626 case IP_TOS:
1627 case IP_TTL:
1628 case IP_HDRINCL:
1629 case IP_ROUTER_ALERT:
1630 case IP_RECVOPTS:
1631 case IP_RETOPTS:
1632 case IP_PKTINFO:
1633 case IP_MTU_DISCOVER:
1634 case IP_RECVERR:
1635 case IP_RECVTOS:
1636#ifdef IP_FREEBIND
1637 case IP_FREEBIND:
1638#endif
1639 case IP_MULTICAST_TTL:
1640 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001641 if (get_user_u32(len, optlen))
1642 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001643 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001644 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001645 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001646 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1647 if (ret < 0)
1648 return ret;
bellard2efbe912005-07-23 15:10:20 +00001649 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001650 len = 1;
bellard2f619692007-11-16 10:46:05 +00001651 if (put_user_u32(len, optlen)
1652 || put_user_u8(val, optval_addr))
1653 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001654 } else {
bellard2efbe912005-07-23 15:10:20 +00001655 if (len > sizeof(int))
1656 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001657 if (put_user_u32(len, optlen)
1658 || put_user_u32(val, optval_addr))
1659 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001660 }
bellard8853f862004-02-22 14:57:26 +00001661 break;
bellard2efbe912005-07-23 15:10:20 +00001662 default:
thsc02f4992007-12-18 02:39:59 +00001663 ret = -TARGET_ENOPROTOOPT;
1664 break;
bellard8853f862004-02-22 14:57:26 +00001665 }
1666 break;
1667 default:
1668 unimplemented:
1669 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1670 level, optname);
thsc02f4992007-12-18 02:39:59 +00001671 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001672 break;
1673 }
1674 return ret;
bellard7854b052003-03-29 17:22:23 +00001675}
1676
bellard579a97f2007-11-11 14:26:47 +00001677/* FIXME
1678 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1679 * other lock functions have a return code of 0 for failure.
1680 */
1681static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1682 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001683{
1684 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001685 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001686 int i;
pbrook53a59602006-03-25 19:31:22 +00001687
bellard579a97f2007-11-11 14:26:47 +00001688 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1689 if (!target_vec)
1690 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001691 for(i = 0;i < count; i++) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001692 base = tswapal(target_vec[i].iov_base);
1693 vec[i].iov_len = tswapal(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001694 if (vec[i].iov_len != 0) {
1695 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001696 /* Don't check lock_user return value. We must call writev even
1697 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001698 } else {
1699 /* zero length pointer is ignored */
1700 vec[i].iov_base = NULL;
1701 }
pbrook53a59602006-03-25 19:31:22 +00001702 }
1703 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001704 return 0;
pbrook53a59602006-03-25 19:31:22 +00001705}
1706
bellard579a97f2007-11-11 14:26:47 +00001707static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1708 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001709{
1710 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001711 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001712 int i;
1713
bellard579a97f2007-11-11 14:26:47 +00001714 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1715 if (!target_vec)
1716 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001717 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001718 if (target_vec[i].iov_base) {
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001719 base = tswapal(target_vec[i].iov_base);
balrogd732dcb2008-10-28 10:21:03 +00001720 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1721 }
pbrook53a59602006-03-25 19:31:22 +00001722 }
1723 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001724
1725 return 0;
pbrook53a59602006-03-25 19:31:22 +00001726}
1727
ths0da46a62007-10-20 20:23:07 +00001728/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001729static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001730{
1731#if defined(TARGET_MIPS)
1732 switch(type) {
1733 case TARGET_SOCK_DGRAM:
1734 type = SOCK_DGRAM;
1735 break;
1736 case TARGET_SOCK_STREAM:
1737 type = SOCK_STREAM;
1738 break;
1739 case TARGET_SOCK_RAW:
1740 type = SOCK_RAW;
1741 break;
1742 case TARGET_SOCK_RDM:
1743 type = SOCK_RDM;
1744 break;
1745 case TARGET_SOCK_SEQPACKET:
1746 type = SOCK_SEQPACKET;
1747 break;
1748 case TARGET_SOCK_PACKET:
1749 type = SOCK_PACKET;
1750 break;
1751 }
1752#endif
balrog12bc92a2007-10-30 21:06:14 +00001753 if (domain == PF_NETLINK)
1754 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001755 return get_errno(socket(domain, type, protocol));
1756}
1757
ths0da46a62007-10-20 20:23:07 +00001758/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001759static abi_long do_bind(int sockfd, abi_ulong target_addr,
1760 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001761{
aurel328f7aeaf2009-01-30 19:47:57 +00001762 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001763 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001764
Blue Swirl38724252010-09-18 05:53:14 +00001765 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001766 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001767 }
aurel328f7aeaf2009-01-30 19:47:57 +00001768
aurel32607175e2009-04-15 16:11:59 +00001769 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001770
Arnaud Patard917507b2009-06-19 10:44:45 +03001771 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1772 if (ret)
1773 return ret;
1774
bellard3532fa72006-06-24 15:06:03 +00001775 return get_errno(bind(sockfd, addr, addrlen));
1776}
1777
ths0da46a62007-10-20 20:23:07 +00001778/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001779static abi_long do_connect(int sockfd, abi_ulong target_addr,
1780 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001781{
aurel328f7aeaf2009-01-30 19:47:57 +00001782 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001783 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001784
Blue Swirl38724252010-09-18 05:53:14 +00001785 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001786 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001787 }
aurel328f7aeaf2009-01-30 19:47:57 +00001788
1789 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001790
Arnaud Patard917507b2009-06-19 10:44:45 +03001791 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1792 if (ret)
1793 return ret;
1794
bellard3532fa72006-06-24 15:06:03 +00001795 return get_errno(connect(sockfd, addr, addrlen));
1796}
1797
ths0da46a62007-10-20 20:23:07 +00001798/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001799static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1800 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001801{
balrog6de645c2008-10-28 10:26:29 +00001802 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001803 struct target_msghdr *msgp;
1804 struct msghdr msg;
1805 int count;
1806 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001807 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001808
bellard579a97f2007-11-11 14:26:47 +00001809 /* FIXME */
1810 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1811 msgp,
1812 target_msg,
1813 send ? 1 : 0))
1814 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001815 if (msgp->msg_name) {
1816 msg.msg_namelen = tswap32(msgp->msg_namelen);
1817 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001818 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001819 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001820 if (ret) {
1821 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1822 return ret;
1823 }
bellard3532fa72006-06-24 15:06:03 +00001824 } else {
1825 msg.msg_name = NULL;
1826 msg.msg_namelen = 0;
1827 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001828 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001829 msg.msg_control = alloca(msg.msg_controllen);
1830 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001831
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001832 count = tswapal(msgp->msg_iovlen);
bellard3532fa72006-06-24 15:06:03 +00001833 vec = alloca(count * sizeof(struct iovec));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001834 target_vec = tswapal(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001835 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001836 msg.msg_iovlen = count;
1837 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001838
bellard3532fa72006-06-24 15:06:03 +00001839 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001840 ret = target_to_host_cmsg(&msg, msgp);
1841 if (ret == 0)
1842 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001843 } else {
1844 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001845 if (!is_error(ret)) {
1846 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001847 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001848 if (!is_error(ret))
1849 ret = len;
1850 }
bellard3532fa72006-06-24 15:06:03 +00001851 }
1852 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001853 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001854 return ret;
1855}
1856
ths0da46a62007-10-20 20:23:07 +00001857/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001858static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001859 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001860{
bellard2f619692007-11-16 10:46:05 +00001861 socklen_t addrlen;
1862 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001863 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001864
Arnaud Patard917507b2009-06-19 10:44:45 +03001865 if (target_addr == 0)
1866 return get_errno(accept(fd, NULL, NULL));
1867
1868 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001869 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001870 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001871
Blue Swirl38724252010-09-18 05:53:14 +00001872 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001873 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001874 }
aurel328f7aeaf2009-01-30 19:47:57 +00001875
Arnaud Patard917507b2009-06-19 10:44:45 +03001876 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1877 return -TARGET_EINVAL;
1878
bellard2f619692007-11-16 10:46:05 +00001879 addr = alloca(addrlen);
1880
pbrook1be9e1d2006-11-19 15:26:04 +00001881 ret = get_errno(accept(fd, addr, &addrlen));
1882 if (!is_error(ret)) {
1883 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001884 if (put_user_u32(addrlen, target_addrlen_addr))
1885 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001886 }
1887 return ret;
1888}
1889
ths0da46a62007-10-20 20:23:07 +00001890/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001891static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001892 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001893{
bellard2f619692007-11-16 10:46:05 +00001894 socklen_t addrlen;
1895 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001896 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001897
bellard2f619692007-11-16 10:46:05 +00001898 if (get_user_u32(addrlen, target_addrlen_addr))
1899 return -TARGET_EFAULT;
1900
Blue Swirl38724252010-09-18 05:53:14 +00001901 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001902 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001903 }
aurel328f7aeaf2009-01-30 19:47:57 +00001904
Arnaud Patard917507b2009-06-19 10:44:45 +03001905 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1906 return -TARGET_EFAULT;
1907
bellard2f619692007-11-16 10:46:05 +00001908 addr = alloca(addrlen);
1909
pbrook1be9e1d2006-11-19 15:26:04 +00001910 ret = get_errno(getpeername(fd, addr, &addrlen));
1911 if (!is_error(ret)) {
1912 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001913 if (put_user_u32(addrlen, target_addrlen_addr))
1914 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001915 }
1916 return ret;
1917}
1918
ths0da46a62007-10-20 20:23:07 +00001919/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001920static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001921 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001922{
bellard2f619692007-11-16 10:46:05 +00001923 socklen_t addrlen;
1924 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001925 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001926
bellard2f619692007-11-16 10:46:05 +00001927 if (get_user_u32(addrlen, target_addrlen_addr))
1928 return -TARGET_EFAULT;
1929
Blue Swirl38724252010-09-18 05:53:14 +00001930 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001931 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001932 }
aurel328f7aeaf2009-01-30 19:47:57 +00001933
Arnaud Patard917507b2009-06-19 10:44:45 +03001934 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1935 return -TARGET_EFAULT;
1936
bellard2f619692007-11-16 10:46:05 +00001937 addr = alloca(addrlen);
1938
pbrook1be9e1d2006-11-19 15:26:04 +00001939 ret = get_errno(getsockname(fd, addr, &addrlen));
1940 if (!is_error(ret)) {
1941 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001942 if (put_user_u32(addrlen, target_addrlen_addr))
1943 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001944 }
1945 return ret;
1946}
1947
ths0da46a62007-10-20 20:23:07 +00001948/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001949static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001950 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001951{
1952 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001953 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001954
1955 ret = get_errno(socketpair(domain, type, protocol, tab));
1956 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001957 if (put_user_s32(tab[0], target_tab_addr)
1958 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1959 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001960 }
1961 return ret;
1962}
1963
ths0da46a62007-10-20 20:23:07 +00001964/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001965static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1966 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001967{
1968 void *addr;
1969 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001970 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001971
Blue Swirl38724252010-09-18 05:53:14 +00001972 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001973 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001974 }
aurel328f7aeaf2009-01-30 19:47:57 +00001975
bellard579a97f2007-11-11 14:26:47 +00001976 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1977 if (!host_msg)
1978 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001979 if (target_addr) {
1980 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001981 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1982 if (ret) {
1983 unlock_user(host_msg, msg, 0);
1984 return ret;
1985 }
pbrook1be9e1d2006-11-19 15:26:04 +00001986 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1987 } else {
1988 ret = get_errno(send(fd, host_msg, len, flags));
1989 }
1990 unlock_user(host_msg, msg, 0);
1991 return ret;
1992}
1993
ths0da46a62007-10-20 20:23:07 +00001994/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001995static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1996 abi_ulong target_addr,
1997 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001998{
1999 socklen_t addrlen;
2000 void *addr;
2001 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002002 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002003
bellard579a97f2007-11-11 14:26:47 +00002004 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2005 if (!host_msg)
2006 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002007 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002008 if (get_user_u32(addrlen, target_addrlen)) {
2009 ret = -TARGET_EFAULT;
2010 goto fail;
2011 }
Blue Swirl38724252010-09-18 05:53:14 +00002012 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002013 ret = -TARGET_EINVAL;
2014 goto fail;
2015 }
pbrook1be9e1d2006-11-19 15:26:04 +00002016 addr = alloca(addrlen);
2017 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2018 } else {
2019 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002020 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002021 }
2022 if (!is_error(ret)) {
2023 if (target_addr) {
2024 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002025 if (put_user_u32(addrlen, target_addrlen)) {
2026 ret = -TARGET_EFAULT;
2027 goto fail;
2028 }
pbrook1be9e1d2006-11-19 15:26:04 +00002029 }
2030 unlock_user(host_msg, msg, len);
2031 } else {
bellard2f619692007-11-16 10:46:05 +00002032fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002033 unlock_user(host_msg, msg, 0);
2034 }
2035 return ret;
2036}
2037
j_mayer32407102007-09-26 23:01:49 +00002038#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002039/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002040static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002041{
blueswir1992f48a2007-10-14 16:27:31 +00002042 abi_long ret;
2043 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002044
2045 switch(num) {
2046 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002047 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002048 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002049
Ulrich Hecht98818182009-07-03 17:09:28 +02002050 if (get_user_ual(domain, vptr)
2051 || get_user_ual(type, vptr + n)
2052 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002053 return -TARGET_EFAULT;
2054
bellard3532fa72006-06-24 15:06:03 +00002055 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002056 }
bellard31e31b82003-02-18 22:55:36 +00002057 break;
2058 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002059 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002060 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002061 abi_ulong target_addr;
2062 socklen_t addrlen;
2063
Ulrich Hecht98818182009-07-03 17:09:28 +02002064 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002065 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002066 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002067 return -TARGET_EFAULT;
2068
bellard3532fa72006-06-24 15:06:03 +00002069 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002070 }
bellard31e31b82003-02-18 22:55:36 +00002071 break;
2072 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002073 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002074 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002075 abi_ulong target_addr;
2076 socklen_t addrlen;
2077
Ulrich Hecht98818182009-07-03 17:09:28 +02002078 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002079 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002080 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002081 return -TARGET_EFAULT;
2082
bellard3532fa72006-06-24 15:06:03 +00002083 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002084 }
bellard31e31b82003-02-18 22:55:36 +00002085 break;
2086 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002087 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002088 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002089
Ulrich Hecht98818182009-07-03 17:09:28 +02002090 if (get_user_ual(sockfd, vptr)
2091 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002092 return -TARGET_EFAULT;
2093
bellard7854b052003-03-29 17:22:23 +00002094 ret = get_errno(listen(sockfd, backlog));
2095 }
bellard31e31b82003-02-18 22:55:36 +00002096 break;
2097 case SOCKOP_accept:
2098 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002099 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002100 abi_ulong target_addr, target_addrlen;
2101
Ulrich Hecht98818182009-07-03 17:09:28 +02002102 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002103 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002104 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002105 return -TARGET_EFAULT;
2106
pbrook1be9e1d2006-11-19 15:26:04 +00002107 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002108 }
2109 break;
2110 case SOCKOP_getsockname:
2111 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002112 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002113 abi_ulong target_addr, target_addrlen;
2114
Ulrich Hecht98818182009-07-03 17:09:28 +02002115 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002116 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002117 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002118 return -TARGET_EFAULT;
2119
pbrook1be9e1d2006-11-19 15:26:04 +00002120 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002121 }
2122 break;
2123 case SOCKOP_getpeername:
2124 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002125 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002126 abi_ulong target_addr, target_addrlen;
2127
Ulrich Hecht98818182009-07-03 17:09:28 +02002128 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002129 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002130 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002131 return -TARGET_EFAULT;
2132
pbrook1be9e1d2006-11-19 15:26:04 +00002133 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002134 }
2135 break;
2136 case SOCKOP_socketpair:
2137 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002138 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002139 abi_ulong tab;
2140
Ulrich Hecht98818182009-07-03 17:09:28 +02002141 if (get_user_ual(domain, vptr)
2142 || get_user_ual(type, vptr + n)
2143 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002144 || get_user_ual(tab, vptr + 3 * n))
2145 return -TARGET_EFAULT;
2146
pbrook1be9e1d2006-11-19 15:26:04 +00002147 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002148 }
2149 break;
2150 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002151 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002152 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002153 abi_ulong msg;
2154 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002155 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002156
Ulrich Hecht98818182009-07-03 17:09:28 +02002157 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002158 || get_user_ual(msg, vptr + n)
2159 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002160 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002161 return -TARGET_EFAULT;
2162
pbrook1be9e1d2006-11-19 15:26:04 +00002163 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002164 }
bellard31e31b82003-02-18 22:55:36 +00002165 break;
2166 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002167 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002168 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002169 abi_ulong msg;
2170 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002171 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002172
Ulrich Hecht98818182009-07-03 17:09:28 +02002173 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002174 || get_user_ual(msg, vptr + n)
2175 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002176 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002177 return -TARGET_EFAULT;
2178
pbrook1be9e1d2006-11-19 15:26:04 +00002179 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002180 }
bellard31e31b82003-02-18 22:55:36 +00002181 break;
2182 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002183 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002184 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002185 abi_ulong msg;
2186 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002187 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002188 abi_ulong 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(msg, vptr + n)
2193 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002194 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002195 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002196 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002197 return -TARGET_EFAULT;
2198
pbrook1be9e1d2006-11-19 15:26:04 +00002199 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002200 }
bellard31e31b82003-02-18 22:55:36 +00002201 break;
2202 case SOCKOP_recvfrom:
2203 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002204 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002205 abi_ulong msg;
2206 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002207 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002208 abi_ulong addr;
2209 socklen_t addrlen;
2210
Ulrich Hecht98818182009-07-03 17:09:28 +02002211 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002212 || get_user_ual(msg, vptr + n)
2213 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002214 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002215 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002216 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002217 return -TARGET_EFAULT;
2218
pbrook1be9e1d2006-11-19 15:26:04 +00002219 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002220 }
2221 break;
2222 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002223 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002224 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002225
Ulrich Hecht98818182009-07-03 17:09:28 +02002226 if (get_user_ual(sockfd, vptr)
2227 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002228 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002229
2230 ret = get_errno(shutdown(sockfd, how));
2231 }
bellard31e31b82003-02-18 22:55:36 +00002232 break;
2233 case SOCKOP_sendmsg:
2234 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002235 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002236 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002237 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002238 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002239
Ulrich Hecht98818182009-07-03 17:09:28 +02002240 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002241 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002242 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002243 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002244
ths5fafdf22007-09-16 21:08:06 +00002245 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002246 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002247 }
2248 break;
bellard31e31b82003-02-18 22:55:36 +00002249 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002250 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002251 abi_ulong sockfd;
2252 abi_ulong level;
2253 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002254 abi_ulong optval;
2255 socklen_t optlen;
2256
Ulrich Hecht98818182009-07-03 17:09:28 +02002257 if (get_user_ual(sockfd, vptr)
2258 || get_user_ual(level, vptr + n)
2259 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002260 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002261 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002262 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002263
2264 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2265 }
2266 break;
bellard31e31b82003-02-18 22:55:36 +00002267 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002268 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002269 abi_ulong sockfd;
2270 abi_ulong level;
2271 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002272 abi_ulong optval;
2273 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002274
Ulrich Hecht98818182009-07-03 17:09:28 +02002275 if (get_user_ual(sockfd, vptr)
2276 || get_user_ual(level, vptr + n)
2277 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002278 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002279 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002280 return -TARGET_EFAULT;
2281
2282 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002283 }
2284 break;
bellard31e31b82003-02-18 22:55:36 +00002285 default:
2286 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002287 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002288 break;
2289 }
2290 return ret;
2291}
j_mayer32407102007-09-26 23:01:49 +00002292#endif
bellard31e31b82003-02-18 22:55:36 +00002293
bellard8853f862004-02-22 14:57:26 +00002294#define N_SHM_REGIONS 32
2295
2296static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002297 abi_ulong start;
2298 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002299} shm_regions[N_SHM_REGIONS];
2300
ths3eb6b042007-06-03 14:26:27 +00002301struct target_ipc_perm
2302{
blueswir1992f48a2007-10-14 16:27:31 +00002303 abi_long __key;
2304 abi_ulong uid;
2305 abi_ulong gid;
2306 abi_ulong cuid;
2307 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002308 unsigned short int mode;
2309 unsigned short int __pad1;
2310 unsigned short int __seq;
2311 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002312 abi_ulong __unused1;
2313 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002314};
2315
2316struct target_semid_ds
2317{
2318 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002319 abi_ulong sem_otime;
2320 abi_ulong __unused1;
2321 abi_ulong sem_ctime;
2322 abi_ulong __unused2;
2323 abi_ulong sem_nsems;
2324 abi_ulong __unused3;
2325 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002326};
2327
bellard579a97f2007-11-11 14:26:47 +00002328static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2329 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002330{
2331 struct target_ipc_perm *target_ip;
2332 struct target_semid_ds *target_sd;
2333
bellard579a97f2007-11-11 14:26:47 +00002334 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2335 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002336 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002337 host_ip->__key = tswapal(target_ip->__key);
2338 host_ip->uid = tswapal(target_ip->uid);
2339 host_ip->gid = tswapal(target_ip->gid);
2340 host_ip->cuid = tswapal(target_ip->cuid);
2341 host_ip->cgid = tswapal(target_ip->cgid);
2342 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002343 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002344 return 0;
ths3eb6b042007-06-03 14:26:27 +00002345}
2346
bellard579a97f2007-11-11 14:26:47 +00002347static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2348 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002349{
2350 struct target_ipc_perm *target_ip;
2351 struct target_semid_ds *target_sd;
2352
bellard579a97f2007-11-11 14:26:47 +00002353 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2354 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002355 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002356 target_ip->__key = tswapal(host_ip->__key);
2357 target_ip->uid = tswapal(host_ip->uid);
2358 target_ip->gid = tswapal(host_ip->gid);
2359 target_ip->cuid = tswapal(host_ip->cuid);
2360 target_ip->cgid = tswapal(host_ip->cgid);
2361 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002362 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002363 return 0;
ths3eb6b042007-06-03 14:26:27 +00002364}
2365
bellard579a97f2007-11-11 14:26:47 +00002366static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2367 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002368{
2369 struct target_semid_ds *target_sd;
2370
bellard579a97f2007-11-11 14:26:47 +00002371 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2372 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002373 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2374 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002375 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2376 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2377 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002378 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002379 return 0;
ths3eb6b042007-06-03 14:26:27 +00002380}
2381
bellard579a97f2007-11-11 14:26:47 +00002382static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2383 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002384{
2385 struct target_semid_ds *target_sd;
2386
bellard579a97f2007-11-11 14:26:47 +00002387 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2388 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002389 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2390 return -TARGET_EFAULT;;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002391 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2392 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2393 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002394 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002395 return 0;
ths3eb6b042007-06-03 14:26:27 +00002396}
2397
aurel32e5289082009-04-18 16:16:12 +00002398struct target_seminfo {
2399 int semmap;
2400 int semmni;
2401 int semmns;
2402 int semmnu;
2403 int semmsl;
2404 int semopm;
2405 int semume;
2406 int semusz;
2407 int semvmx;
2408 int semaem;
2409};
2410
2411static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2412 struct seminfo *host_seminfo)
2413{
2414 struct target_seminfo *target_seminfo;
2415 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2416 return -TARGET_EFAULT;
2417 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2418 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2419 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2420 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2421 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2422 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2423 __put_user(host_seminfo->semume, &target_seminfo->semume);
2424 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2425 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2426 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2427 unlock_user_struct(target_seminfo, target_addr, 1);
2428 return 0;
2429}
2430
thsfa294812007-02-02 22:05:00 +00002431union semun {
2432 int val;
ths3eb6b042007-06-03 14:26:27 +00002433 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002434 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002435 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002436};
2437
ths3eb6b042007-06-03 14:26:27 +00002438union target_semun {
2439 int val;
aurel32e5289082009-04-18 16:16:12 +00002440 abi_ulong buf;
2441 abi_ulong array;
2442 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002443};
2444
aurel32e5289082009-04-18 16:16:12 +00002445static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2446 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002447{
aurel32e5289082009-04-18 16:16:12 +00002448 int nsems;
2449 unsigned short *array;
2450 union semun semun;
2451 struct semid_ds semid_ds;
2452 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002453
aurel32e5289082009-04-18 16:16:12 +00002454 semun.buf = &semid_ds;
2455
2456 ret = semctl(semid, 0, IPC_STAT, semun);
2457 if (ret == -1)
2458 return get_errno(ret);
2459
2460 nsems = semid_ds.sem_nsems;
2461
2462 *host_array = malloc(nsems*sizeof(unsigned short));
2463 array = lock_user(VERIFY_READ, target_addr,
2464 nsems*sizeof(unsigned short), 1);
2465 if (!array)
2466 return -TARGET_EFAULT;
2467
2468 for(i=0; i<nsems; i++) {
2469 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002470 }
aurel32e5289082009-04-18 16:16:12 +00002471 unlock_user(array, target_addr, 0);
2472
bellard579a97f2007-11-11 14:26:47 +00002473 return 0;
ths3eb6b042007-06-03 14:26:27 +00002474}
2475
aurel32e5289082009-04-18 16:16:12 +00002476static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2477 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002478{
aurel32e5289082009-04-18 16:16:12 +00002479 int nsems;
2480 unsigned short *array;
2481 union semun semun;
2482 struct semid_ds semid_ds;
2483 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002484
aurel32e5289082009-04-18 16:16:12 +00002485 semun.buf = &semid_ds;
2486
2487 ret = semctl(semid, 0, IPC_STAT, semun);
2488 if (ret == -1)
2489 return get_errno(ret);
2490
2491 nsems = semid_ds.sem_nsems;
2492
2493 array = lock_user(VERIFY_WRITE, target_addr,
2494 nsems*sizeof(unsigned short), 0);
2495 if (!array)
2496 return -TARGET_EFAULT;
2497
2498 for(i=0; i<nsems; i++) {
2499 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002500 }
aurel32e5289082009-04-18 16:16:12 +00002501 free(*host_array);
2502 unlock_user(array, target_addr, 1);
2503
bellard579a97f2007-11-11 14:26:47 +00002504 return 0;
ths3eb6b042007-06-03 14:26:27 +00002505}
2506
aurel32e5289082009-04-18 16:16:12 +00002507static inline abi_long do_semctl(int semid, int semnum, int cmd,
2508 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002509{
2510 union semun arg;
2511 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302512 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002513 struct seminfo seminfo;
2514 abi_long ret = -TARGET_EINVAL;
2515 abi_long err;
2516 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002517
2518 switch( cmd ) {
2519 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002520 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002521 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002522 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002523 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002524 break;
2525 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002526 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002527 err = target_to_host_semarray(semid, &array, target_su.array);
2528 if (err)
2529 return err;
2530 arg.array = array;
2531 ret = get_errno(semctl(semid, semnum, cmd, arg));
2532 err = host_to_target_semarray(semid, target_su.array, &array);
2533 if (err)
2534 return err;
ths3eb6b042007-06-03 14:26:27 +00002535 break;
2536 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002537 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002538 case SEM_STAT:
2539 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2540 if (err)
2541 return err;
2542 arg.buf = &dsarg;
2543 ret = get_errno(semctl(semid, semnum, cmd, arg));
2544 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2545 if (err)
2546 return err;
ths3eb6b042007-06-03 14:26:27 +00002547 break;
aurel32e5289082009-04-18 16:16:12 +00002548 case IPC_INFO:
2549 case SEM_INFO:
2550 arg.__buf = &seminfo;
2551 ret = get_errno(semctl(semid, semnum, cmd, arg));
2552 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2553 if (err)
2554 return err;
2555 break;
2556 case IPC_RMID:
2557 case GETPID:
2558 case GETNCNT:
2559 case GETZCNT:
2560 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2561 break;
ths3eb6b042007-06-03 14:26:27 +00002562 }
2563
2564 return ret;
2565}
2566
aurel32e5289082009-04-18 16:16:12 +00002567struct target_sembuf {
2568 unsigned short sem_num;
2569 short sem_op;
2570 short sem_flg;
2571};
2572
2573static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2574 abi_ulong target_addr,
2575 unsigned nsops)
2576{
2577 struct target_sembuf *target_sembuf;
2578 int i;
2579
2580 target_sembuf = lock_user(VERIFY_READ, target_addr,
2581 nsops*sizeof(struct target_sembuf), 1);
2582 if (!target_sembuf)
2583 return -TARGET_EFAULT;
2584
2585 for(i=0; i<nsops; i++) {
2586 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2587 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2588 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2589 }
2590
2591 unlock_user(target_sembuf, target_addr, 0);
2592
2593 return 0;
2594}
2595
2596static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2597{
2598 struct sembuf sops[nsops];
2599
2600 if (target_to_host_sembuf(sops, ptr, nsops))
2601 return -TARGET_EFAULT;
2602
2603 return semop(semid, sops, nsops);
2604}
2605
ths1bc012f2007-06-03 14:27:49 +00002606struct target_msqid_ds
2607{
aurel321c54ff92008-10-13 21:08:44 +00002608 struct target_ipc_perm msg_perm;
2609 abi_ulong msg_stime;
2610#if TARGET_ABI_BITS == 32
2611 abi_ulong __unused1;
2612#endif
2613 abi_ulong msg_rtime;
2614#if TARGET_ABI_BITS == 32
2615 abi_ulong __unused2;
2616#endif
2617 abi_ulong msg_ctime;
2618#if TARGET_ABI_BITS == 32
2619 abi_ulong __unused3;
2620#endif
2621 abi_ulong __msg_cbytes;
2622 abi_ulong msg_qnum;
2623 abi_ulong msg_qbytes;
2624 abi_ulong msg_lspid;
2625 abi_ulong msg_lrpid;
2626 abi_ulong __unused4;
2627 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002628};
2629
bellard579a97f2007-11-11 14:26:47 +00002630static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2631 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002632{
2633 struct target_msqid_ds *target_md;
2634
bellard579a97f2007-11-11 14:26:47 +00002635 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2636 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002637 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2638 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002639 host_md->msg_stime = tswapal(target_md->msg_stime);
2640 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2641 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2642 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2643 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2644 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2645 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2646 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002647 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002648 return 0;
ths1bc012f2007-06-03 14:27:49 +00002649}
2650
bellard579a97f2007-11-11 14:26:47 +00002651static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2652 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002653{
2654 struct target_msqid_ds *target_md;
2655
bellard579a97f2007-11-11 14:26:47 +00002656 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2657 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002658 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2659 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002660 target_md->msg_stime = tswapal(host_md->msg_stime);
2661 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2662 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2663 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2664 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2665 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2666 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2667 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002668 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002669 return 0;
ths1bc012f2007-06-03 14:27:49 +00002670}
2671
aurel321c54ff92008-10-13 21:08:44 +00002672struct target_msginfo {
2673 int msgpool;
2674 int msgmap;
2675 int msgmax;
2676 int msgmnb;
2677 int msgmni;
2678 int msgssz;
2679 int msgtql;
2680 unsigned short int msgseg;
2681};
2682
2683static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2684 struct msginfo *host_msginfo)
2685{
2686 struct target_msginfo *target_msginfo;
2687 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2688 return -TARGET_EFAULT;
2689 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2690 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2691 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2692 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2693 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2694 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2695 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2696 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2697 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002698 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002699}
2700
2701static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002702{
2703 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002704 struct msginfo msginfo;
2705 abi_long ret = -TARGET_EINVAL;
2706
2707 cmd &= 0xff;
2708
2709 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002710 case IPC_STAT:
2711 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002712 case MSG_STAT:
2713 if (target_to_host_msqid_ds(&dsarg,ptr))
2714 return -TARGET_EFAULT;
2715 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2716 if (host_to_target_msqid_ds(ptr,&dsarg))
2717 return -TARGET_EFAULT;
2718 break;
2719 case IPC_RMID:
2720 ret = get_errno(msgctl(msgid, cmd, NULL));
2721 break;
2722 case IPC_INFO:
2723 case MSG_INFO:
2724 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2725 if (host_to_target_msginfo(ptr, &msginfo))
2726 return -TARGET_EFAULT;
2727 break;
ths1bc012f2007-06-03 14:27:49 +00002728 }
aurel321c54ff92008-10-13 21:08:44 +00002729
ths1bc012f2007-06-03 14:27:49 +00002730 return ret;
2731}
2732
2733struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002734 abi_long mtype;
2735 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002736};
2737
blueswir1992f48a2007-10-14 16:27:31 +00002738static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2739 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002740{
2741 struct target_msgbuf *target_mb;
2742 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002743 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002744
bellard579a97f2007-11-11 14:26:47 +00002745 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2746 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002747 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002748 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002749 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002750 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2751 free(host_mb);
2752 unlock_user_struct(target_mb, msgp, 0);
2753
2754 return ret;
2755}
2756
blueswir1992f48a2007-10-14 16:27:31 +00002757static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002758 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002759 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002760{
2761 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002762 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002763 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002764 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002765
bellard579a97f2007-11-11 14:26:47 +00002766 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2767 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002768
ths1bc012f2007-06-03 14:27:49 +00002769 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002770 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002771
bellard579a97f2007-11-11 14:26:47 +00002772 if (ret > 0) {
2773 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2774 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2775 if (!target_mtext) {
2776 ret = -TARGET_EFAULT;
2777 goto end;
2778 }
aurel321c54ff92008-10-13 21:08:44 +00002779 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002780 unlock_user(target_mtext, target_mtext_addr, ret);
2781 }
aurel321c54ff92008-10-13 21:08:44 +00002782
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002783 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002784 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002785
bellard579a97f2007-11-11 14:26:47 +00002786end:
2787 if (target_mb)
2788 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002789 return ret;
2790}
2791
Riku Voipio88a8c982009-04-03 10:42:00 +03002792struct target_shmid_ds
2793{
2794 struct target_ipc_perm shm_perm;
2795 abi_ulong shm_segsz;
2796 abi_ulong shm_atime;
2797#if TARGET_ABI_BITS == 32
2798 abi_ulong __unused1;
2799#endif
2800 abi_ulong shm_dtime;
2801#if TARGET_ABI_BITS == 32
2802 abi_ulong __unused2;
2803#endif
2804 abi_ulong shm_ctime;
2805#if TARGET_ABI_BITS == 32
2806 abi_ulong __unused3;
2807#endif
2808 int shm_cpid;
2809 int shm_lpid;
2810 abi_ulong shm_nattch;
2811 unsigned long int __unused4;
2812 unsigned long int __unused5;
2813};
2814
2815static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2816 abi_ulong target_addr)
2817{
2818 struct target_shmid_ds *target_sd;
2819
2820 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2821 return -TARGET_EFAULT;
2822 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2823 return -TARGET_EFAULT;
2824 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2825 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2826 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2827 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2828 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2829 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2830 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2831 unlock_user_struct(target_sd, target_addr, 0);
2832 return 0;
2833}
2834
2835static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2836 struct shmid_ds *host_sd)
2837{
2838 struct target_shmid_ds *target_sd;
2839
2840 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2841 return -TARGET_EFAULT;
2842 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2843 return -TARGET_EFAULT;
2844 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2845 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2846 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2847 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2848 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2849 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2850 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2851 unlock_user_struct(target_sd, target_addr, 1);
2852 return 0;
2853}
2854
2855struct target_shminfo {
2856 abi_ulong shmmax;
2857 abi_ulong shmmin;
2858 abi_ulong shmmni;
2859 abi_ulong shmseg;
2860 abi_ulong shmall;
2861};
2862
2863static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2864 struct shminfo *host_shminfo)
2865{
2866 struct target_shminfo *target_shminfo;
2867 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2868 return -TARGET_EFAULT;
2869 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2870 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2871 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2872 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2873 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2874 unlock_user_struct(target_shminfo, target_addr, 1);
2875 return 0;
2876}
2877
2878struct target_shm_info {
2879 int used_ids;
2880 abi_ulong shm_tot;
2881 abi_ulong shm_rss;
2882 abi_ulong shm_swp;
2883 abi_ulong swap_attempts;
2884 abi_ulong swap_successes;
2885};
2886
2887static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2888 struct shm_info *host_shm_info)
2889{
2890 struct target_shm_info *target_shm_info;
2891 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2892 return -TARGET_EFAULT;
2893 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2894 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2895 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2896 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2897 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2898 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2899 unlock_user_struct(target_shm_info, target_addr, 1);
2900 return 0;
2901}
2902
2903static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2904{
2905 struct shmid_ds dsarg;
2906 struct shminfo shminfo;
2907 struct shm_info shm_info;
2908 abi_long ret = -TARGET_EINVAL;
2909
2910 cmd &= 0xff;
2911
2912 switch(cmd) {
2913 case IPC_STAT:
2914 case IPC_SET:
2915 case SHM_STAT:
2916 if (target_to_host_shmid_ds(&dsarg, buf))
2917 return -TARGET_EFAULT;
2918 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2919 if (host_to_target_shmid_ds(buf, &dsarg))
2920 return -TARGET_EFAULT;
2921 break;
2922 case IPC_INFO:
2923 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2924 if (host_to_target_shminfo(buf, &shminfo))
2925 return -TARGET_EFAULT;
2926 break;
2927 case SHM_INFO:
2928 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2929 if (host_to_target_shm_info(buf, &shm_info))
2930 return -TARGET_EFAULT;
2931 break;
2932 case IPC_RMID:
2933 case SHM_LOCK:
2934 case SHM_UNLOCK:
2935 ret = get_errno(shmctl(shmid, cmd, NULL));
2936 break;
2937 }
2938
2939 return ret;
2940}
2941
2942static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2943{
2944 abi_long raddr;
2945 void *host_raddr;
2946 struct shmid_ds shm_info;
2947 int i,ret;
2948
2949 /* find out the length of the shared memory segment */
2950 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2951 if (is_error(ret)) {
2952 /* can't get length, bail out */
2953 return ret;
2954 }
2955
2956 mmap_lock();
2957
2958 if (shmaddr)
2959 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2960 else {
2961 abi_ulong mmap_start;
2962
2963 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2964
2965 if (mmap_start == -1) {
2966 errno = ENOMEM;
2967 host_raddr = (void *)-1;
2968 } else
2969 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2970 }
2971
2972 if (host_raddr == (void *)-1) {
2973 mmap_unlock();
2974 return get_errno((long)host_raddr);
2975 }
2976 raddr=h2g((unsigned long)host_raddr);
2977
2978 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2979 PAGE_VALID | PAGE_READ |
2980 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2981
2982 for (i = 0; i < N_SHM_REGIONS; i++) {
2983 if (shm_regions[i].start == 0) {
2984 shm_regions[i].start = raddr;
2985 shm_regions[i].size = shm_info.shm_segsz;
2986 break;
2987 }
2988 }
2989
2990 mmap_unlock();
2991 return raddr;
2992
2993}
2994
2995static inline abi_long do_shmdt(abi_ulong shmaddr)
2996{
2997 int i;
2998
2999 for (i = 0; i < N_SHM_REGIONS; ++i) {
3000 if (shm_regions[i].start == shmaddr) {
3001 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003002 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003003 break;
3004 }
3005 }
3006
3007 return get_errno(shmdt(g2h(shmaddr)));
3008}
3009
aurel321c54ff92008-10-13 21:08:44 +00003010#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003011/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003012/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003013static abi_long do_ipc(unsigned int call, int first,
3014 int second, int third,
3015 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003016{
3017 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003018 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003019
3020 version = call >> 16;
3021 call &= 0xffff;
3022
3023 switch (call) {
thsfa294812007-02-02 22:05:00 +00003024 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003025 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003026 break;
3027
3028 case IPCOP_semget:
3029 ret = get_errno(semget(first, second, third));
3030 break;
3031
3032 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003033 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003034 break;
thsd96372e2007-02-02 22:05:44 +00003035
aurel321c54ff92008-10-13 21:08:44 +00003036 case IPCOP_msgget:
3037 ret = get_errno(msgget(first, second));
3038 break;
thsd96372e2007-02-02 22:05:44 +00003039
aurel321c54ff92008-10-13 21:08:44 +00003040 case IPCOP_msgsnd:
3041 ret = do_msgsnd(first, ptr, second, third);
3042 break;
thsd96372e2007-02-02 22:05:44 +00003043
aurel321c54ff92008-10-13 21:08:44 +00003044 case IPCOP_msgctl:
3045 ret = do_msgctl(first, second, ptr);
3046 break;
thsd96372e2007-02-02 22:05:44 +00003047
aurel321c54ff92008-10-13 21:08:44 +00003048 case IPCOP_msgrcv:
3049 switch (version) {
3050 case 0:
3051 {
3052 struct target_ipc_kludge {
3053 abi_long msgp;
3054 abi_long msgtyp;
3055 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003056
aurel321c54ff92008-10-13 21:08:44 +00003057 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3058 ret = -TARGET_EFAULT;
3059 break;
ths1bc012f2007-06-03 14:27:49 +00003060 }
aurel321c54ff92008-10-13 21:08:44 +00003061
3062 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3063
3064 unlock_user_struct(tmp, ptr, 0);
3065 break;
3066 }
3067 default:
3068 ret = do_msgrcv(first, ptr, second, fifth, third);
3069 }
3070 break;
thsd96372e2007-02-02 22:05:44 +00003071
bellard8853f862004-02-22 14:57:26 +00003072 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003073 switch (version) {
3074 default:
bellard5a4a8982007-11-11 17:39:18 +00003075 {
3076 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003077 raddr = do_shmat(first, ptr, second);
3078 if (is_error(raddr))
3079 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003080 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003081 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003082 break;
3083 }
3084 case 1:
3085 ret = -TARGET_EINVAL;
3086 break;
bellard5a4a8982007-11-11 17:39:18 +00003087 }
bellard8853f862004-02-22 14:57:26 +00003088 break;
3089 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003090 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003091 break;
3092
3093 case IPCOP_shmget:
3094 /* IPC_* flag values are the same on all linux platforms */
3095 ret = get_errno(shmget(first, second, third));
3096 break;
3097
3098 /* IPC_* and SHM_* command values are the same on all linux platforms */
3099 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003100 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003101 break;
3102 default:
j_mayer32407102007-09-26 23:01:49 +00003103 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003104 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003105 break;
3106 }
3107 return ret;
3108}
j_mayer32407102007-09-26 23:01:49 +00003109#endif
bellard8853f862004-02-22 14:57:26 +00003110
bellard31e31b82003-02-18 22:55:36 +00003111/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003112
Blue Swirl001faf32009-05-13 17:53:17 +00003113#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003114#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3115enum {
3116#include "syscall_types.h"
3117};
3118#undef STRUCT
3119#undef STRUCT_SPECIAL
3120
Blue Swirl001faf32009-05-13 17:53:17 +00003121#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003122#define STRUCT_SPECIAL(name)
3123#include "syscall_types.h"
3124#undef STRUCT
3125#undef STRUCT_SPECIAL
3126
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003127typedef struct IOCTLEntry IOCTLEntry;
3128
3129typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3130 int fd, abi_long cmd, abi_long arg);
3131
3132struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003133 unsigned int target_cmd;
3134 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003135 const char *name;
3136 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003137 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003138 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003139};
bellard31e31b82003-02-18 22:55:36 +00003140
3141#define IOC_R 0x0001
3142#define IOC_W 0x0002
3143#define IOC_RW (IOC_R | IOC_W)
3144
3145#define MAX_STRUCT_SIZE 4096
3146
Peter Maydelldace20d2011-01-10 13:11:24 +00003147#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003148/* So fiemap access checks don't overflow on 32 bit systems.
3149 * This is very slightly smaller than the limit imposed by
3150 * the underlying kernel.
3151 */
3152#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3153 / sizeof(struct fiemap_extent))
3154
3155static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3156 int fd, abi_long cmd, abi_long arg)
3157{
3158 /* The parameter for this ioctl is a struct fiemap followed
3159 * by an array of struct fiemap_extent whose size is set
3160 * in fiemap->fm_extent_count. The array is filled in by the
3161 * ioctl.
3162 */
3163 int target_size_in, target_size_out;
3164 struct fiemap *fm;
3165 const argtype *arg_type = ie->arg_type;
3166 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3167 void *argptr, *p;
3168 abi_long ret;
3169 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3170 uint32_t outbufsz;
3171 int free_fm = 0;
3172
3173 assert(arg_type[0] == TYPE_PTR);
3174 assert(ie->access == IOC_RW);
3175 arg_type++;
3176 target_size_in = thunk_type_size(arg_type, 0);
3177 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3178 if (!argptr) {
3179 return -TARGET_EFAULT;
3180 }
3181 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3182 unlock_user(argptr, arg, 0);
3183 fm = (struct fiemap *)buf_temp;
3184 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3185 return -TARGET_EINVAL;
3186 }
3187
3188 outbufsz = sizeof (*fm) +
3189 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3190
3191 if (outbufsz > MAX_STRUCT_SIZE) {
3192 /* We can't fit all the extents into the fixed size buffer.
3193 * Allocate one that is large enough and use it instead.
3194 */
3195 fm = malloc(outbufsz);
3196 if (!fm) {
3197 return -TARGET_ENOMEM;
3198 }
3199 memcpy(fm, buf_temp, sizeof(struct fiemap));
3200 free_fm = 1;
3201 }
3202 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3203 if (!is_error(ret)) {
3204 target_size_out = target_size_in;
3205 /* An extent_count of 0 means we were only counting the extents
3206 * so there are no structs to copy
3207 */
3208 if (fm->fm_extent_count != 0) {
3209 target_size_out += fm->fm_mapped_extents * extent_size;
3210 }
3211 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3212 if (!argptr) {
3213 ret = -TARGET_EFAULT;
3214 } else {
3215 /* Convert the struct fiemap */
3216 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3217 if (fm->fm_extent_count != 0) {
3218 p = argptr + target_size_in;
3219 /* ...and then all the struct fiemap_extents */
3220 for (i = 0; i < fm->fm_mapped_extents; i++) {
3221 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3222 THUNK_TARGET);
3223 p += extent_size;
3224 }
3225 }
3226 unlock_user(argptr, arg, target_size_out);
3227 }
3228 }
3229 if (free_fm) {
3230 free(fm);
3231 }
3232 return ret;
3233}
Peter Maydelldace20d2011-01-10 13:11:24 +00003234#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003235
Laurent Vivier059c2f22011-03-30 00:12:12 +02003236static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3237 int fd, abi_long cmd, abi_long arg)
3238{
3239 const argtype *arg_type = ie->arg_type;
3240 int target_size;
3241 void *argptr;
3242 int ret;
3243 struct ifconf *host_ifconf;
3244 uint32_t outbufsz;
3245 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3246 int target_ifreq_size;
3247 int nb_ifreq;
3248 int free_buf = 0;
3249 int i;
3250 int target_ifc_len;
3251 abi_long target_ifc_buf;
3252 int host_ifc_len;
3253 char *host_ifc_buf;
3254
3255 assert(arg_type[0] == TYPE_PTR);
3256 assert(ie->access == IOC_RW);
3257
3258 arg_type++;
3259 target_size = thunk_type_size(arg_type, 0);
3260
3261 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3262 if (!argptr)
3263 return -TARGET_EFAULT;
3264 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3265 unlock_user(argptr, arg, 0);
3266
3267 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3268 target_ifc_len = host_ifconf->ifc_len;
3269 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3270
3271 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3272 nb_ifreq = target_ifc_len / target_ifreq_size;
3273 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3274
3275 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3276 if (outbufsz > MAX_STRUCT_SIZE) {
3277 /* We can't fit all the extents into the fixed size buffer.
3278 * Allocate one that is large enough and use it instead.
3279 */
3280 host_ifconf = malloc(outbufsz);
3281 if (!host_ifconf) {
3282 return -TARGET_ENOMEM;
3283 }
3284 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3285 free_buf = 1;
3286 }
3287 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3288
3289 host_ifconf->ifc_len = host_ifc_len;
3290 host_ifconf->ifc_buf = host_ifc_buf;
3291
3292 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3293 if (!is_error(ret)) {
3294 /* convert host ifc_len to target ifc_len */
3295
3296 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3297 target_ifc_len = nb_ifreq * target_ifreq_size;
3298 host_ifconf->ifc_len = target_ifc_len;
3299
3300 /* restore target ifc_buf */
3301
3302 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3303
3304 /* copy struct ifconf to target user */
3305
3306 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3307 if (!argptr)
3308 return -TARGET_EFAULT;
3309 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3310 unlock_user(argptr, arg, target_size);
3311
3312 /* copy ifreq[] to target user */
3313
3314 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3315 for (i = 0; i < nb_ifreq ; i++) {
3316 thunk_convert(argptr + i * target_ifreq_size,
3317 host_ifc_buf + i * sizeof(struct ifreq),
3318 ifreq_arg_type, THUNK_TARGET);
3319 }
3320 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3321 }
3322
3323 if (free_buf) {
3324 free(host_ifconf);
3325 }
3326
3327 return ret;
3328}
3329
blueswir19f106a72008-10-05 10:52:52 +00003330static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003331#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003332 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3333#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3334 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003335#include "ioctls.h"
3336 { 0, 0, },
3337};
3338
pbrook53a59602006-03-25 19:31:22 +00003339/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003340/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003341static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003342{
3343 const IOCTLEntry *ie;
3344 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003345 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003346 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003347 int target_size;
3348 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003349
3350 ie = ioctl_entries;
3351 for(;;) {
3352 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003353 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003354 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003355 }
3356 if (ie->target_cmd == cmd)
3357 break;
3358 ie++;
3359 }
3360 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003361#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003362 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003363#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003364 if (ie->do_ioctl) {
3365 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3366 }
3367
bellard31e31b82003-02-18 22:55:36 +00003368 switch(arg_type[0]) {
3369 case TYPE_NULL:
3370 /* no argument */
3371 ret = get_errno(ioctl(fd, ie->host_cmd));
3372 break;
3373 case TYPE_PTRVOID:
3374 case TYPE_INT:
3375 /* int argment */
3376 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3377 break;
3378 case TYPE_PTR:
3379 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003380 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003381 switch(ie->access) {
3382 case IOC_R:
3383 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3384 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003385 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3386 if (!argptr)
3387 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003388 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3389 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003390 }
3391 break;
3392 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003393 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3394 if (!argptr)
3395 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003396 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3397 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003398 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3399 break;
3400 default:
3401 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003402 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3403 if (!argptr)
3404 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003405 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3406 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003407 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3408 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003409 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3410 if (!argptr)
3411 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003412 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3413 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003414 }
3415 break;
3416 }
3417 break;
3418 default:
j_mayer32407102007-09-26 23:01:49 +00003419 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3420 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003421 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003422 break;
3423 }
3424 return ret;
3425}
3426
blueswir1b39bc502008-10-05 10:51:10 +00003427static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003428 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3429 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3430 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3431 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3432 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3433 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3434 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3435 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3436 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3437 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3438 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3439 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3440 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3441 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3442 { 0, 0, 0, 0 }
3443};
3444
blueswir1b39bc502008-10-05 10:51:10 +00003445static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003446 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3447 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3448 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3449 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3450 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3451 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3452 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3453 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3454 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3455 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3456 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3457 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3458 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3459 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3460 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3461 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3462 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3463 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3464 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3465 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3466 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3467 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3468 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3469 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3470 { 0, 0, 0, 0 }
3471};
3472
blueswir1b39bc502008-10-05 10:51:10 +00003473static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003474 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3475 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3476 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3477 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3478 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3479 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3480 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3481 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3482 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3483 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3484 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3485 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3486 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3487 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3488 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3489 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3490 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3491 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3492 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3493 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3494 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3495 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3496 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3497 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3498 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3499 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3500 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3501 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3502 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3503 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3504 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3505 { 0, 0, 0, 0 }
3506};
3507
blueswir1b39bc502008-10-05 10:51:10 +00003508static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003509 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3510 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3511 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3512 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3513 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3514 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3515 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3516 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3517 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3518 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3519 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3520 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3521 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3522 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3523 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3524 { 0, 0, 0, 0 }
3525};
3526
3527static void target_to_host_termios (void *dst, const void *src)
3528{
3529 struct host_termios *host = dst;
3530 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003531
ths5fafdf22007-09-16 21:08:06 +00003532 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003533 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003534 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003535 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003536 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003537 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003538 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003539 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3540 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003541
Arnaud Patard44607122009-04-21 17:39:08 +03003542 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003543 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3544 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003545 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003546 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003547 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003548 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003549 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003550 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003551 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003552 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3553 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003554 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3555 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3556 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3557 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3558 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003559 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003560}
ths3b46e622007-09-17 08:09:54 +00003561
bellard31e31b82003-02-18 22:55:36 +00003562static void host_to_target_termios (void *dst, const void *src)
3563{
3564 struct target_termios *target = dst;
3565 const struct host_termios *host = src;
3566
ths5fafdf22007-09-16 21:08:06 +00003567 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003568 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003569 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003570 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003571 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003572 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003573 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003574 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3575 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003576
Arnaud Patard44607122009-04-21 17:39:08 +03003577 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003578 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3579 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3580 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3581 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3582 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3583 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3584 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3585 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3586 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3587 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3588 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3589 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3590 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3591 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3592 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3593 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3594 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3595}
3596
blueswir18e853dc2008-10-05 10:49:32 +00003597static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003598 .convert = { host_to_target_termios, target_to_host_termios },
3599 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3600 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3601};
3602
bellard5286db72003-06-05 00:57:30 +00003603static bitmask_transtbl mmap_flags_tbl[] = {
3604 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3605 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3606 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3607 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3608 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3609 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3610 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3611 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3612 { 0, 0, 0, 0 }
3613};
3614
bellard2ab83ea2003-06-15 19:56:46 +00003615#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003616
3617/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003618static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003619
bellard03acab62007-11-11 14:57:14 +00003620static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003621{
3622 int size;
pbrook53a59602006-03-25 19:31:22 +00003623 void *p;
bellard6dbad632003-03-16 18:05:05 +00003624
3625 if (!ldt_table)
3626 return 0;
3627 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3628 if (size > bytecount)
3629 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003630 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3631 if (!p)
bellard03acab62007-11-11 14:57:14 +00003632 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003633 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003634 memcpy(p, ldt_table, size);
3635 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003636 return size;
3637}
3638
3639/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003640static abi_long write_ldt(CPUX86State *env,
3641 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003642{
3643 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003644 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003645 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003646 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003647 uint32_t *lp, entry_1, entry_2;
3648
3649 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003650 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003651 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003652 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003653 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003654 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003655 ldt_info.limit = tswap32(target_ldt_info->limit);
3656 ldt_info.flags = tswap32(target_ldt_info->flags);
3657 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003658
bellard6dbad632003-03-16 18:05:05 +00003659 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003660 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003661 seg_32bit = ldt_info.flags & 1;
3662 contents = (ldt_info.flags >> 1) & 3;
3663 read_exec_only = (ldt_info.flags >> 3) & 1;
3664 limit_in_pages = (ldt_info.flags >> 4) & 1;
3665 seg_not_present = (ldt_info.flags >> 5) & 1;
3666 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003667#ifdef TARGET_ABI32
3668 lm = 0;
3669#else
3670 lm = (ldt_info.flags >> 7) & 1;
3671#endif
bellard6dbad632003-03-16 18:05:05 +00003672 if (contents == 3) {
3673 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003674 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003675 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003676 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003677 }
3678 /* allocate the LDT */
3679 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003680 env->ldt.base = target_mmap(0,
3681 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3682 PROT_READ|PROT_WRITE,
3683 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3684 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003685 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003686 memset(g2h(env->ldt.base), 0,
3687 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003688 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003689 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003690 }
3691
3692 /* NOTE: same code as Linux kernel */
3693 /* Allow LDTs to be cleared by the user. */
3694 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3695 if (oldmode ||
3696 (contents == 0 &&
3697 read_exec_only == 1 &&
3698 seg_32bit == 0 &&
3699 limit_in_pages == 0 &&
3700 seg_not_present == 1 &&
3701 useable == 0 )) {
3702 entry_1 = 0;
3703 entry_2 = 0;
3704 goto install;
3705 }
3706 }
ths3b46e622007-09-17 08:09:54 +00003707
bellard6dbad632003-03-16 18:05:05 +00003708 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3709 (ldt_info.limit & 0x0ffff);
3710 entry_2 = (ldt_info.base_addr & 0xff000000) |
3711 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3712 (ldt_info.limit & 0xf0000) |
3713 ((read_exec_only ^ 1) << 9) |
3714 (contents << 10) |
3715 ((seg_not_present ^ 1) << 15) |
3716 (seg_32bit << 22) |
3717 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003718 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003719 0x7000;
3720 if (!oldmode)
3721 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003722
bellard6dbad632003-03-16 18:05:05 +00003723 /* Install the new entry ... */
3724install:
3725 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3726 lp[0] = tswap32(entry_1);
3727 lp[1] = tswap32(entry_2);
3728 return 0;
3729}
3730
3731/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003732static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3733 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003734{
bellard03acab62007-11-11 14:57:14 +00003735 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003736
bellard6dbad632003-03-16 18:05:05 +00003737 switch (func) {
3738 case 0:
3739 ret = read_ldt(ptr, bytecount);
3740 break;
3741 case 1:
3742 ret = write_ldt(env, ptr, bytecount, 1);
3743 break;
3744 case 0x11:
3745 ret = write_ldt(env, ptr, bytecount, 0);
3746 break;
bellard03acab62007-11-11 14:57:14 +00003747 default:
3748 ret = -TARGET_ENOSYS;
3749 break;
bellard6dbad632003-03-16 18:05:05 +00003750 }
3751 return ret;
3752}
bellard1b6b0292003-03-22 17:31:38 +00003753
blueswir14583f582008-08-24 10:35:55 +00003754#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003755static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003756{
3757 uint64_t *gdt_table = g2h(env->gdt.base);
3758 struct target_modify_ldt_ldt_s ldt_info;
3759 struct target_modify_ldt_ldt_s *target_ldt_info;
3760 int seg_32bit, contents, read_exec_only, limit_in_pages;
3761 int seg_not_present, useable, lm;
3762 uint32_t *lp, entry_1, entry_2;
3763 int i;
3764
3765 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3766 if (!target_ldt_info)
3767 return -TARGET_EFAULT;
3768 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003769 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00003770 ldt_info.limit = tswap32(target_ldt_info->limit);
3771 ldt_info.flags = tswap32(target_ldt_info->flags);
3772 if (ldt_info.entry_number == -1) {
3773 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3774 if (gdt_table[i] == 0) {
3775 ldt_info.entry_number = i;
3776 target_ldt_info->entry_number = tswap32(i);
3777 break;
3778 }
3779 }
3780 }
3781 unlock_user_struct(target_ldt_info, ptr, 1);
3782
3783 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
3784 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
3785 return -TARGET_EINVAL;
3786 seg_32bit = ldt_info.flags & 1;
3787 contents = (ldt_info.flags >> 1) & 3;
3788 read_exec_only = (ldt_info.flags >> 3) & 1;
3789 limit_in_pages = (ldt_info.flags >> 4) & 1;
3790 seg_not_present = (ldt_info.flags >> 5) & 1;
3791 useable = (ldt_info.flags >> 6) & 1;
3792#ifdef TARGET_ABI32
3793 lm = 0;
3794#else
3795 lm = (ldt_info.flags >> 7) & 1;
3796#endif
3797
3798 if (contents == 3) {
3799 if (seg_not_present == 0)
3800 return -TARGET_EINVAL;
3801 }
3802
3803 /* NOTE: same code as Linux kernel */
3804 /* Allow LDTs to be cleared by the user. */
3805 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3806 if ((contents == 0 &&
3807 read_exec_only == 1 &&
3808 seg_32bit == 0 &&
3809 limit_in_pages == 0 &&
3810 seg_not_present == 1 &&
3811 useable == 0 )) {
3812 entry_1 = 0;
3813 entry_2 = 0;
3814 goto install;
3815 }
3816 }
3817
3818 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3819 (ldt_info.limit & 0x0ffff);
3820 entry_2 = (ldt_info.base_addr & 0xff000000) |
3821 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3822 (ldt_info.limit & 0xf0000) |
3823 ((read_exec_only ^ 1) << 9) |
3824 (contents << 10) |
3825 ((seg_not_present ^ 1) << 15) |
3826 (seg_32bit << 22) |
3827 (limit_in_pages << 23) |
3828 (useable << 20) |
3829 (lm << 21) |
3830 0x7000;
3831
3832 /* Install the new entry ... */
3833install:
3834 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
3835 lp[0] = tswap32(entry_1);
3836 lp[1] = tswap32(entry_2);
3837 return 0;
3838}
3839
blueswir18fcd3692008-08-17 20:26:25 +00003840static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003841{
3842 struct target_modify_ldt_ldt_s *target_ldt_info;
3843 uint64_t *gdt_table = g2h(env->gdt.base);
3844 uint32_t base_addr, limit, flags;
3845 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
3846 int seg_not_present, useable, lm;
3847 uint32_t *lp, entry_1, entry_2;
3848
3849 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3850 if (!target_ldt_info)
3851 return -TARGET_EFAULT;
3852 idx = tswap32(target_ldt_info->entry_number);
3853 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
3854 idx > TARGET_GDT_ENTRY_TLS_MAX) {
3855 unlock_user_struct(target_ldt_info, ptr, 1);
3856 return -TARGET_EINVAL;
3857 }
3858 lp = (uint32_t *)(gdt_table + idx);
3859 entry_1 = tswap32(lp[0]);
3860 entry_2 = tswap32(lp[1]);
3861
3862 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
3863 contents = (entry_2 >> 10) & 3;
3864 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
3865 seg_32bit = (entry_2 >> 22) & 1;
3866 limit_in_pages = (entry_2 >> 23) & 1;
3867 useable = (entry_2 >> 20) & 1;
3868#ifdef TARGET_ABI32
3869 lm = 0;
3870#else
3871 lm = (entry_2 >> 21) & 1;
3872#endif
3873 flags = (seg_32bit << 0) | (contents << 1) |
3874 (read_exec_only << 3) | (limit_in_pages << 4) |
3875 (seg_not_present << 5) | (useable << 6) | (lm << 7);
3876 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
3877 base_addr = (entry_1 >> 16) |
3878 (entry_2 & 0xff000000) |
3879 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003880 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00003881 target_ldt_info->limit = tswap32(limit);
3882 target_ldt_info->flags = tswap32(flags);
3883 unlock_user_struct(target_ldt_info, ptr, 1);
3884 return 0;
3885}
blueswir14583f582008-08-24 10:35:55 +00003886#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00003887
bellardd2fd1af2007-11-14 18:08:56 +00003888#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00003889static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00003890{
Juan Quintela1add8692011-06-16 17:37:09 +01003891 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00003892 abi_ulong val;
3893 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01003894
bellardd2fd1af2007-11-14 18:08:56 +00003895 switch(code) {
3896 case TARGET_ARCH_SET_GS:
3897 case TARGET_ARCH_SET_FS:
3898 if (code == TARGET_ARCH_SET_GS)
3899 idx = R_GS;
3900 else
3901 idx = R_FS;
3902 cpu_x86_load_seg(env, idx, 0);
3903 env->segs[idx].base = addr;
3904 break;
3905 case TARGET_ARCH_GET_GS:
3906 case TARGET_ARCH_GET_FS:
3907 if (code == TARGET_ARCH_GET_GS)
3908 idx = R_GS;
3909 else
3910 idx = R_FS;
3911 val = env->segs[idx].base;
3912 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01003913 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00003914 break;
3915 default:
3916 ret = -TARGET_EINVAL;
3917 break;
3918 }
Juan Quintela1add8692011-06-16 17:37:09 +01003919 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00003920}
3921#endif
3922
bellard2ab83ea2003-06-15 19:56:46 +00003923#endif /* defined(TARGET_I386) */
3924
Riku Voipio05098a92011-03-04 15:27:29 +02003925#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00003926
Riku Voipio05098a92011-03-04 15:27:29 +02003927#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003928
3929static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
3930typedef struct {
3931 CPUState *env;
3932 pthread_mutex_t mutex;
3933 pthread_cond_t cond;
3934 pthread_t thread;
3935 uint32_t tid;
3936 abi_ulong child_tidptr;
3937 abi_ulong parent_tidptr;
3938 sigset_t sigmask;
3939} new_thread_info;
3940
3941static void *clone_func(void *arg)
3942{
3943 new_thread_info *info = arg;
3944 CPUState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003945 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00003946
3947 env = info->env;
3948 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003949 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00003950 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07003951 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003952 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00003953 if (info->child_tidptr)
3954 put_user_u32(info->tid, info->child_tidptr);
3955 if (info->parent_tidptr)
3956 put_user_u32(info->tid, info->parent_tidptr);
3957 /* Enable signals. */
3958 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
3959 /* Signal to the parent that we're ready. */
3960 pthread_mutex_lock(&info->mutex);
3961 pthread_cond_broadcast(&info->cond);
3962 pthread_mutex_unlock(&info->mutex);
3963 /* Wait until the parent has finshed initializing the tls state. */
3964 pthread_mutex_lock(&clone_lock);
3965 pthread_mutex_unlock(&clone_lock);
3966 cpu_loop(env);
3967 /* never exits */
3968 return NULL;
3969}
3970#else
bellard1b6b0292003-03-22 17:31:38 +00003971
3972static int clone_func(void *arg)
3973{
bellard2ab83ea2003-06-15 19:56:46 +00003974 CPUState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00003975 cpu_loop(env);
3976 /* never exits */
3977 return 0;
3978}
pbrookd865bab2008-06-07 22:12:17 +00003979#endif
bellard1b6b0292003-03-22 17:31:38 +00003980
ths0da46a62007-10-20 20:23:07 +00003981/* do_fork() Must return host values and target errnos (unlike most
3982 do_*() functions). */
pbrookd865bab2008-06-07 22:12:17 +00003983static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3984 abi_ulong parent_tidptr, target_ulong newtls,
3985 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00003986{
3987 int ret;
bellard5cd43932003-03-29 16:54:36 +00003988 TaskState *ts;
bellard2ab83ea2003-06-15 19:56:46 +00003989 CPUState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003990#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003991 unsigned int nptl_flags;
3992 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02003993#else
3994 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00003995#endif
ths3b46e622007-09-17 08:09:54 +00003996
balrog436d1242008-09-21 02:39:45 +00003997 /* Emulate vfork() with fork() */
3998 if (flags & CLONE_VFORK)
3999 flags &= ~(CLONE_VFORK | CLONE_VM);
4000
bellard1b6b0292003-03-22 17:31:38 +00004001 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004002 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004003#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004004 new_thread_info info;
4005 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004006#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004007 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004008 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004009 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004010 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004011#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
4012 cpu_reset(new_env);
4013#endif
pbrook6e68e072008-05-30 17:22:15 +00004014 /* Init regs that differ from the parent. */
4015 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004016 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004017 ts->bprm = parent_ts->bprm;
4018 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004019#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004020 nptl_flags = flags;
4021 flags &= ~CLONE_NPTL_FLAGS2;
4022
pbrookc2764712009-03-07 15:24:59 +00004023 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4024 ts->child_tidptr = child_tidptr;
4025 }
4026
pbrookd865bab2008-06-07 22:12:17 +00004027 if (nptl_flags & CLONE_SETTLS)
4028 cpu_set_tls (new_env, newtls);
4029
4030 /* Grab a mutex so that thread setup appears atomic. */
4031 pthread_mutex_lock(&clone_lock);
4032
4033 memset(&info, 0, sizeof(info));
4034 pthread_mutex_init(&info.mutex, NULL);
4035 pthread_mutex_lock(&info.mutex);
4036 pthread_cond_init(&info.cond, NULL);
4037 info.env = new_env;
4038 if (nptl_flags & CLONE_CHILD_SETTID)
4039 info.child_tidptr = child_tidptr;
4040 if (nptl_flags & CLONE_PARENT_SETTID)
4041 info.parent_tidptr = parent_tidptr;
4042
4043 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004044 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4045 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004046 /* It is not safe to deliver signals until the child has finished
4047 initializing, so temporarily block all signals. */
4048 sigfillset(&sigmask);
4049 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4050
4051 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004052 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004053
4054 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4055 pthread_attr_destroy(&attr);
4056 if (ret == 0) {
4057 /* Wait for the child to initialize. */
4058 pthread_cond_wait(&info.cond, &info.mutex);
4059 ret = info.tid;
4060 if (flags & CLONE_PARENT_SETTID)
4061 put_user_u32(ret, parent_tidptr);
4062 } else {
4063 ret = -1;
4064 }
4065 pthread_mutex_unlock(&info.mutex);
4066 pthread_cond_destroy(&info.cond);
4067 pthread_mutex_destroy(&info.mutex);
4068 pthread_mutex_unlock(&clone_lock);
4069#else
4070 if (flags & CLONE_NPTL_FLAGS2)
4071 return -EINVAL;
4072 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004073 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004074#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004075 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004076#else
4077 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4078#endif
pbrookd865bab2008-06-07 22:12:17 +00004079#endif
bellard1b6b0292003-03-22 17:31:38 +00004080 } else {
4081 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004082 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004083 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004084 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004085 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004086 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004087 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004088 cpu_clone_regs(env, newsp);
4089 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004090#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004091 /* There is a race condition here. The parent process could
4092 theoretically read the TID in the child process before the child
4093 tid is set. This would require using either ptrace
4094 (not implemented) or having *_tidptr to point at a shared memory
4095 mapping. We can't repeat the spinlock hack used above because
4096 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004097 if (flags & CLONE_CHILD_SETTID)
4098 put_user_u32(gettid(), child_tidptr);
4099 if (flags & CLONE_PARENT_SETTID)
4100 put_user_u32(gettid(), parent_tidptr);
4101 ts = (TaskState *)env->opaque;
4102 if (flags & CLONE_SETTLS)
4103 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004104 if (flags & CLONE_CHILD_CLEARTID)
4105 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004106#endif
pbrookd865bab2008-06-07 22:12:17 +00004107 } else {
4108 fork_end(0);
4109 }
bellard1b6b0292003-03-22 17:31:38 +00004110 }
4111 return ret;
4112}
4113
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004114/* warning : doesn't handle linux specific flags... */
4115static int target_to_host_fcntl_cmd(int cmd)
4116{
4117 switch(cmd) {
4118 case TARGET_F_DUPFD:
4119 case TARGET_F_GETFD:
4120 case TARGET_F_SETFD:
4121 case TARGET_F_GETFL:
4122 case TARGET_F_SETFL:
4123 return cmd;
4124 case TARGET_F_GETLK:
4125 return F_GETLK;
4126 case TARGET_F_SETLK:
4127 return F_SETLK;
4128 case TARGET_F_SETLKW:
4129 return F_SETLKW;
4130 case TARGET_F_GETOWN:
4131 return F_GETOWN;
4132 case TARGET_F_SETOWN:
4133 return F_SETOWN;
4134 case TARGET_F_GETSIG:
4135 return F_GETSIG;
4136 case TARGET_F_SETSIG:
4137 return F_SETSIG;
4138#if TARGET_ABI_BITS == 32
4139 case TARGET_F_GETLK64:
4140 return F_GETLK64;
4141 case TARGET_F_SETLK64:
4142 return F_SETLK64;
4143 case TARGET_F_SETLKW64:
4144 return F_SETLKW64;
4145#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004146 case TARGET_F_SETLEASE:
4147 return F_SETLEASE;
4148 case TARGET_F_GETLEASE:
4149 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004150#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004151 case TARGET_F_DUPFD_CLOEXEC:
4152 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004153#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004154 case TARGET_F_NOTIFY:
4155 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004156 default:
4157 return -TARGET_EINVAL;
4158 }
4159 return -TARGET_EINVAL;
4160}
4161
blueswir1992f48a2007-10-14 16:27:31 +00004162static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004163{
4164 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004165 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004166 struct flock64 fl64;
4167 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004168 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004169 int host_cmd = target_to_host_fcntl_cmd(cmd);
4170
4171 if (host_cmd == -TARGET_EINVAL)
4172 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004173
bellard7775e9e2003-05-14 22:46:48 +00004174 switch(cmd) {
4175 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004176 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4177 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004178 fl.l_type = tswap16(target_fl->l_type);
4179 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004180 fl.l_start = tswapal(target_fl->l_start);
4181 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004182 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004183 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004184 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004185 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004186 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4187 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004188 target_fl->l_type = tswap16(fl.l_type);
4189 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004190 target_fl->l_start = tswapal(fl.l_start);
4191 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004192 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004193 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004194 }
4195 break;
ths3b46e622007-09-17 08:09:54 +00004196
bellard7775e9e2003-05-14 22:46:48 +00004197 case TARGET_F_SETLK:
4198 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004199 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4200 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004201 fl.l_type = tswap16(target_fl->l_type);
4202 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004203 fl.l_start = tswapal(target_fl->l_start);
4204 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004205 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004206 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004207 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004208 break;
ths3b46e622007-09-17 08:09:54 +00004209
bellard7775e9e2003-05-14 22:46:48 +00004210 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004211 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4212 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004213 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4214 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004215 fl64.l_start = tswap64(target_fl64->l_start);
4216 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004217 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004218 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004219 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004220 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004221 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4222 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004223 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4224 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004225 target_fl64->l_start = tswap64(fl64.l_start);
4226 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004227 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004228 unlock_user_struct(target_fl64, arg, 1);
4229 }
bellard9ee1fa22007-11-11 15:11:19 +00004230 break;
bellard7775e9e2003-05-14 22:46:48 +00004231 case TARGET_F_SETLK64:
4232 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004233 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4234 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004235 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4236 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004237 fl64.l_start = tswap64(target_fl64->l_start);
4238 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004239 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004240 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004241 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004242 break;
4243
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004244 case TARGET_F_GETFL:
4245 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004246 if (ret >= 0) {
4247 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4248 }
bellardffa65c32004-01-04 23:57:22 +00004249 break;
4250
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004251 case TARGET_F_SETFL:
4252 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4253 break;
4254
4255 case TARGET_F_SETOWN:
4256 case TARGET_F_GETOWN:
4257 case TARGET_F_SETSIG:
4258 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004259 case TARGET_F_SETLEASE:
4260 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004261 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004262 break;
4263
bellard7775e9e2003-05-14 22:46:48 +00004264 default:
bellard9ee1fa22007-11-11 15:11:19 +00004265 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004266 break;
4267 }
4268 return ret;
4269}
4270
bellard67867302003-11-23 17:05:30 +00004271#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004272
bellard67867302003-11-23 17:05:30 +00004273static inline int high2lowuid(int uid)
4274{
4275 if (uid > 65535)
4276 return 65534;
4277 else
4278 return uid;
4279}
4280
4281static inline int high2lowgid(int gid)
4282{
4283 if (gid > 65535)
4284 return 65534;
4285 else
4286 return gid;
4287}
4288
4289static inline int low2highuid(int uid)
4290{
4291 if ((int16_t)uid == -1)
4292 return -1;
4293 else
4294 return uid;
4295}
4296
4297static inline int low2highgid(int gid)
4298{
4299 if ((int16_t)gid == -1)
4300 return -1;
4301 else
4302 return gid;
4303}
Riku Voipio0c866a72011-04-18 15:23:06 +03004304static inline int tswapid(int id)
4305{
4306 return tswap16(id);
4307}
4308#else /* !USE_UID16 */
4309static inline int high2lowuid(int uid)
4310{
4311 return uid;
4312}
4313static inline int high2lowgid(int gid)
4314{
4315 return gid;
4316}
4317static inline int low2highuid(int uid)
4318{
4319 return uid;
4320}
4321static inline int low2highgid(int gid)
4322{
4323 return gid;
4324}
4325static inline int tswapid(int id)
4326{
4327 return tswap32(id);
4328}
bellard67867302003-11-23 17:05:30 +00004329#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004330
bellard31e31b82003-02-18 22:55:36 +00004331void syscall_init(void)
4332{
bellard2ab83ea2003-06-15 19:56:46 +00004333 IOCTLEntry *ie;
4334 const argtype *arg_type;
4335 int size;
thsb92c47c2007-11-01 00:07:38 +00004336 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004337
Blue Swirl001faf32009-05-13 17:53:17 +00004338#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004339#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004340#include "syscall_types.h"
4341#undef STRUCT
4342#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004343
4344 /* we patch the ioctl size if necessary. We rely on the fact that
4345 no ioctl has all the bits at '1' in the size field */
4346 ie = ioctl_entries;
4347 while (ie->target_cmd != 0) {
4348 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4349 TARGET_IOC_SIZEMASK) {
4350 arg_type = ie->arg_type;
4351 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004352 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004353 ie->target_cmd);
4354 exit(1);
4355 }
4356 arg_type++;
4357 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004358 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004359 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4360 (size << TARGET_IOC_SIZESHIFT);
4361 }
thsb92c47c2007-11-01 00:07:38 +00004362
4363 /* Build target_to_host_errno_table[] table from
4364 * host_to_target_errno_table[]. */
4365 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4366 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4367
bellard2ab83ea2003-06-15 19:56:46 +00004368 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004369#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4370 (defined(__x86_64__) && defined(TARGET_X86_64))
4371 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4372 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4373 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004374 }
4375#endif
4376 ie++;
4377 }
bellard31e31b82003-02-18 22:55:36 +00004378}
bellardc573ff62004-01-04 15:51:36 +00004379
blueswir1992f48a2007-10-14 16:27:31 +00004380#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004381static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4382{
thsaf325d32008-06-10 15:29:15 +00004383#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004384 return ((uint64_t)word0 << 32) | word1;
4385#else
4386 return ((uint64_t)word1 << 32) | word0;
4387#endif
4388}
blueswir1992f48a2007-10-14 16:27:31 +00004389#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004390static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4391{
4392 return word0;
4393}
blueswir1992f48a2007-10-14 16:27:31 +00004394#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004395
4396#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004397static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4398 abi_long arg2,
4399 abi_long arg3,
4400 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004401{
Riku Voipio48e515d2011-07-12 15:40:51 +03004402 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004403 arg2 = arg3;
4404 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004405 }
pbrookce4defa2006-02-09 16:49:55 +00004406 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4407}
4408#endif
4409
4410#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004411static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4412 abi_long arg2,
4413 abi_long arg3,
4414 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004415{
Riku Voipio48e515d2011-07-12 15:40:51 +03004416 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004417 arg2 = arg3;
4418 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004419 }
pbrookce4defa2006-02-09 16:49:55 +00004420 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4421}
4422#endif
4423
bellard579a97f2007-11-11 14:26:47 +00004424static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4425 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004426{
4427 struct target_timespec *target_ts;
4428
bellard579a97f2007-11-11 14:26:47 +00004429 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4430 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004431 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4432 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004433 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004434 return 0;
pbrook53a59602006-03-25 19:31:22 +00004435}
4436
bellard579a97f2007-11-11 14:26:47 +00004437static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4438 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004439{
4440 struct target_timespec *target_ts;
4441
bellard579a97f2007-11-11 14:26:47 +00004442 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4443 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004444 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4445 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004446 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004447 return 0;
pbrook53a59602006-03-25 19:31:22 +00004448}
4449
aurel329d33b762009-04-08 23:07:05 +00004450#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004451static inline abi_long host_to_target_stat64(void *cpu_env,
4452 abi_ulong target_addr,
4453 struct stat *host_st)
4454{
4455#ifdef TARGET_ARM
4456 if (((CPUARMState *)cpu_env)->eabi) {
4457 struct target_eabi_stat64 *target_st;
4458
4459 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4460 return -TARGET_EFAULT;
4461 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4462 __put_user(host_st->st_dev, &target_st->st_dev);
4463 __put_user(host_st->st_ino, &target_st->st_ino);
4464#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4465 __put_user(host_st->st_ino, &target_st->__st_ino);
4466#endif
4467 __put_user(host_st->st_mode, &target_st->st_mode);
4468 __put_user(host_st->st_nlink, &target_st->st_nlink);
4469 __put_user(host_st->st_uid, &target_st->st_uid);
4470 __put_user(host_st->st_gid, &target_st->st_gid);
4471 __put_user(host_st->st_rdev, &target_st->st_rdev);
4472 __put_user(host_st->st_size, &target_st->st_size);
4473 __put_user(host_st->st_blksize, &target_st->st_blksize);
4474 __put_user(host_st->st_blocks, &target_st->st_blocks);
4475 __put_user(host_st->st_atime, &target_st->target_st_atime);
4476 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4477 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4478 unlock_user_struct(target_st, target_addr, 1);
4479 } else
4480#endif
4481 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004482#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004483 struct target_stat *target_st;
4484#else
balrog6a24a772008-09-20 02:23:36 +00004485 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004486#endif
balrog6a24a772008-09-20 02:23:36 +00004487
4488 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4489 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004490 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004491 __put_user(host_st->st_dev, &target_st->st_dev);
4492 __put_user(host_st->st_ino, &target_st->st_ino);
4493#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4494 __put_user(host_st->st_ino, &target_st->__st_ino);
4495#endif
4496 __put_user(host_st->st_mode, &target_st->st_mode);
4497 __put_user(host_st->st_nlink, &target_st->st_nlink);
4498 __put_user(host_st->st_uid, &target_st->st_uid);
4499 __put_user(host_st->st_gid, &target_st->st_gid);
4500 __put_user(host_st->st_rdev, &target_st->st_rdev);
4501 /* XXX: better use of kernel struct */
4502 __put_user(host_st->st_size, &target_st->st_size);
4503 __put_user(host_st->st_blksize, &target_st->st_blksize);
4504 __put_user(host_st->st_blocks, &target_st->st_blocks);
4505 __put_user(host_st->st_atime, &target_st->target_st_atime);
4506 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4507 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4508 unlock_user_struct(target_st, target_addr, 1);
4509 }
4510
4511 return 0;
4512}
4513#endif
4514
Juan Quintela2f7bb872009-07-27 16:13:24 +02004515#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004516/* ??? Using host futex calls even when target atomic operations
4517 are not really atomic probably breaks things. However implementing
4518 futexes locally would make futexes shared between multiple processes
4519 tricky. However they're probably useless because guest atomic
4520 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004521static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4522 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004523{
4524 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004525 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004526
4527 /* ??? We assume FUTEX_* constants are the same on both host
4528 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004529#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004530 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004531#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004532 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004533#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004534 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004535 case FUTEX_WAIT:
4536 if (timeout) {
4537 pts = &ts;
4538 target_to_host_timespec(pts, timeout);
4539 } else {
4540 pts = NULL;
4541 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004542 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004543 pts, NULL, 0));
4544 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004545 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004546 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004547 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004548 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004549 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004550 case FUTEX_WAKE_OP:
4551 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4552 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4553 But the prototype takes a `struct timespec *'; insert casts
4554 to satisfy the compiler. We do not need to tswap TIMEOUT
4555 since it's not compared to guest memory. */
4556 pts = (struct timespec *)(uintptr_t) timeout;
4557 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4558 g2h(uaddr2),
4559 (base_op == FUTEX_CMP_REQUEUE
4560 ? tswap32(val3)
4561 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004562 default:
4563 return -TARGET_ENOSYS;
4564 }
4565}
4566#endif
4567
pbrook1d9d8b52009-04-16 15:17:02 +00004568/* Map host to target signal numbers for the wait family of syscalls.
4569 Assume all other status bits are the same. */
4570static int host_to_target_waitstatus(int status)
4571{
4572 if (WIFSIGNALED(status)) {
4573 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4574 }
4575 if (WIFSTOPPED(status)) {
4576 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4577 | (status & 0xff);
4578 }
4579 return status;
4580}
4581
pbrooka745ec62008-05-06 15:36:17 +00004582int get_osversion(void)
4583{
4584 static int osversion;
4585 struct new_utsname buf;
4586 const char *s;
4587 int i, n, tmp;
4588 if (osversion)
4589 return osversion;
4590 if (qemu_uname_release && *qemu_uname_release) {
4591 s = qemu_uname_release;
4592 } else {
4593 if (sys_uname(&buf))
4594 return 0;
4595 s = buf.release;
4596 }
4597 tmp = 0;
4598 for (i = 0; i < 3; i++) {
4599 n = 0;
4600 while (*s >= '0' && *s <= '9') {
4601 n *= 10;
4602 n += *s - '0';
4603 s++;
4604 }
4605 tmp = (tmp << 8) + n;
4606 if (*s == '.')
4607 s++;
4608 }
4609 osversion = tmp;
4610 return osversion;
4611}
4612
ths0da46a62007-10-20 20:23:07 +00004613/* do_syscall() should always have a single exit point at the end so
4614 that actions, such as logging of syscall results, can be performed.
4615 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004616abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4617 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004618 abi_long arg5, abi_long arg6, abi_long arg7,
4619 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00004620{
blueswir1992f48a2007-10-14 16:27:31 +00004621 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004622 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004623 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004624 void *p;
ths3b46e622007-09-17 08:09:54 +00004625
bellard72f03902003-02-18 23:33:18 +00004626#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00004627 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00004628#endif
thsb92c47c2007-11-01 00:07:38 +00004629 if(do_strace)
4630 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
4631
bellard31e31b82003-02-18 22:55:36 +00004632 switch(num) {
4633 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02004634#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00004635 /* In old applications this may be used to implement _exit(2).
4636 However in threaded applictions it is used for thread termination,
4637 and _exit_group is used for application termination.
4638 Do thread termination if we have more then one thread. */
4639 /* FIXME: This probably breaks if a signal arrives. We should probably
4640 be disabling signals. */
4641 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004642 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00004643 CPUState **lastp;
4644 CPUState *p;
4645
4646 cpu_list_lock();
4647 lastp = &first_cpu;
4648 p = first_cpu;
4649 while (p && p != (CPUState *)cpu_env) {
4650 lastp = &p->next_cpu;
4651 p = p->next_cpu;
4652 }
4653 /* If we didn't find the CPU for this thread then something is
4654 horribly wrong. */
4655 if (!p)
4656 abort();
4657 /* Remove the CPU from the list. */
4658 *lastp = p->next_cpu;
4659 cpu_list_unlock();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004660 ts = ((CPUState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00004661 if (ts->child_tidptr) {
4662 put_user_u32(0, ts->child_tidptr);
4663 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
4664 NULL, NULL, 0);
4665 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004666 thread_env = NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05004667 g_free(cpu_env);
4668 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00004669 pthread_exit(NULL);
4670 }
4671#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02004672#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00004673 _mcleanup();
4674#endif
bellarde9009672005-04-26 20:42:36 +00004675 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00004676 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00004677 ret = 0; /* avoid warning */
4678 break;
4679 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00004680 if (arg3 == 0)
4681 ret = 0;
4682 else {
4683 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
4684 goto efault;
4685 ret = get_errno(read(arg1, p, arg3));
4686 unlock_user(p, arg2, ret);
4687 }
bellard31e31b82003-02-18 22:55:36 +00004688 break;
4689 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00004690 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
4691 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004692 ret = get_errno(write(arg1, p, arg3));
4693 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00004694 break;
4695 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00004696 if (!(p = lock_user_string(arg1)))
4697 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004698 ret = get_errno(open(path(p),
bellardffa65c32004-01-04 23:57:22 +00004699 target_to_host_bitmask(arg2, fcntl_flags_tbl),
4700 arg3));
pbrook53a59602006-03-25 19:31:22 +00004701 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004702 break;
ths82424832007-09-24 09:21:55 +00004703#if defined(TARGET_NR_openat) && defined(__NR_openat)
4704 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00004705 if (!(p = lock_user_string(arg2)))
4706 goto efault;
4707 ret = get_errno(sys_openat(arg1,
4708 path(p),
4709 target_to_host_bitmask(arg3, fcntl_flags_tbl),
4710 arg4));
4711 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00004712 break;
4713#endif
bellard31e31b82003-02-18 22:55:36 +00004714 case TARGET_NR_close:
4715 ret = get_errno(close(arg1));
4716 break;
4717 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00004718 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00004719 break;
4720 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00004721 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00004722 break;
thse5febef2007-04-01 18:31:35 +00004723#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00004724 case TARGET_NR_waitpid:
4725 {
pbrook53a59602006-03-25 19:31:22 +00004726 int status;
4727 ret = get_errno(waitpid(arg1, &status, arg3));
bellard2f619692007-11-16 10:46:05 +00004728 if (!is_error(ret) && arg2
pbrook1d9d8b52009-04-16 15:17:02 +00004729 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00004730 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004731 }
4732 break;
thse5febef2007-04-01 18:31:35 +00004733#endif
pbrookf0cbb612008-05-30 18:20:05 +00004734#ifdef TARGET_NR_waitid
4735 case TARGET_NR_waitid:
4736 {
4737 siginfo_t info;
4738 info.si_pid = 0;
4739 ret = get_errno(waitid(arg1, arg2, &info, arg4));
4740 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004741 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00004742 goto efault;
4743 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05004744 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00004745 }
4746 }
4747 break;
4748#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004749#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004750 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00004751 if (!(p = lock_user_string(arg1)))
4752 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004753 ret = get_errno(creat(p, arg2));
4754 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004755 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004756#endif
bellard31e31b82003-02-18 22:55:36 +00004757 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00004758 {
4759 void * p2;
4760 p = lock_user_string(arg1);
4761 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004762 if (!p || !p2)
4763 ret = -TARGET_EFAULT;
4764 else
4765 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004766 unlock_user(p2, arg2, 0);
4767 unlock_user(p, arg1, 0);
4768 }
bellard31e31b82003-02-18 22:55:36 +00004769 break;
ths64f0ce42007-09-24 09:25:06 +00004770#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
4771 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00004772 {
4773 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00004774 if (!arg2 || !arg4)
4775 goto efault;
ths64f0ce42007-09-24 09:25:06 +00004776 p = lock_user_string(arg2);
4777 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004778 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004779 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00004780 else
4781 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00004782 unlock_user(p, arg2, 0);
4783 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00004784 }
4785 break;
4786#endif
bellard31e31b82003-02-18 22:55:36 +00004787 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00004788 if (!(p = lock_user_string(arg1)))
4789 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004790 ret = get_errno(unlink(p));
4791 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004792 break;
ths8170f562007-09-24 09:24:11 +00004793#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
4794 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00004795 if (!(p = lock_user_string(arg2)))
4796 goto efault;
4797 ret = get_errno(sys_unlinkat(arg1, p, arg3));
4798 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00004799 break;
balrogb7d35e62007-12-12 00:40:24 +00004800#endif
bellard31e31b82003-02-18 22:55:36 +00004801 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00004802 {
4803 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00004804 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00004805 abi_ulong gp;
4806 abi_ulong guest_argp;
4807 abi_ulong guest_envp;
4808 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00004809 char **q;
4810
bellardf7341ff2003-03-30 21:00:25 +00004811 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00004812 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00004813 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004814 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004815 goto efault;
ths03aa1972007-12-02 06:28:08 +00004816 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004817 break;
bellard7854b052003-03-29 17:22:23 +00004818 argc++;
bellard2f619692007-11-16 10:46:05 +00004819 }
bellardf7341ff2003-03-30 21:00:25 +00004820 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00004821 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00004822 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004823 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004824 goto efault;
ths03aa1972007-12-02 06:28:08 +00004825 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004826 break;
bellard7854b052003-03-29 17:22:23 +00004827 envc++;
bellard2f619692007-11-16 10:46:05 +00004828 }
bellard7854b052003-03-29 17:22:23 +00004829
bellardf7341ff2003-03-30 21:00:25 +00004830 argp = alloca((argc + 1) * sizeof(void *));
4831 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00004832
pbrookda94d262008-05-30 18:24:00 +00004833 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004834 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004835 if (get_user_ual(addr, gp))
4836 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004837 if (!addr)
4838 break;
bellard2f619692007-11-16 10:46:05 +00004839 if (!(*q = lock_user_string(addr)))
4840 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004841 }
bellardf7341ff2003-03-30 21:00:25 +00004842 *q = NULL;
4843
pbrookda94d262008-05-30 18:24:00 +00004844 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004845 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004846 if (get_user_ual(addr, gp))
4847 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004848 if (!addr)
4849 break;
bellard2f619692007-11-16 10:46:05 +00004850 if (!(*q = lock_user_string(addr)))
4851 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004852 }
bellardf7341ff2003-03-30 21:00:25 +00004853 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00004854
bellard2f619692007-11-16 10:46:05 +00004855 if (!(p = lock_user_string(arg1)))
4856 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004857 ret = get_errno(execve(p, argp, envp));
4858 unlock_user(p, arg1, 0);
4859
bellard2f619692007-11-16 10:46:05 +00004860 goto execve_end;
4861
4862 execve_efault:
4863 ret = -TARGET_EFAULT;
4864
4865 execve_end:
pbrook53a59602006-03-25 19:31:22 +00004866 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004867 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004868 if (get_user_ual(addr, gp)
4869 || !addr)
4870 break;
pbrook53a59602006-03-25 19:31:22 +00004871 unlock_user(*q, addr, 0);
4872 }
4873 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004874 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004875 if (get_user_ual(addr, gp)
4876 || !addr)
4877 break;
pbrook53a59602006-03-25 19:31:22 +00004878 unlock_user(*q, addr, 0);
4879 }
bellard7854b052003-03-29 17:22:23 +00004880 }
bellard31e31b82003-02-18 22:55:36 +00004881 break;
4882 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00004883 if (!(p = lock_user_string(arg1)))
4884 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004885 ret = get_errno(chdir(p));
4886 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004887 break;
bellarda315a142005-01-30 22:59:18 +00004888#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00004889 case TARGET_NR_time:
4890 {
pbrook53a59602006-03-25 19:31:22 +00004891 time_t host_time;
4892 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00004893 if (!is_error(ret)
4894 && arg1
4895 && put_user_sal(host_time, arg1))
4896 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004897 }
4898 break;
bellarda315a142005-01-30 22:59:18 +00004899#endif
bellard31e31b82003-02-18 22:55:36 +00004900 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00004901 if (!(p = lock_user_string(arg1)))
4902 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004903 ret = get_errno(mknod(p, arg2, arg3));
4904 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004905 break;
ths75ac37a2007-09-24 09:23:05 +00004906#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
4907 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00004908 if (!(p = lock_user_string(arg2)))
4909 goto efault;
4910 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
4911 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00004912 break;
4913#endif
bellard31e31b82003-02-18 22:55:36 +00004914 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00004915 if (!(p = lock_user_string(arg1)))
4916 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004917 ret = get_errno(chmod(p, arg2));
4918 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004919 break;
bellardebc05482003-09-30 21:08:41 +00004920#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00004921 case TARGET_NR_break:
4922 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004923#endif
4924#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00004925 case TARGET_NR_oldstat:
4926 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004927#endif
bellard31e31b82003-02-18 22:55:36 +00004928 case TARGET_NR_lseek:
4929 ret = get_errno(lseek(arg1, arg2, arg3));
4930 break;
Richard Henderson92317332010-05-03 10:07:53 -07004931#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
4932 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00004933 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07004934 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00004935 ret = get_errno(getpid());
4936 break;
Richard Henderson92317332010-05-03 10:07:53 -07004937#endif
4938#ifdef TARGET_NR_getpid
4939 case TARGET_NR_getpid:
4940 ret = get_errno(getpid());
4941 break;
4942#endif
bellard31e31b82003-02-18 22:55:36 +00004943 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00004944 {
4945 /* need to look at the data field */
4946 void *p2, *p3;
4947 p = lock_user_string(arg1);
4948 p2 = lock_user_string(arg2);
4949 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00004950 if (!p || !p2 || !p3)
4951 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004952 else {
bellard579a97f2007-11-11 14:26:47 +00004953 /* FIXME - arg5 should be locked, but it isn't clear how to
4954 * do that since it's not guaranteed to be a NULL-terminated
4955 * string.
4956 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004957 if ( ! arg5 )
4958 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
4959 else
4960 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
4961 }
bellard579a97f2007-11-11 14:26:47 +00004962 unlock_user(p, arg1, 0);
4963 unlock_user(p2, arg2, 0);
4964 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00004965 break;
4966 }
thse5febef2007-04-01 18:31:35 +00004967#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00004968 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00004969 if (!(p = lock_user_string(arg1)))
4970 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004971 ret = get_errno(umount(p));
4972 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004973 break;
thse5febef2007-04-01 18:31:35 +00004974#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004975#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004976 case TARGET_NR_stime:
4977 {
pbrook53a59602006-03-25 19:31:22 +00004978 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00004979 if (get_user_sal(host_time, arg1))
4980 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004981 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00004982 }
4983 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004984#endif
bellard31e31b82003-02-18 22:55:36 +00004985 case TARGET_NR_ptrace:
4986 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00004987#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004988 case TARGET_NR_alarm:
4989 ret = alarm(arg1);
4990 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004991#endif
bellardebc05482003-09-30 21:08:41 +00004992#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00004993 case TARGET_NR_oldfstat:
4994 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004995#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004996#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004997 case TARGET_NR_pause:
4998 ret = get_errno(pause());
4999 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005000#endif
thse5febef2007-04-01 18:31:35 +00005001#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005002 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005003 {
pbrook53a59602006-03-25 19:31:22 +00005004 struct utimbuf tbuf, *host_tbuf;
5005 struct target_utimbuf *target_tbuf;
5006 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005007 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5008 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005009 tbuf.actime = tswapal(target_tbuf->actime);
5010 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005011 unlock_user_struct(target_tbuf, arg2, 0);
5012 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005013 } else {
pbrook53a59602006-03-25 19:31:22 +00005014 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005015 }
bellard579a97f2007-11-11 14:26:47 +00005016 if (!(p = lock_user_string(arg1)))
5017 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005018 ret = get_errno(utime(p, host_tbuf));
5019 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005020 }
5021 break;
thse5febef2007-04-01 18:31:35 +00005022#endif
bellard978a66f2004-12-06 22:58:05 +00005023 case TARGET_NR_utimes:
5024 {
bellard978a66f2004-12-06 22:58:05 +00005025 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005026 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005027 if (copy_from_user_timeval(&tv[0], arg2)
5028 || copy_from_user_timeval(&tv[1],
5029 arg2 + sizeof(struct target_timeval)))
5030 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005031 tvp = tv;
5032 } else {
5033 tvp = NULL;
5034 }
bellard579a97f2007-11-11 14:26:47 +00005035 if (!(p = lock_user_string(arg1)))
5036 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005037 ret = get_errno(utimes(p, tvp));
5038 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005039 }
5040 break;
balrogac8a6552008-09-20 02:25:39 +00005041#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5042 case TARGET_NR_futimesat:
5043 {
5044 struct timeval *tvp, tv[2];
5045 if (arg3) {
5046 if (copy_from_user_timeval(&tv[0], arg3)
5047 || copy_from_user_timeval(&tv[1],
5048 arg3 + sizeof(struct target_timeval)))
5049 goto efault;
5050 tvp = tv;
5051 } else {
5052 tvp = NULL;
5053 }
5054 if (!(p = lock_user_string(arg2)))
5055 goto efault;
5056 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5057 unlock_user(p, arg2, 0);
5058 }
5059 break;
5060#endif
bellardebc05482003-09-30 21:08:41 +00005061#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005062 case TARGET_NR_stty:
5063 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005064#endif
5065#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005066 case TARGET_NR_gtty:
5067 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005068#endif
bellard31e31b82003-02-18 22:55:36 +00005069 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005070 if (!(p = lock_user_string(arg1)))
5071 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005072 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005073 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005074 break;
ths92a34c12007-09-24 09:27:49 +00005075#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5076 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005077 if (!(p = lock_user_string(arg2)))
5078 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005079 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005080 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005081 break;
5082#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005083#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005084 case TARGET_NR_nice:
5085 ret = get_errno(nice(arg1));
5086 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005087#endif
bellardebc05482003-09-30 21:08:41 +00005088#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005089 case TARGET_NR_ftime:
5090 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005091#endif
bellard31e31b82003-02-18 22:55:36 +00005092 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005093 sync();
5094 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005095 break;
5096 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005097 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005098 break;
5099 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005100 {
5101 void *p2;
5102 p = lock_user_string(arg1);
5103 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005104 if (!p || !p2)
5105 ret = -TARGET_EFAULT;
5106 else
5107 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005108 unlock_user(p2, arg2, 0);
5109 unlock_user(p, arg1, 0);
5110 }
bellard31e31b82003-02-18 22:55:36 +00005111 break;
ths722183f2007-09-24 09:24:37 +00005112#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5113 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005114 {
bellard579a97f2007-11-11 14:26:47 +00005115 void *p2;
ths722183f2007-09-24 09:24:37 +00005116 p = lock_user_string(arg2);
5117 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005118 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005119 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005120 else
5121 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005122 unlock_user(p2, arg4, 0);
5123 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005124 }
5125 break;
5126#endif
bellard31e31b82003-02-18 22:55:36 +00005127 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005128 if (!(p = lock_user_string(arg1)))
5129 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005130 ret = get_errno(mkdir(p, arg2));
5131 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005132 break;
ths4472ad02007-09-24 09:22:32 +00005133#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5134 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005135 if (!(p = lock_user_string(arg2)))
5136 goto efault;
5137 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5138 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005139 break;
5140#endif
bellard31e31b82003-02-18 22:55:36 +00005141 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005142 if (!(p = lock_user_string(arg1)))
5143 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005144 ret = get_errno(rmdir(p));
5145 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005146 break;
5147 case TARGET_NR_dup:
5148 ret = get_errno(dup(arg1));
5149 break;
5150 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005151 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005152 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005153#ifdef TARGET_NR_pipe2
5154 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005155 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005156 break;
5157#endif
bellard31e31b82003-02-18 22:55:36 +00005158 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005159 {
pbrook53a59602006-03-25 19:31:22 +00005160 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005161 struct tms tms;
5162 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005163 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005164 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5165 if (!tmsp)
5166 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005167 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5168 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5169 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5170 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005171 }
bellardc596ed12003-07-13 17:32:31 +00005172 if (!is_error(ret))
5173 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005174 }
5175 break;
bellardebc05482003-09-30 21:08:41 +00005176#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005177 case TARGET_NR_prof:
5178 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005179#endif
thse5febef2007-04-01 18:31:35 +00005180#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005181 case TARGET_NR_signal:
5182 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005183#endif
bellard31e31b82003-02-18 22:55:36 +00005184 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005185 if (arg1 == 0) {
5186 ret = get_errno(acct(NULL));
5187 } else {
5188 if (!(p = lock_user_string(arg1)))
5189 goto efault;
5190 ret = get_errno(acct(path(p)));
5191 unlock_user(p, arg1, 0);
5192 }
pbrook24836682006-04-16 14:14:53 +00005193 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005194#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005195 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005196 if (!(p = lock_user_string(arg1)))
5197 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005198 ret = get_errno(umount2(p, arg2));
5199 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005200 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005201#endif
bellardebc05482003-09-30 21:08:41 +00005202#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005203 case TARGET_NR_lock:
5204 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005205#endif
bellard31e31b82003-02-18 22:55:36 +00005206 case TARGET_NR_ioctl:
5207 ret = do_ioctl(arg1, arg2, arg3);
5208 break;
5209 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005210 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005211 break;
bellardebc05482003-09-30 21:08:41 +00005212#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005213 case TARGET_NR_mpx:
5214 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005215#endif
bellard31e31b82003-02-18 22:55:36 +00005216 case TARGET_NR_setpgid:
5217 ret = get_errno(setpgid(arg1, arg2));
5218 break;
bellardebc05482003-09-30 21:08:41 +00005219#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005220 case TARGET_NR_ulimit:
5221 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005222#endif
5223#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005224 case TARGET_NR_oldolduname:
5225 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005226#endif
bellard31e31b82003-02-18 22:55:36 +00005227 case TARGET_NR_umask:
5228 ret = get_errno(umask(arg1));
5229 break;
5230 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005231 if (!(p = lock_user_string(arg1)))
5232 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005233 ret = get_errno(chroot(p));
5234 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005235 break;
5236 case TARGET_NR_ustat:
5237 goto unimplemented;
5238 case TARGET_NR_dup2:
5239 ret = get_errno(dup2(arg1, arg2));
5240 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005241#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5242 case TARGET_NR_dup3:
5243 ret = get_errno(dup3(arg1, arg2, arg3));
5244 break;
5245#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005246#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005247 case TARGET_NR_getppid:
5248 ret = get_errno(getppid());
5249 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005250#endif
bellard31e31b82003-02-18 22:55:36 +00005251 case TARGET_NR_getpgrp:
5252 ret = get_errno(getpgrp());
5253 break;
5254 case TARGET_NR_setsid:
5255 ret = get_errno(setsid());
5256 break;
thse5febef2007-04-01 18:31:35 +00005257#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005258 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005259 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005260#if defined(TARGET_ALPHA)
5261 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005262 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005263 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005264 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5265 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005266 act._sa_handler = old_act->_sa_handler;
5267 target_siginitset(&act.sa_mask, old_act->sa_mask);
5268 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005269 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005270 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005271 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005272 }
5273 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005274 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005275 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5276 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005277 old_act->_sa_handler = oact._sa_handler;
5278 old_act->sa_mask = oact.sa_mask.sig[0];
5279 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005280 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005281 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005282#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005283 struct target_sigaction act, oact, *pact, *old_act;
5284
5285 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005286 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5287 goto efault;
bellard106ec872006-06-27 21:08:10 +00005288 act._sa_handler = old_act->_sa_handler;
5289 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5290 act.sa_flags = old_act->sa_flags;
5291 unlock_user_struct(old_act, arg2, 0);
5292 pact = &act;
5293 } else {
5294 pact = NULL;
5295 }
5296
5297 ret = get_errno(do_sigaction(arg1, pact, &oact));
5298
5299 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005300 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5301 goto efault;
bellard106ec872006-06-27 21:08:10 +00005302 old_act->_sa_handler = oact._sa_handler;
5303 old_act->sa_flags = oact.sa_flags;
5304 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5305 old_act->sa_mask.sig[1] = 0;
5306 old_act->sa_mask.sig[2] = 0;
5307 old_act->sa_mask.sig[3] = 0;
5308 unlock_user_struct(old_act, arg3, 1);
5309 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005310#else
5311 struct target_old_sigaction *old_act;
5312 struct target_sigaction act, oact, *pact;
5313 if (arg2) {
5314 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5315 goto efault;
5316 act._sa_handler = old_act->_sa_handler;
5317 target_siginitset(&act.sa_mask, old_act->sa_mask);
5318 act.sa_flags = old_act->sa_flags;
5319 act.sa_restorer = old_act->sa_restorer;
5320 unlock_user_struct(old_act, arg2, 0);
5321 pact = &act;
5322 } else {
5323 pact = NULL;
5324 }
5325 ret = get_errno(do_sigaction(arg1, pact, &oact));
5326 if (!is_error(ret) && arg3) {
5327 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5328 goto efault;
5329 old_act->_sa_handler = oact._sa_handler;
5330 old_act->sa_mask = oact.sa_mask.sig[0];
5331 old_act->sa_flags = oact.sa_flags;
5332 old_act->sa_restorer = oact.sa_restorer;
5333 unlock_user_struct(old_act, arg3, 1);
5334 }
ths388bb212007-05-13 13:58:00 +00005335#endif
bellard31e31b82003-02-18 22:55:36 +00005336 }
5337 break;
thse5febef2007-04-01 18:31:35 +00005338#endif
bellard66fb9762003-03-23 01:06:05 +00005339 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005340 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005341#if defined(TARGET_ALPHA)
5342 struct target_sigaction act, oact, *pact = 0;
5343 struct target_rt_sigaction *rt_act;
5344 /* ??? arg4 == sizeof(sigset_t). */
5345 if (arg2) {
5346 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5347 goto efault;
5348 act._sa_handler = rt_act->_sa_handler;
5349 act.sa_mask = rt_act->sa_mask;
5350 act.sa_flags = rt_act->sa_flags;
5351 act.sa_restorer = arg5;
5352 unlock_user_struct(rt_act, arg2, 0);
5353 pact = &act;
5354 }
5355 ret = get_errno(do_sigaction(arg1, pact, &oact));
5356 if (!is_error(ret) && arg3) {
5357 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5358 goto efault;
5359 rt_act->_sa_handler = oact._sa_handler;
5360 rt_act->sa_mask = oact.sa_mask;
5361 rt_act->sa_flags = oact.sa_flags;
5362 unlock_user_struct(rt_act, arg3, 1);
5363 }
5364#else
pbrook53a59602006-03-25 19:31:22 +00005365 struct target_sigaction *act;
5366 struct target_sigaction *oact;
5367
bellard579a97f2007-11-11 14:26:47 +00005368 if (arg2) {
5369 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5370 goto efault;
5371 } else
pbrook53a59602006-03-25 19:31:22 +00005372 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005373 if (arg3) {
5374 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5375 ret = -TARGET_EFAULT;
5376 goto rt_sigaction_fail;
5377 }
5378 } else
pbrook53a59602006-03-25 19:31:22 +00005379 oact = NULL;
5380 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005381 rt_sigaction_fail:
5382 if (act)
pbrook53a59602006-03-25 19:31:22 +00005383 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005384 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005385 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005386#endif
pbrook53a59602006-03-25 19:31:22 +00005387 }
bellard66fb9762003-03-23 01:06:05 +00005388 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005389#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005390 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005391 {
5392 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005393 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005394 sigprocmask(0, NULL, &cur_set);
5395 host_to_target_old_sigset(&target_set, &cur_set);
5396 ret = target_set;
5397 }
5398 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005399#endif
5400#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005401 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005402 {
5403 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005404 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005405 sigprocmask(0, NULL, &cur_set);
5406 target_to_host_old_sigset(&set, &target_set);
5407 sigorset(&set, &set, &cur_set);
5408 sigprocmask(SIG_SETMASK, &set, &oset);
5409 host_to_target_old_sigset(&target_set, &oset);
5410 ret = target_set;
5411 }
5412 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005413#endif
thse5febef2007-04-01 18:31:35 +00005414#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005415 case TARGET_NR_sigprocmask:
5416 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005417#if defined(TARGET_ALPHA)
5418 sigset_t set, oldset;
5419 abi_ulong mask;
5420 int how;
5421
5422 switch (arg1) {
5423 case TARGET_SIG_BLOCK:
5424 how = SIG_BLOCK;
5425 break;
5426 case TARGET_SIG_UNBLOCK:
5427 how = SIG_UNBLOCK;
5428 break;
5429 case TARGET_SIG_SETMASK:
5430 how = SIG_SETMASK;
5431 break;
5432 default:
5433 ret = -TARGET_EINVAL;
5434 goto fail;
5435 }
5436 mask = arg2;
5437 target_to_host_old_sigset(&set, &mask);
5438
5439 ret = get_errno(sigprocmask(how, &set, &oldset));
5440
5441 if (!is_error(ret)) {
5442 host_to_target_old_sigset(&mask, &oldset);
5443 ret = mask;
5444 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5445 }
5446#else
bellard66fb9762003-03-23 01:06:05 +00005447 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005448 int how;
ths3b46e622007-09-17 08:09:54 +00005449
pbrook53a59602006-03-25 19:31:22 +00005450 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005451 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005452 case TARGET_SIG_BLOCK:
5453 how = SIG_BLOCK;
5454 break;
5455 case TARGET_SIG_UNBLOCK:
5456 how = SIG_UNBLOCK;
5457 break;
5458 case TARGET_SIG_SETMASK:
5459 how = SIG_SETMASK;
5460 break;
5461 default:
ths0da46a62007-10-20 20:23:07 +00005462 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005463 goto fail;
5464 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005465 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005466 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005467 target_to_host_old_sigset(&set, p);
5468 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005469 set_ptr = &set;
5470 } else {
5471 how = 0;
5472 set_ptr = NULL;
5473 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005474 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005475 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005476 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005477 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005478 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005479 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005480 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005481#endif
bellard66fb9762003-03-23 01:06:05 +00005482 }
5483 break;
thse5febef2007-04-01 18:31:35 +00005484#endif
bellard66fb9762003-03-23 01:06:05 +00005485 case TARGET_NR_rt_sigprocmask:
5486 {
5487 int how = arg1;
5488 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005489
pbrook53a59602006-03-25 19:31:22 +00005490 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005491 switch(how) {
5492 case TARGET_SIG_BLOCK:
5493 how = SIG_BLOCK;
5494 break;
5495 case TARGET_SIG_UNBLOCK:
5496 how = SIG_UNBLOCK;
5497 break;
5498 case TARGET_SIG_SETMASK:
5499 how = SIG_SETMASK;
5500 break;
5501 default:
ths0da46a62007-10-20 20:23:07 +00005502 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005503 goto fail;
5504 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005505 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005506 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005507 target_to_host_sigset(&set, p);
5508 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005509 set_ptr = &set;
5510 } else {
5511 how = 0;
5512 set_ptr = NULL;
5513 }
5514 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005515 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005516 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005517 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005518 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005519 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005520 }
5521 }
5522 break;
thse5febef2007-04-01 18:31:35 +00005523#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005524 case TARGET_NR_sigpending:
5525 {
5526 sigset_t set;
5527 ret = get_errno(sigpending(&set));
5528 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005529 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005530 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005531 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005532 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005533 }
5534 }
5535 break;
thse5febef2007-04-01 18:31:35 +00005536#endif
bellard66fb9762003-03-23 01:06:05 +00005537 case TARGET_NR_rt_sigpending:
5538 {
5539 sigset_t set;
5540 ret = get_errno(sigpending(&set));
5541 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005542 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005543 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005544 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005545 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005546 }
5547 }
5548 break;
thse5febef2007-04-01 18:31:35 +00005549#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005550 case TARGET_NR_sigsuspend:
5551 {
5552 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005553#if defined(TARGET_ALPHA)
5554 abi_ulong mask = arg1;
5555 target_to_host_old_sigset(&set, &mask);
5556#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005557 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005558 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005559 target_to_host_old_sigset(&set, p);
5560 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005561#endif
bellard66fb9762003-03-23 01:06:05 +00005562 ret = get_errno(sigsuspend(&set));
5563 }
5564 break;
thse5febef2007-04-01 18:31:35 +00005565#endif
bellard66fb9762003-03-23 01:06:05 +00005566 case TARGET_NR_rt_sigsuspend:
5567 {
5568 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005569 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005570 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005571 target_to_host_sigset(&set, p);
5572 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005573 ret = get_errno(sigsuspend(&set));
5574 }
5575 break;
5576 case TARGET_NR_rt_sigtimedwait:
5577 {
bellard66fb9762003-03-23 01:06:05 +00005578 sigset_t set;
5579 struct timespec uts, *puts;
5580 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005581
Anthony Liguoric227f092009-10-01 16:12:16 -05005582 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005583 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005584 target_to_host_sigset(&set, p);
5585 unlock_user(p, arg1, 0);
5586 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005587 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005588 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005589 } else {
5590 puts = NULL;
5591 }
5592 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005593 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005594 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005595 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005596 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005597 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005598 }
5599 }
5600 break;
5601 case TARGET_NR_rt_sigqueueinfo:
5602 {
5603 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005604 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005605 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005606 target_to_host_siginfo(&uinfo, p);
5607 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005608 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5609 }
5610 break;
thse5febef2007-04-01 18:31:35 +00005611#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005612 case TARGET_NR_sigreturn:
5613 /* NOTE: ret is eax, so not transcoding must be done */
5614 ret = do_sigreturn(cpu_env);
5615 break;
thse5febef2007-04-01 18:31:35 +00005616#endif
bellard66fb9762003-03-23 01:06:05 +00005617 case TARGET_NR_rt_sigreturn:
5618 /* NOTE: ret is eax, so not transcoding must be done */
5619 ret = do_rt_sigreturn(cpu_env);
5620 break;
bellard31e31b82003-02-18 22:55:36 +00005621 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00005622 if (!(p = lock_user_string(arg1)))
5623 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005624 ret = get_errno(sethostname(p, arg2));
5625 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005626 break;
5627 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00005628 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005629 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005630 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005631 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00005632 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
5633 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005634 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
5635 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005636 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00005637 ret = get_errno(setrlimit(resource, &rlim));
5638 }
5639 break;
bellard31e31b82003-02-18 22:55:36 +00005640 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00005641 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005642 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005643 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005644 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00005645
bellard9de5e442003-03-23 16:49:39 +00005646 ret = get_errno(getrlimit(resource, &rlim));
5647 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005648 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
5649 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005650 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
5651 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005652 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00005653 }
5654 }
5655 break;
bellard31e31b82003-02-18 22:55:36 +00005656 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00005657 {
5658 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00005659 ret = get_errno(getrusage(arg1, &rusage));
5660 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005661 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00005662 }
5663 }
5664 break;
bellard31e31b82003-02-18 22:55:36 +00005665 case TARGET_NR_gettimeofday:
5666 {
bellard31e31b82003-02-18 22:55:36 +00005667 struct timeval tv;
5668 ret = get_errno(gettimeofday(&tv, NULL));
5669 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00005670 if (copy_to_user_timeval(arg1, &tv))
5671 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005672 }
5673 }
5674 break;
5675 case TARGET_NR_settimeofday:
5676 {
bellard31e31b82003-02-18 22:55:36 +00005677 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00005678 if (copy_from_user_timeval(&tv, arg1))
5679 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005680 ret = get_errno(settimeofday(&tv, NULL));
5681 }
5682 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005683#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00005684 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00005685 {
pbrook53a59602006-03-25 19:31:22 +00005686 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00005687 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00005688 long nsel;
5689
bellard579a97f2007-11-11 14:26:47 +00005690 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
5691 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005692 nsel = tswapal(sel->n);
5693 inp = tswapal(sel->inp);
5694 outp = tswapal(sel->outp);
5695 exp = tswapal(sel->exp);
5696 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00005697 unlock_user_struct(sel, arg1, 0);
5698 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00005699 }
5700 break;
bellard048f6b42005-11-26 18:47:20 +00005701#endif
Riku Voipio9e423822010-05-07 12:28:05 +00005702#ifdef TARGET_NR_pselect6
5703 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04005704 {
5705 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
5706 fd_set rfds, wfds, efds;
5707 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
5708 struct timespec ts, *ts_ptr;
5709
5710 /*
5711 * The 6th arg is actually two args smashed together,
5712 * so we cannot use the C library.
5713 */
5714 sigset_t set;
5715 struct {
5716 sigset_t *set;
5717 size_t size;
5718 } sig, *sig_ptr;
5719
5720 abi_ulong arg_sigset, arg_sigsize, *arg7;
5721 target_sigset_t *target_sigset;
5722
5723 n = arg1;
5724 rfd_addr = arg2;
5725 wfd_addr = arg3;
5726 efd_addr = arg4;
5727 ts_addr = arg5;
5728
5729 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
5730 if (ret) {
5731 goto fail;
5732 }
5733 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
5734 if (ret) {
5735 goto fail;
5736 }
5737 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
5738 if (ret) {
5739 goto fail;
5740 }
5741
5742 /*
5743 * This takes a timespec, and not a timeval, so we cannot
5744 * use the do_select() helper ...
5745 */
5746 if (ts_addr) {
5747 if (target_to_host_timespec(&ts, ts_addr)) {
5748 goto efault;
5749 }
5750 ts_ptr = &ts;
5751 } else {
5752 ts_ptr = NULL;
5753 }
5754
5755 /* Extract the two packed args for the sigset */
5756 if (arg6) {
5757 sig_ptr = &sig;
5758 sig.size = _NSIG / 8;
5759
5760 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
5761 if (!arg7) {
5762 goto efault;
5763 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005764 arg_sigset = tswapal(arg7[0]);
5765 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04005766 unlock_user(arg7, arg6, 0);
5767
5768 if (arg_sigset) {
5769 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01005770 if (arg_sigsize != sizeof(*target_sigset)) {
5771 /* Like the kernel, we enforce correct size sigsets */
5772 ret = -TARGET_EINVAL;
5773 goto fail;
5774 }
Mike Frysinger055e0902011-06-03 17:01:49 -04005775 target_sigset = lock_user(VERIFY_READ, arg_sigset,
5776 sizeof(*target_sigset), 1);
5777 if (!target_sigset) {
5778 goto efault;
5779 }
5780 target_to_host_sigset(&set, target_sigset);
5781 unlock_user(target_sigset, arg_sigset, 0);
5782 } else {
5783 sig.set = NULL;
5784 }
5785 } else {
5786 sig_ptr = NULL;
5787 }
5788
5789 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
5790 ts_ptr, sig_ptr));
5791
5792 if (!is_error(ret)) {
5793 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
5794 goto efault;
5795 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
5796 goto efault;
5797 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
5798 goto efault;
5799
5800 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
5801 goto efault;
5802 }
5803 }
5804 break;
Riku Voipio9e423822010-05-07 12:28:05 +00005805#endif
bellard31e31b82003-02-18 22:55:36 +00005806 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00005807 {
5808 void *p2;
5809 p = lock_user_string(arg1);
5810 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005811 if (!p || !p2)
5812 ret = -TARGET_EFAULT;
5813 else
5814 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005815 unlock_user(p2, arg2, 0);
5816 unlock_user(p, arg1, 0);
5817 }
bellard31e31b82003-02-18 22:55:36 +00005818 break;
thsf0b62432007-09-24 09:25:40 +00005819#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
5820 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00005821 {
bellard579a97f2007-11-11 14:26:47 +00005822 void *p2;
thsf0b62432007-09-24 09:25:40 +00005823 p = lock_user_string(arg1);
5824 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005825 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005826 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00005827 else
5828 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00005829 unlock_user(p2, arg3, 0);
5830 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00005831 }
5832 break;
5833#endif
bellardebc05482003-09-30 21:08:41 +00005834#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00005835 case TARGET_NR_oldlstat:
5836 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005837#endif
bellard31e31b82003-02-18 22:55:36 +00005838 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00005839 {
aurel32d088d662009-01-30 20:09:01 +00005840 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00005841 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00005842 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
5843 if (!p || !p2)
5844 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00005845 else {
5846 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
5847 char real[PATH_MAX];
5848 temp = realpath(exec_path,real);
5849 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
5850 snprintf((char *)p2, arg3, "%s", real);
5851 }
5852 else
5853 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00005854 }
pbrook53a59602006-03-25 19:31:22 +00005855 unlock_user(p2, arg2, ret);
5856 unlock_user(p, arg1, 0);
5857 }
bellard31e31b82003-02-18 22:55:36 +00005858 break;
ths5e0ccb12007-09-24 09:26:10 +00005859#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
5860 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00005861 {
bellard579a97f2007-11-11 14:26:47 +00005862 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00005863 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005864 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
5865 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005866 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00005867 else
5868 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00005869 unlock_user(p2, arg3, ret);
5870 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00005871 }
5872 break;
5873#endif
thse5febef2007-04-01 18:31:35 +00005874#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00005875 case TARGET_NR_uselib:
5876 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005877#endif
5878#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00005879 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00005880 if (!(p = lock_user_string(arg1)))
5881 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005882 ret = get_errno(swapon(p, arg2));
5883 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005884 break;
thse5febef2007-04-01 18:31:35 +00005885#endif
bellard31e31b82003-02-18 22:55:36 +00005886 case TARGET_NR_reboot:
5887 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005888#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00005889 case TARGET_NR_readdir:
5890 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005891#endif
5892#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00005893 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005894#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
5895 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
5896 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00005897 {
blueswir1992f48a2007-10-14 16:27:31 +00005898 abi_ulong *v;
5899 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00005900 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
5901 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005902 v1 = tswapal(v[0]);
5903 v2 = tswapal(v[1]);
5904 v3 = tswapal(v[2]);
5905 v4 = tswapal(v[3]);
5906 v5 = tswapal(v[4]);
5907 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00005908 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00005909 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00005910 target_to_host_bitmask(v4, mmap_flags_tbl),
5911 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00005912 }
bellard31e31b82003-02-18 22:55:36 +00005913#else
ths5fafdf22007-09-16 21:08:06 +00005914 ret = get_errno(target_mmap(arg1, arg2, arg3,
5915 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00005916 arg5,
5917 arg6));
bellard31e31b82003-02-18 22:55:36 +00005918#endif
bellard6fb883e2003-07-09 17:12:39 +00005919 break;
thse5febef2007-04-01 18:31:35 +00005920#endif
bellarda315a142005-01-30 22:59:18 +00005921#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00005922 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00005923#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00005924#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00005925#endif
ths5fafdf22007-09-16 21:08:06 +00005926 ret = get_errno(target_mmap(arg1, arg2, arg3,
5927 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00005928 arg5,
bellardc573ff62004-01-04 15:51:36 +00005929 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00005930 break;
bellarda315a142005-01-30 22:59:18 +00005931#endif
bellard31e31b82003-02-18 22:55:36 +00005932 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00005933 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005934 break;
bellard9de5e442003-03-23 16:49:39 +00005935 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01005936 {
5937 TaskState *ts = ((CPUState *)cpu_env)->opaque;
5938 /* Special hack to detect libc making the stack executable. */
5939 if ((arg3 & PROT_GROWSDOWN)
5940 && arg1 >= ts->info->stack_limit
5941 && arg1 <= ts->info->start_stack) {
5942 arg3 &= ~PROT_GROWSDOWN;
5943 arg2 = arg2 + arg1 - ts->info->stack_limit;
5944 arg1 = ts->info->stack_limit;
5945 }
5946 }
bellard54936002003-05-13 00:25:15 +00005947 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005948 break;
thse5febef2007-04-01 18:31:35 +00005949#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00005950 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00005951 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00005952 break;
thse5febef2007-04-01 18:31:35 +00005953#endif
pbrook53a59602006-03-25 19:31:22 +00005954 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00005955#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00005956 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00005957 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005958 break;
thse5febef2007-04-01 18:31:35 +00005959#endif
5960#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00005961 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00005962 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005963 break;
thse5febef2007-04-01 18:31:35 +00005964#endif
5965#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00005966 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00005967 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005968 break;
thse5febef2007-04-01 18:31:35 +00005969#endif
5970#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00005971 case TARGET_NR_mlockall:
5972 ret = get_errno(mlockall(arg1));
5973 break;
thse5febef2007-04-01 18:31:35 +00005974#endif
5975#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00005976 case TARGET_NR_munlockall:
5977 ret = get_errno(munlockall());
5978 break;
thse5febef2007-04-01 18:31:35 +00005979#endif
bellard31e31b82003-02-18 22:55:36 +00005980 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00005981 if (!(p = lock_user_string(arg1)))
5982 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005983 ret = get_errno(truncate(p, arg2));
5984 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005985 break;
5986 case TARGET_NR_ftruncate:
5987 ret = get_errno(ftruncate(arg1, arg2));
5988 break;
5989 case TARGET_NR_fchmod:
5990 ret = get_errno(fchmod(arg1, arg2));
5991 break;
ths814d7972007-09-24 09:26:51 +00005992#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
5993 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00005994 if (!(p = lock_user_string(arg2)))
5995 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005996 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005997 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00005998 break;
5999#endif
bellard31e31b82003-02-18 22:55:36 +00006000 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00006001 /* libc does special remapping of the return value of
6002 * sys_getpriority() so it's just easiest to call
6003 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03006004 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006005 break;
6006 case TARGET_NR_setpriority:
6007 ret = get_errno(setpriority(arg1, arg2, arg3));
6008 break;
bellardebc05482003-09-30 21:08:41 +00006009#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006010 case TARGET_NR_profil:
6011 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006012#endif
bellard31e31b82003-02-18 22:55:36 +00006013 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006014 if (!(p = lock_user_string(arg1)))
6015 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006016 ret = get_errno(statfs(path(p), &stfs));
6017 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006018 convert_statfs:
6019 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006020 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006021
bellard579a97f2007-11-11 14:26:47 +00006022 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6023 goto efault;
6024 __put_user(stfs.f_type, &target_stfs->f_type);
6025 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6026 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6027 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6028 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6029 __put_user(stfs.f_files, &target_stfs->f_files);
6030 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6031 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6032 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6033 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00006034 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006035 }
6036 break;
6037 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006038 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006039 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006040#ifdef TARGET_NR_statfs64
6041 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006042 if (!(p = lock_user_string(arg1)))
6043 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006044 ret = get_errno(statfs(path(p), &stfs));
6045 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006046 convert_statfs64:
6047 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006048 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006049
bellard579a97f2007-11-11 14:26:47 +00006050 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6051 goto efault;
6052 __put_user(stfs.f_type, &target_stfs->f_type);
6053 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6054 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6055 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6056 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6057 __put_user(stfs.f_files, &target_stfs->f_files);
6058 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6059 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6060 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6061 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
6062 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006063 }
6064 break;
6065 case TARGET_NR_fstatfs64:
6066 ret = get_errno(fstatfs(arg1, &stfs));
6067 goto convert_statfs64;
6068#endif
bellardebc05482003-09-30 21:08:41 +00006069#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006070 case TARGET_NR_ioperm:
6071 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006072#endif
thse5febef2007-04-01 18:31:35 +00006073#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006074 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006075 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006076 break;
thse5febef2007-04-01 18:31:35 +00006077#endif
bellard3532fa72006-06-24 15:06:03 +00006078#ifdef TARGET_NR_accept
6079 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006080 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006081 break;
6082#endif
6083#ifdef TARGET_NR_bind
6084 case TARGET_NR_bind:
6085 ret = do_bind(arg1, arg2, arg3);
6086 break;
6087#endif
6088#ifdef TARGET_NR_connect
6089 case TARGET_NR_connect:
6090 ret = do_connect(arg1, arg2, arg3);
6091 break;
6092#endif
6093#ifdef TARGET_NR_getpeername
6094 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006095 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006096 break;
6097#endif
6098#ifdef TARGET_NR_getsockname
6099 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006100 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006101 break;
6102#endif
6103#ifdef TARGET_NR_getsockopt
6104 case TARGET_NR_getsockopt:
6105 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6106 break;
6107#endif
6108#ifdef TARGET_NR_listen
6109 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006110 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006111 break;
6112#endif
6113#ifdef TARGET_NR_recv
6114 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006115 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006116 break;
6117#endif
6118#ifdef TARGET_NR_recvfrom
6119 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006120 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006121 break;
6122#endif
6123#ifdef TARGET_NR_recvmsg
6124 case TARGET_NR_recvmsg:
6125 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6126 break;
6127#endif
6128#ifdef TARGET_NR_send
6129 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006130 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006131 break;
6132#endif
6133#ifdef TARGET_NR_sendmsg
6134 case TARGET_NR_sendmsg:
6135 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6136 break;
6137#endif
6138#ifdef TARGET_NR_sendto
6139 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006140 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006141 break;
6142#endif
6143#ifdef TARGET_NR_shutdown
6144 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006145 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006146 break;
6147#endif
6148#ifdef TARGET_NR_socket
6149 case TARGET_NR_socket:
6150 ret = do_socket(arg1, arg2, arg3);
6151 break;
6152#endif
6153#ifdef TARGET_NR_socketpair
6154 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006155 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006156 break;
6157#endif
6158#ifdef TARGET_NR_setsockopt
6159 case TARGET_NR_setsockopt:
6160 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6161 break;
6162#endif
ths7494b0f2007-02-11 18:26:53 +00006163
bellard31e31b82003-02-18 22:55:36 +00006164 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006165 if (!(p = lock_user_string(arg2)))
6166 goto efault;
thse5574482007-02-11 20:03:13 +00006167 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6168 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006169 break;
6170
bellard31e31b82003-02-18 22:55:36 +00006171 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006172 {
bellard66fb9762003-03-23 01:06:05 +00006173 struct itimerval value, ovalue, *pvalue;
6174
pbrook53a59602006-03-25 19:31:22 +00006175 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006176 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006177 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6178 || copy_from_user_timeval(&pvalue->it_value,
6179 arg2 + sizeof(struct target_timeval)))
6180 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006181 } else {
6182 pvalue = NULL;
6183 }
6184 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006185 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006186 if (copy_to_user_timeval(arg3,
6187 &ovalue.it_interval)
6188 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6189 &ovalue.it_value))
6190 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006191 }
6192 }
6193 break;
bellard31e31b82003-02-18 22:55:36 +00006194 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006195 {
bellard66fb9762003-03-23 01:06:05 +00006196 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006197
bellard66fb9762003-03-23 01:06:05 +00006198 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006199 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006200 if (copy_to_user_timeval(arg2,
6201 &value.it_interval)
6202 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6203 &value.it_value))
6204 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006205 }
6206 }
6207 break;
bellard31e31b82003-02-18 22:55:36 +00006208 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006209 if (!(p = lock_user_string(arg1)))
6210 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006211 ret = get_errno(stat(path(p), &st));
6212 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006213 goto do_stat;
6214 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006215 if (!(p = lock_user_string(arg1)))
6216 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006217 ret = get_errno(lstat(path(p), &st));
6218 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006219 goto do_stat;
6220 case TARGET_NR_fstat:
6221 {
6222 ret = get_errno(fstat(arg1, &st));
6223 do_stat:
6224 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006225 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006226
bellard579a97f2007-11-11 14:26:47 +00006227 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6228 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006229 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006230 __put_user(st.st_dev, &target_st->st_dev);
6231 __put_user(st.st_ino, &target_st->st_ino);
6232 __put_user(st.st_mode, &target_st->st_mode);
6233 __put_user(st.st_uid, &target_st->st_uid);
6234 __put_user(st.st_gid, &target_st->st_gid);
6235 __put_user(st.st_nlink, &target_st->st_nlink);
6236 __put_user(st.st_rdev, &target_st->st_rdev);
6237 __put_user(st.st_size, &target_st->st_size);
6238 __put_user(st.st_blksize, &target_st->st_blksize);
6239 __put_user(st.st_blocks, &target_st->st_blocks);
6240 __put_user(st.st_atime, &target_st->target_st_atime);
6241 __put_user(st.st_mtime, &target_st->target_st_mtime);
6242 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006243 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006244 }
6245 }
6246 break;
bellardebc05482003-09-30 21:08:41 +00006247#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006248 case TARGET_NR_olduname:
6249 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006250#endif
6251#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006252 case TARGET_NR_iopl:
6253 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006254#endif
bellard31e31b82003-02-18 22:55:36 +00006255 case TARGET_NR_vhangup:
6256 ret = get_errno(vhangup());
6257 break;
bellardebc05482003-09-30 21:08:41 +00006258#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006259 case TARGET_NR_idle:
6260 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006261#endif
bellard42ad6ae2005-01-03 22:48:11 +00006262#ifdef TARGET_NR_syscall
6263 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006264 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6265 arg6, arg7, arg8, 0);
6266 break;
bellard42ad6ae2005-01-03 22:48:11 +00006267#endif
bellard31e31b82003-02-18 22:55:36 +00006268 case TARGET_NR_wait4:
6269 {
6270 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006271 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006272 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006273 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006274 if (target_rusage)
6275 rusage_ptr = &rusage;
6276 else
6277 rusage_ptr = NULL;
6278 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6279 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006280 if (status_ptr) {
pbrook1d9d8b52009-04-16 15:17:02 +00006281 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006282 if (put_user_s32(status, status_ptr))
6283 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006284 }
bellard2f619692007-11-16 10:46:05 +00006285 if (target_rusage)
6286 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006287 }
6288 }
6289 break;
thse5febef2007-04-01 18:31:35 +00006290#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006291 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006292 if (!(p = lock_user_string(arg1)))
6293 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006294 ret = get_errno(swapoff(p));
6295 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006296 break;
thse5febef2007-04-01 18:31:35 +00006297#endif
bellard31e31b82003-02-18 22:55:36 +00006298 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006299 {
pbrook53a59602006-03-25 19:31:22 +00006300 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006301 struct sysinfo value;
6302 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006303 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006304 {
bellard579a97f2007-11-11 14:26:47 +00006305 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6306 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006307 __put_user(value.uptime, &target_value->uptime);
6308 __put_user(value.loads[0], &target_value->loads[0]);
6309 __put_user(value.loads[1], &target_value->loads[1]);
6310 __put_user(value.loads[2], &target_value->loads[2]);
6311 __put_user(value.totalram, &target_value->totalram);
6312 __put_user(value.freeram, &target_value->freeram);
6313 __put_user(value.sharedram, &target_value->sharedram);
6314 __put_user(value.bufferram, &target_value->bufferram);
6315 __put_user(value.totalswap, &target_value->totalswap);
6316 __put_user(value.freeswap, &target_value->freeswap);
6317 __put_user(value.procs, &target_value->procs);
6318 __put_user(value.totalhigh, &target_value->totalhigh);
6319 __put_user(value.freehigh, &target_value->freehigh);
6320 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006321 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006322 }
6323 }
6324 break;
thse5febef2007-04-01 18:31:35 +00006325#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006326 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006327 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6328 break;
thse5febef2007-04-01 18:31:35 +00006329#endif
aurel32e5289082009-04-18 16:16:12 +00006330#ifdef TARGET_NR_semget
6331 case TARGET_NR_semget:
6332 ret = get_errno(semget(arg1, arg2, arg3));
6333 break;
6334#endif
6335#ifdef TARGET_NR_semop
6336 case TARGET_NR_semop:
6337 ret = get_errno(do_semop(arg1, arg2, arg3));
6338 break;
6339#endif
6340#ifdef TARGET_NR_semctl
6341 case TARGET_NR_semctl:
6342 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6343 break;
6344#endif
aurel32eeb438c2008-10-13 21:08:55 +00006345#ifdef TARGET_NR_msgctl
6346 case TARGET_NR_msgctl:
6347 ret = do_msgctl(arg1, arg2, arg3);
6348 break;
6349#endif
6350#ifdef TARGET_NR_msgget
6351 case TARGET_NR_msgget:
6352 ret = get_errno(msgget(arg1, arg2));
6353 break;
6354#endif
6355#ifdef TARGET_NR_msgrcv
6356 case TARGET_NR_msgrcv:
6357 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6358 break;
6359#endif
6360#ifdef TARGET_NR_msgsnd
6361 case TARGET_NR_msgsnd:
6362 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6363 break;
6364#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006365#ifdef TARGET_NR_shmget
6366 case TARGET_NR_shmget:
6367 ret = get_errno(shmget(arg1, arg2, arg3));
6368 break;
6369#endif
6370#ifdef TARGET_NR_shmctl
6371 case TARGET_NR_shmctl:
6372 ret = do_shmctl(arg1, arg2, arg3);
6373 break;
6374#endif
6375#ifdef TARGET_NR_shmat
6376 case TARGET_NR_shmat:
6377 ret = do_shmat(arg1, arg2, arg3);
6378 break;
6379#endif
6380#ifdef TARGET_NR_shmdt
6381 case TARGET_NR_shmdt:
6382 ret = do_shmdt(arg1);
6383 break;
6384#endif
bellard31e31b82003-02-18 22:55:36 +00006385 case TARGET_NR_fsync:
6386 ret = get_errno(fsync(arg1));
6387 break;
bellard31e31b82003-02-18 22:55:36 +00006388 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006389#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006390 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006391#elif defined(TARGET_CRIS)
6392 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006393#elif defined(TARGET_S390X)
6394 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006395#else
pbrookd865bab2008-06-07 22:12:17 +00006396 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006397#endif
bellard1b6b0292003-03-22 17:31:38 +00006398 break;
bellardec86b0f2003-04-11 00:15:04 +00006399#ifdef __NR_exit_group
6400 /* new thread calls */
6401 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006402#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006403 _mcleanup();
6404#endif
bellarde9009672005-04-26 20:42:36 +00006405 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006406 ret = get_errno(exit_group(arg1));
6407 break;
6408#endif
bellard31e31b82003-02-18 22:55:36 +00006409 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006410 if (!(p = lock_user_string(arg1)))
6411 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006412 ret = get_errno(setdomainname(p, arg2));
6413 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006414 break;
6415 case TARGET_NR_uname:
6416 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006417 {
6418 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006419
bellard579a97f2007-11-11 14:26:47 +00006420 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6421 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006422 ret = get_errno(sys_uname(buf));
6423 if (!is_error(ret)) {
6424 /* Overrite the native machine name with whatever is being
6425 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006426 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006427 /* Allow the user to override the reported release. */
6428 if (qemu_uname_release && *qemu_uname_release)
6429 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006430 }
pbrook53a59602006-03-25 19:31:22 +00006431 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006432 }
bellard31e31b82003-02-18 22:55:36 +00006433 break;
bellard6dbad632003-03-16 18:05:05 +00006434#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006435 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006436 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006437 break;
j_mayer84409dd2007-04-06 08:56:50 +00006438#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006439 case TARGET_NR_vm86old:
6440 goto unimplemented;
6441 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006442 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006443 break;
6444#endif
j_mayer84409dd2007-04-06 08:56:50 +00006445#endif
bellard31e31b82003-02-18 22:55:36 +00006446 case TARGET_NR_adjtimex:
6447 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006448#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006449 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006450#endif
bellard31e31b82003-02-18 22:55:36 +00006451 case TARGET_NR_init_module:
6452 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006453#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006454 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006455#endif
bellard31e31b82003-02-18 22:55:36 +00006456 goto unimplemented;
6457 case TARGET_NR_quotactl:
6458 goto unimplemented;
6459 case TARGET_NR_getpgid:
6460 ret = get_errno(getpgid(arg1));
6461 break;
6462 case TARGET_NR_fchdir:
6463 ret = get_errno(fchdir(arg1));
6464 break;
j_mayer84409dd2007-04-06 08:56:50 +00006465#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006466 case TARGET_NR_bdflush:
6467 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006468#endif
thse5febef2007-04-01 18:31:35 +00006469#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006470 case TARGET_NR_sysfs:
6471 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006472#endif
bellard31e31b82003-02-18 22:55:36 +00006473 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006474 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006475 break;
thse5febef2007-04-01 18:31:35 +00006476#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006477 case TARGET_NR_afs_syscall:
6478 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006479#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006480#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006481 case TARGET_NR__llseek:
6482 {
6483 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006484#if !defined(__NR_llseek)
6485 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6486 if (res == -1) {
6487 ret = get_errno(res);
6488 } else {
6489 ret = 0;
6490 }
6491#else
bellard31e31b82003-02-18 22:55:36 +00006492 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006493#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006494 if ((ret == 0) && put_user_s64(res, arg4)) {
6495 goto efault;
6496 }
bellard31e31b82003-02-18 22:55:36 +00006497 }
6498 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006499#endif
bellard31e31b82003-02-18 22:55:36 +00006500 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006501#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006502 {
pbrook53a59602006-03-25 19:31:22 +00006503 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006504 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006505 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006506
6507 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006508 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006509 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006510 goto fail;
6511 }
ths3b46e622007-09-17 08:09:54 +00006512
bellard4add45b2003-06-05 01:52:59 +00006513 ret = get_errno(sys_getdents(arg1, dirp, count));
6514 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006515 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006516 struct target_dirent *tde;
6517 int len = ret;
6518 int reclen, treclen;
6519 int count1, tnamelen;
6520
6521 count1 = 0;
6522 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006523 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6524 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006525 tde = target_dirp;
6526 while (len > 0) {
6527 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006528 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006529 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006530 tde->d_ino = tswapal(de->d_ino);
6531 tde->d_off = tswapal(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006532 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006533 if (tnamelen > 256)
6534 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006535 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006536 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006537 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006538 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006539 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006540 count1 += treclen;
6541 }
6542 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006543 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006544 }
6545 free(dirp);
6546 }
6547#else
bellard31e31b82003-02-18 22:55:36 +00006548 {
aurel326556a832008-10-13 21:08:17 +00006549 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006550 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006551
bellard579a97f2007-11-11 14:26:47 +00006552 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6553 goto efault;
bellard72f03902003-02-18 23:33:18 +00006554 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006555 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006556 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006557 int len = ret;
6558 int reclen;
6559 de = dirp;
6560 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006561 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006562 if (reclen > len)
6563 break;
bellard8083a3e2003-03-24 23:12:16 +00006564 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006565 tswapls(&de->d_ino);
6566 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006567 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006568 len -= reclen;
6569 }
6570 }
pbrook53a59602006-03-25 19:31:22 +00006571 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006572 }
bellard4add45b2003-06-05 01:52:59 +00006573#endif
bellard31e31b82003-02-18 22:55:36 +00006574 break;
ths3ae43202007-09-16 21:39:48 +00006575#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006576 case TARGET_NR_getdents64:
6577 {
aurel326556a832008-10-13 21:08:17 +00006578 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006579 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006580 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6581 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006582 ret = get_errno(sys_getdents64(arg1, dirp, count));
6583 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006584 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006585 int len = ret;
6586 int reclen;
6587 de = dirp;
6588 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006589 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006590 if (reclen > len)
6591 break;
bellard8083a3e2003-03-24 23:12:16 +00006592 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006593 tswap64s((uint64_t *)&de->d_ino);
6594 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006595 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006596 len -= reclen;
6597 }
6598 }
pbrook53a59602006-03-25 19:31:22 +00006599 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006600 }
6601 break;
bellarda541f292004-04-12 20:39:29 +00006602#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006603#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
6604#ifdef TARGET_S390X
6605 case TARGET_NR_select:
6606#else
bellard31e31b82003-02-18 22:55:36 +00006607 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006608#endif
pbrook53a59602006-03-25 19:31:22 +00006609 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00006610 break;
thse5febef2007-04-01 18:31:35 +00006611#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05006612#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
6613# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00006614 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05006615# endif
6616# ifdef TARGET_NR_ppoll
6617 case TARGET_NR_ppoll:
6618# endif
bellard9de5e442003-03-23 16:49:39 +00006619 {
pbrook53a59602006-03-25 19:31:22 +00006620 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00006621 unsigned int nfds = arg2;
6622 int timeout = arg3;
6623 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00006624 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00006625
bellard579a97f2007-11-11 14:26:47 +00006626 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
6627 if (!target_pfd)
6628 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05006629
bellard9de5e442003-03-23 16:49:39 +00006630 pfd = alloca(sizeof(struct pollfd) * nfds);
6631 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006632 pfd[i].fd = tswap32(target_pfd[i].fd);
6633 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00006634 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05006635
6636# ifdef TARGET_NR_ppoll
6637 if (num == TARGET_NR_ppoll) {
6638 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
6639 target_sigset_t *target_set;
6640 sigset_t _set, *set = &_set;
6641
6642 if (arg3) {
6643 if (target_to_host_timespec(timeout_ts, arg3)) {
6644 unlock_user(target_pfd, arg1, 0);
6645 goto efault;
6646 }
6647 } else {
6648 timeout_ts = NULL;
6649 }
6650
6651 if (arg4) {
6652 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
6653 if (!target_set) {
6654 unlock_user(target_pfd, arg1, 0);
6655 goto efault;
6656 }
6657 target_to_host_sigset(set, target_set);
6658 } else {
6659 set = NULL;
6660 }
6661
6662 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
6663
6664 if (!is_error(ret) && arg3) {
6665 host_to_target_timespec(arg3, timeout_ts);
6666 }
6667 if (arg4) {
6668 unlock_user(target_set, arg4, 0);
6669 }
6670 } else
6671# endif
6672 ret = get_errno(poll(pfd, nfds, timeout));
6673
bellard9de5e442003-03-23 16:49:39 +00006674 if (!is_error(ret)) {
6675 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006676 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00006677 }
6678 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00006679 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00006680 }
6681 break;
thse5febef2007-04-01 18:31:35 +00006682#endif
bellard31e31b82003-02-18 22:55:36 +00006683 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00006684 /* NOTE: the flock constant seems to be the same for every
6685 Linux platform */
6686 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006687 break;
6688 case TARGET_NR_readv:
6689 {
6690 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006691 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006692
6693 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006694 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
6695 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006696 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006697 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00006698 }
6699 break;
6700 case TARGET_NR_writev:
6701 {
6702 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006703 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006704
6705 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006706 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
6707 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006708 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006709 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00006710 }
6711 break;
6712 case TARGET_NR_getsid:
6713 ret = get_errno(getsid(arg1));
6714 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006715#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00006716 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00006717 ret = get_errno(fdatasync(arg1));
6718 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006719#endif
bellard31e31b82003-02-18 22:55:36 +00006720 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00006721 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00006722 return value. */
ths0da46a62007-10-20 20:23:07 +00006723 ret = -TARGET_ENOTDIR;
6724 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05006725 case TARGET_NR_sched_getaffinity:
6726 {
6727 unsigned int mask_size;
6728 unsigned long *mask;
6729
6730 /*
6731 * sched_getaffinity needs multiples of ulong, so need to take
6732 * care of mismatches between target ulong and host ulong sizes.
6733 */
6734 if (arg2 & (sizeof(abi_ulong) - 1)) {
6735 ret = -TARGET_EINVAL;
6736 break;
6737 }
6738 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6739
6740 mask = alloca(mask_size);
6741 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
6742
6743 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09006744 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05006745 goto efault;
6746 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05006747 }
6748 }
6749 break;
6750 case TARGET_NR_sched_setaffinity:
6751 {
6752 unsigned int mask_size;
6753 unsigned long *mask;
6754
6755 /*
6756 * sched_setaffinity needs multiples of ulong, so need to take
6757 * care of mismatches between target ulong and host ulong sizes.
6758 */
6759 if (arg2 & (sizeof(abi_ulong) - 1)) {
6760 ret = -TARGET_EINVAL;
6761 break;
6762 }
6763 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6764
6765 mask = alloca(mask_size);
6766 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
6767 goto efault;
6768 }
6769 memcpy(mask, p, arg2);
6770 unlock_user_struct(p, arg2, 0);
6771
6772 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
6773 }
6774 break;
bellard31e31b82003-02-18 22:55:36 +00006775 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00006776 {
pbrook53a59602006-03-25 19:31:22 +00006777 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006778 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00006779
bellard579a97f2007-11-11 14:26:47 +00006780 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
6781 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006782 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006783 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00006784 ret = get_errno(sched_setparam(arg1, &schp));
6785 }
6786 break;
bellard31e31b82003-02-18 22:55:36 +00006787 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00006788 {
pbrook53a59602006-03-25 19:31:22 +00006789 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006790 struct sched_param schp;
6791 ret = get_errno(sched_getparam(arg1, &schp));
6792 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006793 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
6794 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006795 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006796 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00006797 }
6798 }
6799 break;
bellard31e31b82003-02-18 22:55:36 +00006800 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00006801 {
pbrook53a59602006-03-25 19:31:22 +00006802 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006803 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00006804 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
6805 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006806 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006807 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00006808 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
6809 }
6810 break;
bellard31e31b82003-02-18 22:55:36 +00006811 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00006812 ret = get_errno(sched_getscheduler(arg1));
6813 break;
bellard31e31b82003-02-18 22:55:36 +00006814 case TARGET_NR_sched_yield:
6815 ret = get_errno(sched_yield());
6816 break;
6817 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00006818 ret = get_errno(sched_get_priority_max(arg1));
6819 break;
bellard31e31b82003-02-18 22:55:36 +00006820 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00006821 ret = get_errno(sched_get_priority_min(arg1));
6822 break;
bellard31e31b82003-02-18 22:55:36 +00006823 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00006824 {
bellard5cd43932003-03-29 16:54:36 +00006825 struct timespec ts;
6826 ret = get_errno(sched_rr_get_interval(arg1, &ts));
6827 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006828 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00006829 }
6830 }
6831 break;
bellard31e31b82003-02-18 22:55:36 +00006832 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00006833 {
bellard1b6b0292003-03-22 17:31:38 +00006834 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00006835 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00006836 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00006837 if (is_error(ret) && arg2) {
6838 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00006839 }
6840 }
6841 break;
thse5febef2007-04-01 18:31:35 +00006842#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00006843 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00006844 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006845#endif
6846#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00006847 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00006848 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006849#endif
bellard31e31b82003-02-18 22:55:36 +00006850 case TARGET_NR_prctl:
thse5574482007-02-11 20:03:13 +00006851 switch (arg1)
6852 {
6853 case PR_GET_PDEATHSIG:
6854 {
6855 int deathsig;
6856 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
bellard2f619692007-11-16 10:46:05 +00006857 if (!is_error(ret) && arg2
6858 && put_user_ual(deathsig, arg2))
6859 goto efault;
thse5574482007-02-11 20:03:13 +00006860 }
6861 break;
6862 default:
6863 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
6864 break;
6865 }
ths39b9aae2007-02-11 18:36:44 +00006866 break;
bellardd2fd1af2007-11-14 18:08:56 +00006867#ifdef TARGET_NR_arch_prctl
6868 case TARGET_NR_arch_prctl:
6869#if defined(TARGET_I386) && !defined(TARGET_ABI32)
6870 ret = do_arch_prctl(cpu_env, arg1, arg2);
6871 break;
6872#else
6873 goto unimplemented;
6874#endif
6875#endif
bellard67867302003-11-23 17:05:30 +00006876#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00006877 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03006878 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006879 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006880 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6881 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006882 ret = get_errno(pread(arg1, p, arg3, arg4));
6883 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00006884 break;
bellard31e31b82003-02-18 22:55:36 +00006885 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03006886 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006887 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006888 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6889 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006890 ret = get_errno(pwrite(arg1, p, arg3, arg4));
6891 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00006892 break;
bellard67867302003-11-23 17:05:30 +00006893#endif
aurel32f2c7ba12008-03-28 22:32:06 +00006894#ifdef TARGET_NR_pread64
6895 case TARGET_NR_pread64:
6896 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6897 goto efault;
6898 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
6899 unlock_user(p, arg2, ret);
6900 break;
6901 case TARGET_NR_pwrite64:
6902 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6903 goto efault;
6904 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
6905 unlock_user(p, arg2, 0);
6906 break;
6907#endif
bellard31e31b82003-02-18 22:55:36 +00006908 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00006909 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
6910 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006911 ret = get_errno(sys_getcwd1(p, arg2));
6912 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00006913 break;
6914 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00006915 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006916 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00006917 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006918 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00006919#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02006920 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006921 defined(TARGET_M68K) || defined(TARGET_S390X)
bellard579a97f2007-11-11 14:26:47 +00006922 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00006923 break;
6924#else
bellard5cd43932003-03-29 16:54:36 +00006925 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00006926#endif
bellard31e31b82003-02-18 22:55:36 +00006927 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00006928 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006929#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00006930 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00006931 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006932#endif
6933#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00006934 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00006935 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006936#endif
bellard048f6b42005-11-26 18:47:20 +00006937#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00006938 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00006939 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
6940 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006941 break;
bellard048f6b42005-11-26 18:47:20 +00006942#endif
bellardebc05482003-09-30 21:08:41 +00006943#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00006944 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00006945 {
6946 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006947 int resource = target_to_host_resource(arg1);
6948 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00006949 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006950 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00006951 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6952 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006953 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6954 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006955 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00006956 }
6957 break;
6958 }
bellardebc05482003-09-30 21:08:41 +00006959#endif
bellarda315a142005-01-30 22:59:18 +00006960#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00006961 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00006962 if (!(p = lock_user_string(arg1)))
6963 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006964 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
6965 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00006966 break;
bellarda315a142005-01-30 22:59:18 +00006967#endif
6968#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00006969 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00006970 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00006971 break;
bellarda315a142005-01-30 22:59:18 +00006972#endif
6973#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00006974 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00006975 if (!(p = lock_user_string(arg1)))
6976 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006977 ret = get_errno(stat(path(p), &st));
6978 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006979 if (!is_error(ret))
6980 ret = host_to_target_stat64(cpu_env, arg2, &st);
6981 break;
bellarda315a142005-01-30 22:59:18 +00006982#endif
6983#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00006984 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00006985 if (!(p = lock_user_string(arg1)))
6986 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006987 ret = get_errno(lstat(path(p), &st));
6988 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006989 if (!is_error(ret))
6990 ret = host_to_target_stat64(cpu_env, arg2, &st);
6991 break;
bellarda315a142005-01-30 22:59:18 +00006992#endif
6993#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00006994 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00006995 ret = get_errno(fstat(arg1, &st));
6996 if (!is_error(ret))
6997 ret = host_to_target_stat64(cpu_env, arg2, &st);
6998 break;
bellardec86b0f2003-04-11 00:15:04 +00006999#endif
aurel329d33b762009-04-08 23:07:05 +00007000#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7001 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7002#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007003 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007004#endif
7005#ifdef TARGET_NR_newfstatat
7006 case TARGET_NR_newfstatat:
7007#endif
balrog6a24a772008-09-20 02:23:36 +00007008 if (!(p = lock_user_string(arg2)))
7009 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007010#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007011 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007012#else
7013 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7014#endif
balrog6a24a772008-09-20 02:23:36 +00007015 if (!is_error(ret))
7016 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007017 break;
bellarda315a142005-01-30 22:59:18 +00007018#endif
bellard67867302003-11-23 17:05:30 +00007019 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007020 if (!(p = lock_user_string(arg1)))
7021 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007022 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7023 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007024 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007025#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007026 case TARGET_NR_getuid:
7027 ret = get_errno(high2lowuid(getuid()));
7028 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007029#endif
7030#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007031 case TARGET_NR_getgid:
7032 ret = get_errno(high2lowgid(getgid()));
7033 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007034#endif
7035#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007036 case TARGET_NR_geteuid:
7037 ret = get_errno(high2lowuid(geteuid()));
7038 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007039#endif
7040#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007041 case TARGET_NR_getegid:
7042 ret = get_errno(high2lowgid(getegid()));
7043 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007044#endif
bellard67867302003-11-23 17:05:30 +00007045 case TARGET_NR_setreuid:
7046 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7047 break;
7048 case TARGET_NR_setregid:
7049 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7050 break;
7051 case TARGET_NR_getgroups:
7052 {
7053 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007054 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007055 gid_t *grouplist;
7056 int i;
7057
7058 grouplist = alloca(gidsetsize * sizeof(gid_t));
7059 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007060 if (gidsetsize == 0)
7061 break;
bellard67867302003-11-23 17:05:30 +00007062 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007063 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7064 if (!target_grouplist)
7065 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007066 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007067 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007068 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007069 }
7070 }
7071 break;
7072 case TARGET_NR_setgroups:
7073 {
7074 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007075 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007076 gid_t *grouplist;
7077 int i;
7078
7079 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007080 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7081 if (!target_grouplist) {
7082 ret = -TARGET_EFAULT;
7083 goto fail;
7084 }
bellard67867302003-11-23 17:05:30 +00007085 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007086 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007087 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007088 ret = get_errno(setgroups(gidsetsize, grouplist));
7089 }
7090 break;
7091 case TARGET_NR_fchown:
7092 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7093 break;
thsccfa72b2007-09-24 09:23:34 +00007094#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7095 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007096 if (!(p = lock_user_string(arg2)))
7097 goto efault;
7098 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7099 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007100 break;
7101#endif
bellard67867302003-11-23 17:05:30 +00007102#ifdef TARGET_NR_setresuid
7103 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007104 ret = get_errno(setresuid(low2highuid(arg1),
7105 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007106 low2highuid(arg3)));
7107 break;
7108#endif
7109#ifdef TARGET_NR_getresuid
7110 case TARGET_NR_getresuid:
7111 {
pbrook53a59602006-03-25 19:31:22 +00007112 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007113 ret = get_errno(getresuid(&ruid, &euid, &suid));
7114 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007115 if (put_user_u16(high2lowuid(ruid), arg1)
7116 || put_user_u16(high2lowuid(euid), arg2)
7117 || put_user_u16(high2lowuid(suid), arg3))
7118 goto efault;
bellard67867302003-11-23 17:05:30 +00007119 }
7120 }
7121 break;
7122#endif
7123#ifdef TARGET_NR_getresgid
7124 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007125 ret = get_errno(setresgid(low2highgid(arg1),
7126 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007127 low2highgid(arg3)));
7128 break;
7129#endif
7130#ifdef TARGET_NR_getresgid
7131 case TARGET_NR_getresgid:
7132 {
pbrook53a59602006-03-25 19:31:22 +00007133 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007134 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7135 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007136 if (put_user_u16(high2lowgid(rgid), arg1)
7137 || put_user_u16(high2lowgid(egid), arg2)
7138 || put_user_u16(high2lowgid(sgid), arg3))
7139 goto efault;
bellard67867302003-11-23 17:05:30 +00007140 }
7141 }
7142 break;
7143#endif
7144 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007145 if (!(p = lock_user_string(arg1)))
7146 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007147 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7148 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007149 break;
7150 case TARGET_NR_setuid:
7151 ret = get_errno(setuid(low2highuid(arg1)));
7152 break;
7153 case TARGET_NR_setgid:
7154 ret = get_errno(setgid(low2highgid(arg1)));
7155 break;
7156 case TARGET_NR_setfsuid:
7157 ret = get_errno(setfsuid(arg1));
7158 break;
7159 case TARGET_NR_setfsgid:
7160 ret = get_errno(setfsgid(arg1));
7161 break;
bellard67867302003-11-23 17:05:30 +00007162
bellarda315a142005-01-30 22:59:18 +00007163#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007164 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007165 if (!(p = lock_user_string(arg1)))
7166 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007167 ret = get_errno(lchown(p, arg2, arg3));
7168 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007169 break;
bellarda315a142005-01-30 22:59:18 +00007170#endif
7171#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007172 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007173 ret = get_errno(getuid());
7174 break;
bellarda315a142005-01-30 22:59:18 +00007175#endif
aurel3264b4d282008-11-14 17:20:15 +00007176
7177#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7178 /* Alpha specific */
7179 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007180 {
7181 uid_t euid;
7182 euid=geteuid();
7183 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7184 }
aurel3264b4d282008-11-14 17:20:15 +00007185 ret = get_errno(getuid());
7186 break;
7187#endif
7188#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7189 /* Alpha specific */
7190 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007191 {
7192 uid_t egid;
7193 egid=getegid();
7194 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7195 }
aurel3264b4d282008-11-14 17:20:15 +00007196 ret = get_errno(getgid());
7197 break;
7198#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007199#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7200 /* Alpha specific */
7201 case TARGET_NR_osf_getsysinfo:
7202 ret = -TARGET_EOPNOTSUPP;
7203 switch (arg1) {
7204 case TARGET_GSI_IEEE_FP_CONTROL:
7205 {
7206 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7207
7208 /* Copied from linux ieee_fpcr_to_swcr. */
7209 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7210 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7211 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7212 | SWCR_TRAP_ENABLE_DZE
7213 | SWCR_TRAP_ENABLE_OVF);
7214 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7215 | SWCR_TRAP_ENABLE_INE);
7216 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7217 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7218
7219 if (put_user_u64 (swcr, arg2))
7220 goto efault;
7221 ret = 0;
7222 }
7223 break;
7224
7225 /* case GSI_IEEE_STATE_AT_SIGNAL:
7226 -- Not implemented in linux kernel.
7227 case GSI_UACPROC:
7228 -- Retrieves current unaligned access state; not much used.
7229 case GSI_PROC_TYPE:
7230 -- Retrieves implver information; surely not used.
7231 case GSI_GET_HWRPB:
7232 -- Grabs a copy of the HWRPB; surely not used.
7233 */
7234 }
7235 break;
7236#endif
7237#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7238 /* Alpha specific */
7239 case TARGET_NR_osf_setsysinfo:
7240 ret = -TARGET_EOPNOTSUPP;
7241 switch (arg1) {
7242 case TARGET_SSI_IEEE_FP_CONTROL:
7243 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7244 {
7245 uint64_t swcr, fpcr, orig_fpcr;
7246
7247 if (get_user_u64 (swcr, arg2))
7248 goto efault;
7249 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7250 fpcr = orig_fpcr & FPCR_DYN_MASK;
7251
7252 /* Copied from linux ieee_swcr_to_fpcr. */
7253 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7254 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7255 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7256 | SWCR_TRAP_ENABLE_DZE
7257 | SWCR_TRAP_ENABLE_OVF)) << 48;
7258 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7259 | SWCR_TRAP_ENABLE_INE)) << 57;
7260 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7261 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7262
7263 cpu_alpha_store_fpcr (cpu_env, fpcr);
7264 ret = 0;
7265
7266 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7267 /* Old exceptions are not signaled. */
7268 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7269
7270 /* If any exceptions set by this call, and are unmasked,
7271 send a signal. */
7272 /* ??? FIXME */
7273 }
7274 }
7275 break;
7276
7277 /* case SSI_NVPAIRS:
7278 -- Used with SSIN_UACPROC to enable unaligned accesses.
7279 case SSI_IEEE_STATE_AT_SIGNAL:
7280 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7281 -- Not implemented in linux kernel
7282 */
7283 }
7284 break;
7285#endif
7286#ifdef TARGET_NR_osf_sigprocmask
7287 /* Alpha specific. */
7288 case TARGET_NR_osf_sigprocmask:
7289 {
7290 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007291 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007292 sigset_t set, oldset;
7293
7294 switch(arg1) {
7295 case TARGET_SIG_BLOCK:
7296 how = SIG_BLOCK;
7297 break;
7298 case TARGET_SIG_UNBLOCK:
7299 how = SIG_UNBLOCK;
7300 break;
7301 case TARGET_SIG_SETMASK:
7302 how = SIG_SETMASK;
7303 break;
7304 default:
7305 ret = -TARGET_EINVAL;
7306 goto fail;
7307 }
7308 mask = arg2;
7309 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007310 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007311 host_to_target_old_sigset(&mask, &oldset);
7312 ret = mask;
7313 }
7314 break;
7315#endif
aurel3264b4d282008-11-14 17:20:15 +00007316
bellarda315a142005-01-30 22:59:18 +00007317#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007318 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007319 ret = get_errno(getgid());
7320 break;
bellarda315a142005-01-30 22:59:18 +00007321#endif
7322#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007323 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007324 ret = get_errno(geteuid());
7325 break;
bellarda315a142005-01-30 22:59:18 +00007326#endif
7327#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007328 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007329 ret = get_errno(getegid());
7330 break;
bellarda315a142005-01-30 22:59:18 +00007331#endif
7332#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007333 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007334 ret = get_errno(setreuid(arg1, arg2));
7335 break;
bellarda315a142005-01-30 22:59:18 +00007336#endif
7337#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007338 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007339 ret = get_errno(setregid(arg1, arg2));
7340 break;
bellarda315a142005-01-30 22:59:18 +00007341#endif
7342#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007343 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007344 {
7345 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007346 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007347 gid_t *grouplist;
7348 int i;
7349
7350 grouplist = alloca(gidsetsize * sizeof(gid_t));
7351 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007352 if (gidsetsize == 0)
7353 break;
bellard99c475a2005-01-31 20:45:13 +00007354 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007355 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7356 if (!target_grouplist) {
7357 ret = -TARGET_EFAULT;
7358 goto fail;
7359 }
balroga2155fc2008-09-20 02:12:08 +00007360 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007361 target_grouplist[i] = tswap32(grouplist[i]);
7362 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007363 }
7364 }
7365 break;
bellarda315a142005-01-30 22:59:18 +00007366#endif
7367#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007368 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007369 {
7370 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007371 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007372 gid_t *grouplist;
7373 int i;
ths3b46e622007-09-17 08:09:54 +00007374
bellard99c475a2005-01-31 20:45:13 +00007375 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007376 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7377 if (!target_grouplist) {
7378 ret = -TARGET_EFAULT;
7379 goto fail;
7380 }
bellard99c475a2005-01-31 20:45:13 +00007381 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007382 grouplist[i] = tswap32(target_grouplist[i]);
7383 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007384 ret = get_errno(setgroups(gidsetsize, grouplist));
7385 }
7386 break;
bellarda315a142005-01-30 22:59:18 +00007387#endif
7388#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007389 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007390 ret = get_errno(fchown(arg1, arg2, arg3));
7391 break;
bellarda315a142005-01-30 22:59:18 +00007392#endif
7393#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007394 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007395 ret = get_errno(setresuid(arg1, arg2, arg3));
7396 break;
bellarda315a142005-01-30 22:59:18 +00007397#endif
7398#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007399 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007400 {
pbrook53a59602006-03-25 19:31:22 +00007401 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007402 ret = get_errno(getresuid(&ruid, &euid, &suid));
7403 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007404 if (put_user_u32(ruid, arg1)
7405 || put_user_u32(euid, arg2)
7406 || put_user_u32(suid, arg3))
7407 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007408 }
7409 }
7410 break;
bellarda315a142005-01-30 22:59:18 +00007411#endif
7412#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007413 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007414 ret = get_errno(setresgid(arg1, arg2, arg3));
7415 break;
bellarda315a142005-01-30 22:59:18 +00007416#endif
7417#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007418 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007419 {
pbrook53a59602006-03-25 19:31:22 +00007420 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007421 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7422 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007423 if (put_user_u32(rgid, arg1)
7424 || put_user_u32(egid, arg2)
7425 || put_user_u32(sgid, arg3))
7426 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007427 }
7428 }
7429 break;
bellarda315a142005-01-30 22:59:18 +00007430#endif
7431#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007432 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007433 if (!(p = lock_user_string(arg1)))
7434 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007435 ret = get_errno(chown(p, arg2, arg3));
7436 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007437 break;
bellarda315a142005-01-30 22:59:18 +00007438#endif
7439#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007440 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007441 ret = get_errno(setuid(arg1));
7442 break;
bellarda315a142005-01-30 22:59:18 +00007443#endif
7444#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007445 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007446 ret = get_errno(setgid(arg1));
7447 break;
bellarda315a142005-01-30 22:59:18 +00007448#endif
7449#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007450 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007451 ret = get_errno(setfsuid(arg1));
7452 break;
bellarda315a142005-01-30 22:59:18 +00007453#endif
7454#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007455 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007456 ret = get_errno(setfsgid(arg1));
7457 break;
bellarda315a142005-01-30 22:59:18 +00007458#endif
bellard67867302003-11-23 17:05:30 +00007459
bellard31e31b82003-02-18 22:55:36 +00007460 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007461 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007462#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007463 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007464 {
7465 void *a;
7466 ret = -TARGET_EFAULT;
7467 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7468 goto efault;
7469 if (!(p = lock_user_string(arg3)))
7470 goto mincore_fail;
7471 ret = get_errno(mincore(a, arg2, p));
7472 unlock_user(p, arg3, ret);
7473 mincore_fail:
7474 unlock_user(a, arg1, 0);
7475 }
7476 break;
bellardffa65c32004-01-04 23:57:22 +00007477#endif
aurel32408321b2008-10-01 21:46:32 +00007478#ifdef TARGET_NR_arm_fadvise64_64
7479 case TARGET_NR_arm_fadvise64_64:
7480 {
7481 /*
7482 * arm_fadvise64_64 looks like fadvise64_64 but
7483 * with different argument order
7484 */
7485 abi_long temp;
7486 temp = arg3;
7487 arg3 = arg4;
7488 arg4 = temp;
7489 }
7490#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007491#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007492#ifdef TARGET_NR_fadvise64_64
7493 case TARGET_NR_fadvise64_64:
7494#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007495#ifdef TARGET_NR_fadvise64
7496 case TARGET_NR_fadvise64:
7497#endif
7498#ifdef TARGET_S390X
7499 switch (arg4) {
7500 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7501 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7502 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7503 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7504 default: break;
7505 }
7506#endif
7507 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007508 break;
7509#endif
bellardffa65c32004-01-04 23:57:22 +00007510#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007511 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007512 /* A straight passthrough may not be safe because qemu sometimes
7513 turns private flie-backed mappings into anonymous mappings.
7514 This will break MADV_DONTNEED.
7515 This is a hint, so ignoring and returning success is ok. */
7516 ret = get_errno(0);
7517 break;
bellardffa65c32004-01-04 23:57:22 +00007518#endif
blueswir1992f48a2007-10-14 16:27:31 +00007519#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007520 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007521 {
thsb1e341e2007-03-20 21:50:52 +00007522 int cmd;
bellard77e46722003-04-29 20:39:06 +00007523 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007524 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007525#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007526 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007527#endif
bellard77e46722003-04-29 20:39:06 +00007528
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007529 cmd = target_to_host_fcntl_cmd(arg2);
7530 if (cmd == -TARGET_EINVAL)
7531 return cmd;
thsb1e341e2007-03-20 21:50:52 +00007532
bellard60cd49d2003-03-16 22:53:56 +00007533 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007534 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007535#ifdef TARGET_ARM
7536 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007537 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7538 goto efault;
ths58134272007-03-31 18:59:32 +00007539 fl.l_type = tswap16(target_efl->l_type);
7540 fl.l_whence = tswap16(target_efl->l_whence);
7541 fl.l_start = tswap64(target_efl->l_start);
7542 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007543 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007544 unlock_user_struct(target_efl, arg3, 0);
7545 } else
7546#endif
7547 {
bellard9ee1fa22007-11-11 15:11:19 +00007548 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7549 goto efault;
ths58134272007-03-31 18:59:32 +00007550 fl.l_type = tswap16(target_fl->l_type);
7551 fl.l_whence = tswap16(target_fl->l_whence);
7552 fl.l_start = tswap64(target_fl->l_start);
7553 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007554 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007555 unlock_user_struct(target_fl, arg3, 0);
7556 }
thsb1e341e2007-03-20 21:50:52 +00007557 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007558 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007559#ifdef TARGET_ARM
7560 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007561 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7562 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007563 target_efl->l_type = tswap16(fl.l_type);
7564 target_efl->l_whence = tswap16(fl.l_whence);
7565 target_efl->l_start = tswap64(fl.l_start);
7566 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007567 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007568 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007569 } else
7570#endif
7571 {
bellard9ee1fa22007-11-11 15:11:19 +00007572 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7573 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007574 target_fl->l_type = tswap16(fl.l_type);
7575 target_fl->l_whence = tswap16(fl.l_whence);
7576 target_fl->l_start = tswap64(fl.l_start);
7577 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007578 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007579 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007580 }
bellard77e46722003-04-29 20:39:06 +00007581 }
7582 break;
7583
thsb1e341e2007-03-20 21:50:52 +00007584 case TARGET_F_SETLK64:
7585 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00007586#ifdef TARGET_ARM
7587 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007588 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7589 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007590 fl.l_type = tswap16(target_efl->l_type);
7591 fl.l_whence = tswap16(target_efl->l_whence);
7592 fl.l_start = tswap64(target_efl->l_start);
7593 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007594 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007595 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007596 } else
7597#endif
7598 {
bellard9ee1fa22007-11-11 15:11:19 +00007599 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7600 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007601 fl.l_type = tswap16(target_fl->l_type);
7602 fl.l_whence = tswap16(target_fl->l_whence);
7603 fl.l_start = tswap64(target_fl->l_start);
7604 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007605 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007606 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007607 }
thsb1e341e2007-03-20 21:50:52 +00007608 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007609 break;
bellard60cd49d2003-03-16 22:53:56 +00007610 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007611 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00007612 break;
7613 }
bellard77e46722003-04-29 20:39:06 +00007614 break;
7615 }
bellard60cd49d2003-03-16 22:53:56 +00007616#endif
ths7d600c82006-12-08 01:32:58 +00007617#ifdef TARGET_NR_cacheflush
7618 case TARGET_NR_cacheflush:
7619 /* self-modifying code is handled automatically, so nothing needed */
7620 ret = 0;
7621 break;
7622#endif
bellardebc05482003-09-30 21:08:41 +00007623#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00007624 case TARGET_NR_security:
7625 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007626#endif
bellardc573ff62004-01-04 15:51:36 +00007627#ifdef TARGET_NR_getpagesize
7628 case TARGET_NR_getpagesize:
7629 ret = TARGET_PAGE_SIZE;
7630 break;
7631#endif
bellard31e31b82003-02-18 22:55:36 +00007632 case TARGET_NR_gettid:
7633 ret = get_errno(gettid());
7634 break;
thse5febef2007-04-01 18:31:35 +00007635#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00007636 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00007637#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03007638 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00007639 arg2 = arg3;
7640 arg3 = arg4;
7641 arg4 = arg5;
7642 }
aurel322054ac92008-10-13 21:08:07 +00007643 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
7644#else
7645 ret = get_errno(readahead(arg1, arg2, arg3));
7646#endif
7647 break;
thse5febef2007-04-01 18:31:35 +00007648#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007649#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00007650#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00007651 case TARGET_NR_lsetxattr:
7652 case TARGET_NR_fsetxattr:
bellard31e31b82003-02-18 22:55:36 +00007653 case TARGET_NR_lgetxattr:
7654 case TARGET_NR_fgetxattr:
7655 case TARGET_NR_listxattr:
7656 case TARGET_NR_llistxattr:
7657 case TARGET_NR_flistxattr:
bellard31e31b82003-02-18 22:55:36 +00007658 case TARGET_NR_lremovexattr:
7659 case TARGET_NR_fremovexattr:
Arnaud Patard6f932f92009-04-21 21:04:18 +03007660 ret = -TARGET_EOPNOTSUPP;
7661 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007662 case TARGET_NR_setxattr:
7663 {
7664 void *p, *n, *v;
7665 p = lock_user_string(arg1);
7666 n = lock_user_string(arg2);
7667 v = lock_user(VERIFY_READ, arg3, arg4, 1);
7668 if (p && n && v) {
7669 ret = get_errno(setxattr(p, n, v, arg4, arg5));
7670 } else {
7671 ret = -TARGET_EFAULT;
7672 }
7673 unlock_user(p, arg1, 0);
7674 unlock_user(n, arg2, 0);
7675 unlock_user(v, arg3, 0);
7676 }
7677 break;
7678 case TARGET_NR_getxattr:
7679 {
7680 void *p, *n, *v;
7681 p = lock_user_string(arg1);
7682 n = lock_user_string(arg2);
7683 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
7684 if (p && n && v) {
7685 ret = get_errno(getxattr(p, n, v, arg4));
7686 } else {
7687 ret = -TARGET_EFAULT;
7688 }
7689 unlock_user(p, arg1, 0);
7690 unlock_user(n, arg2, 0);
7691 unlock_user(v, arg3, arg4);
7692 }
7693 break;
7694 case TARGET_NR_removexattr:
7695 {
7696 void *p, *n;
7697 p = lock_user_string(arg1);
7698 n = lock_user_string(arg2);
7699 if (p && n) {
7700 ret = get_errno(removexattr(p, n));
7701 } else {
7702 ret = -TARGET_EFAULT;
7703 }
7704 unlock_user(p, arg1, 0);
7705 unlock_user(n, arg2, 0);
7706 }
7707 break;
bellardebc05482003-09-30 21:08:41 +00007708#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07007709#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00007710#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00007711 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007712#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00007713 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
7714 ret = 0;
7715 break;
edgar_iglef967792009-01-07 14:19:38 +00007716#elif defined(TARGET_CRIS)
7717 if (arg1 & 0xff)
7718 ret = -TARGET_EINVAL;
7719 else {
7720 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
7721 ret = 0;
7722 }
7723 break;
bellard8d18e892007-11-14 15:18:40 +00007724#elif defined(TARGET_I386) && defined(TARGET_ABI32)
7725 ret = do_set_thread_area(cpu_env, arg1);
7726 break;
ths6f5b89a2007-03-02 20:48:00 +00007727#else
7728 goto unimplemented_nowarn;
7729#endif
7730#endif
7731#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00007732 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007733#if defined(TARGET_I386) && defined(TARGET_ABI32)
7734 ret = do_get_thread_area(cpu_env, arg1);
7735#else
bellard5cd43932003-03-29 16:54:36 +00007736 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00007737#endif
bellard8d18e892007-11-14 15:18:40 +00007738#endif
bellard48dc41e2006-06-21 18:15:50 +00007739#ifdef TARGET_NR_getdomainname
7740 case TARGET_NR_getdomainname:
7741 goto unimplemented_nowarn;
7742#endif
ths6f5b89a2007-03-02 20:48:00 +00007743
thsb5906f92007-03-19 13:32:45 +00007744#ifdef TARGET_NR_clock_gettime
7745 case TARGET_NR_clock_gettime:
7746 {
7747 struct timespec ts;
7748 ret = get_errno(clock_gettime(arg1, &ts));
7749 if (!is_error(ret)) {
7750 host_to_target_timespec(arg2, &ts);
7751 }
7752 break;
7753 }
7754#endif
7755#ifdef TARGET_NR_clock_getres
7756 case TARGET_NR_clock_getres:
7757 {
7758 struct timespec ts;
7759 ret = get_errno(clock_getres(arg1, &ts));
7760 if (!is_error(ret)) {
7761 host_to_target_timespec(arg2, &ts);
7762 }
7763 break;
7764 }
7765#endif
pbrook63d76512008-05-29 13:43:29 +00007766#ifdef TARGET_NR_clock_nanosleep
7767 case TARGET_NR_clock_nanosleep:
7768 {
7769 struct timespec ts;
7770 target_to_host_timespec(&ts, arg3);
7771 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
7772 if (arg4)
7773 host_to_target_timespec(arg4, &ts);
7774 break;
7775 }
7776#endif
thsb5906f92007-03-19 13:32:45 +00007777
ths6f5b89a2007-03-02 20:48:00 +00007778#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
7779 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00007780 ret = get_errno(set_tid_address((int *)g2h(arg1)));
7781 break;
ths6f5b89a2007-03-02 20:48:00 +00007782#endif
7783
ths3ae43202007-09-16 21:39:48 +00007784#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00007785 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00007786 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00007787 break;
7788#endif
7789
ths3ae43202007-09-16 21:39:48 +00007790#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00007791 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00007792 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
7793 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00007794 break;
7795#endif
7796
ths4f2b1fe2007-06-21 21:57:12 +00007797#ifdef TARGET_NR_set_robust_list
7798 case TARGET_NR_set_robust_list:
7799 goto unimplemented_nowarn;
7800#endif
7801
ths9007f0e2007-09-25 17:50:37 +00007802#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
7803 case TARGET_NR_utimensat:
7804 {
Riku Voipioebc996f2009-04-21 15:01:51 +03007805 struct timespec *tsp, ts[2];
7806 if (!arg3) {
7807 tsp = NULL;
7808 } else {
7809 target_to_host_timespec(ts, arg3);
7810 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
7811 tsp = ts;
7812 }
ths9007f0e2007-09-25 17:50:37 +00007813 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03007814 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00007815 else {
bellard579a97f2007-11-11 14:26:47 +00007816 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00007817 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00007818 goto fail;
7819 }
Riku Voipioebc996f2009-04-21 15:01:51 +03007820 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00007821 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00007822 }
7823 }
7824 break;
7825#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02007826#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00007827 case TARGET_NR_futex:
7828 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
7829 break;
7830#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007831#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00007832 case TARGET_NR_inotify_init:
7833 ret = get_errno(sys_inotify_init());
7834 break;
7835#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007836#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00007837#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
7838 case TARGET_NR_inotify_init1:
7839 ret = get_errno(sys_inotify_init1(arg1));
7840 break;
7841#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007842#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007843#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00007844 case TARGET_NR_inotify_add_watch:
7845 p = lock_user_string(arg2);
7846 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
7847 unlock_user(p, arg2, 0);
7848 break;
7849#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007850#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00007851 case TARGET_NR_inotify_rm_watch:
7852 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
7853 break;
7854#endif
ths9007f0e2007-09-25 17:50:37 +00007855
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07007856#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00007857 case TARGET_NR_mq_open:
7858 {
7859 struct mq_attr posix_mq_attr;
7860
7861 p = lock_user_string(arg1 - 1);
7862 if (arg4 != 0)
7863 copy_from_user_mq_attr (&posix_mq_attr, arg4);
7864 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
7865 unlock_user (p, arg1, 0);
7866 }
7867 break;
7868
7869 case TARGET_NR_mq_unlink:
7870 p = lock_user_string(arg1 - 1);
7871 ret = get_errno(mq_unlink(p));
7872 unlock_user (p, arg1, 0);
7873 break;
7874
7875 case TARGET_NR_mq_timedsend:
7876 {
7877 struct timespec ts;
7878
7879 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7880 if (arg5 != 0) {
7881 target_to_host_timespec(&ts, arg5);
7882 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
7883 host_to_target_timespec(arg5, &ts);
7884 }
7885 else
7886 ret = get_errno(mq_send(arg1, p, arg3, arg4));
7887 unlock_user (p, arg2, arg3);
7888 }
7889 break;
7890
7891 case TARGET_NR_mq_timedreceive:
7892 {
7893 struct timespec ts;
7894 unsigned int prio;
7895
7896 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7897 if (arg5 != 0) {
7898 target_to_host_timespec(&ts, arg5);
7899 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
7900 host_to_target_timespec(arg5, &ts);
7901 }
7902 else
7903 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
7904 unlock_user (p, arg2, arg3);
7905 if (arg4 != 0)
7906 put_user_u32(prio, arg4);
7907 }
7908 break;
7909
7910 /* Not implemented for now... */
7911/* case TARGET_NR_mq_notify: */
7912/* break; */
7913
7914 case TARGET_NR_mq_getsetattr:
7915 {
7916 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
7917 ret = 0;
7918 if (arg3 != 0) {
7919 ret = mq_getattr(arg1, &posix_mq_attr_out);
7920 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
7921 }
7922 if (arg2 != 0) {
7923 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
7924 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
7925 }
7926
7927 }
7928 break;
7929#endif
7930
vibisreenivasan3ce34df2009-05-16 18:32:41 +05307931#ifdef CONFIG_SPLICE
7932#ifdef TARGET_NR_tee
7933 case TARGET_NR_tee:
7934 {
7935 ret = get_errno(tee(arg1,arg2,arg3,arg4));
7936 }
7937 break;
7938#endif
7939#ifdef TARGET_NR_splice
7940 case TARGET_NR_splice:
7941 {
7942 loff_t loff_in, loff_out;
7943 loff_t *ploff_in = NULL, *ploff_out = NULL;
7944 if(arg2) {
7945 get_user_u64(loff_in, arg2);
7946 ploff_in = &loff_in;
7947 }
7948 if(arg4) {
7949 get_user_u64(loff_out, arg2);
7950 ploff_out = &loff_out;
7951 }
7952 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
7953 }
7954 break;
7955#endif
7956#ifdef TARGET_NR_vmsplice
7957 case TARGET_NR_vmsplice:
7958 {
7959 int count = arg3;
7960 struct iovec *vec;
7961
7962 vec = alloca(count * sizeof(struct iovec));
7963 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7964 goto efault;
7965 ret = get_errno(vmsplice(arg1, vec, count, arg4));
7966 unlock_iovec(vec, arg2, count, 0);
7967 }
7968 break;
7969#endif
7970#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03007971#ifdef CONFIG_EVENTFD
7972#if defined(TARGET_NR_eventfd)
7973 case TARGET_NR_eventfd:
7974 ret = get_errno(eventfd(arg1, 0));
7975 break;
7976#endif
7977#if defined(TARGET_NR_eventfd2)
7978 case TARGET_NR_eventfd2:
7979 ret = get_errno(eventfd(arg1, arg2));
7980 break;
7981#endif
7982#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03007983#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
7984 case TARGET_NR_fallocate:
7985 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
7986 break;
7987#endif
Peter Maydellc727f472011-01-06 11:05:10 +00007988#if defined(CONFIG_SYNC_FILE_RANGE)
7989#if defined(TARGET_NR_sync_file_range)
7990 case TARGET_NR_sync_file_range:
7991#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03007992#if defined(TARGET_MIPS)
7993 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7994 target_offset64(arg5, arg6), arg7));
7995#else
Peter Maydellc727f472011-01-06 11:05:10 +00007996 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
7997 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03007998#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00007999#else
8000 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8001#endif
8002 break;
8003#endif
8004#if defined(TARGET_NR_sync_file_range2)
8005 case TARGET_NR_sync_file_range2:
8006 /* This is like sync_file_range but the arguments are reordered */
8007#if TARGET_ABI_BITS == 32
8008 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8009 target_offset64(arg5, arg6), arg2));
8010#else
8011 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8012#endif
8013 break;
8014#endif
8015#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008016#if defined(CONFIG_EPOLL)
8017#if defined(TARGET_NR_epoll_create)
8018 case TARGET_NR_epoll_create:
8019 ret = get_errno(epoll_create(arg1));
8020 break;
8021#endif
8022#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8023 case TARGET_NR_epoll_create1:
8024 ret = get_errno(epoll_create1(arg1));
8025 break;
8026#endif
8027#if defined(TARGET_NR_epoll_ctl)
8028 case TARGET_NR_epoll_ctl:
8029 {
8030 struct epoll_event ep;
8031 struct epoll_event *epp = 0;
8032 if (arg4) {
8033 struct target_epoll_event *target_ep;
8034 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8035 goto efault;
8036 }
8037 ep.events = tswap32(target_ep->events);
8038 /* The epoll_data_t union is just opaque data to the kernel,
8039 * so we transfer all 64 bits across and need not worry what
8040 * actual data type it is.
8041 */
8042 ep.data.u64 = tswap64(target_ep->data.u64);
8043 unlock_user_struct(target_ep, arg4, 0);
8044 epp = &ep;
8045 }
8046 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8047 break;
8048 }
8049#endif
8050
8051#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8052#define IMPLEMENT_EPOLL_PWAIT
8053#endif
8054#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8055#if defined(TARGET_NR_epoll_wait)
8056 case TARGET_NR_epoll_wait:
8057#endif
8058#if defined(IMPLEMENT_EPOLL_PWAIT)
8059 case TARGET_NR_epoll_pwait:
8060#endif
8061 {
8062 struct target_epoll_event *target_ep;
8063 struct epoll_event *ep;
8064 int epfd = arg1;
8065 int maxevents = arg3;
8066 int timeout = arg4;
8067
8068 target_ep = lock_user(VERIFY_WRITE, arg2,
8069 maxevents * sizeof(struct target_epoll_event), 1);
8070 if (!target_ep) {
8071 goto efault;
8072 }
8073
8074 ep = alloca(maxevents * sizeof(struct epoll_event));
8075
8076 switch (num) {
8077#if defined(IMPLEMENT_EPOLL_PWAIT)
8078 case TARGET_NR_epoll_pwait:
8079 {
8080 target_sigset_t *target_set;
8081 sigset_t _set, *set = &_set;
8082
8083 if (arg5) {
8084 target_set = lock_user(VERIFY_READ, arg5,
8085 sizeof(target_sigset_t), 1);
8086 if (!target_set) {
8087 unlock_user(target_ep, arg2, 0);
8088 goto efault;
8089 }
8090 target_to_host_sigset(set, target_set);
8091 unlock_user(target_set, arg5, 0);
8092 } else {
8093 set = NULL;
8094 }
8095
8096 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8097 break;
8098 }
8099#endif
8100#if defined(TARGET_NR_epoll_wait)
8101 case TARGET_NR_epoll_wait:
8102 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8103 break;
8104#endif
8105 default:
8106 ret = -TARGET_ENOSYS;
8107 }
8108 if (!is_error(ret)) {
8109 int i;
8110 for (i = 0; i < ret; i++) {
8111 target_ep[i].events = tswap32(ep[i].events);
8112 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8113 }
8114 }
8115 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8116 break;
8117 }
8118#endif
8119#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008120#ifdef TARGET_NR_prlimit64
8121 case TARGET_NR_prlimit64:
8122 {
8123 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8124 struct target_rlimit64 *target_rnew, *target_rold;
8125 struct host_rlimit64 rnew, rold, *rnewp = 0;
8126 if (arg3) {
8127 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8128 goto efault;
8129 }
8130 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8131 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8132 unlock_user_struct(target_rnew, arg3, 0);
8133 rnewp = &rnew;
8134 }
8135
8136 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8137 if (!is_error(ret) && arg4) {
8138 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8139 goto efault;
8140 }
8141 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8142 target_rold->rlim_max = tswap64(rold.rlim_max);
8143 unlock_user_struct(target_rold, arg4, 1);
8144 }
8145 break;
8146 }
8147#endif
bellard31e31b82003-02-18 22:55:36 +00008148 default:
8149 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008150 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008151#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 +00008152 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008153#endif
ths0da46a62007-10-20 20:23:07 +00008154 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008155 break;
8156 }
bellard579a97f2007-11-11 14:26:47 +00008157fail:
bellardc573ff62004-01-04 15:51:36 +00008158#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008159 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008160#endif
thsb92c47c2007-11-01 00:07:38 +00008161 if(do_strace)
8162 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008163 return ret;
bellard579a97f2007-11-11 14:26:47 +00008164efault:
8165 ret = -TARGET_EFAULT;
8166 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008167}