blob: fed7a8fe0f25d7957852f2d3cdc1906b5abd59fc [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
bellard31e31b82003-02-18 22:55:36 +000031#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000032#include <sys/ipc.h>
33#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/wait.h>
35#include <sys/time.h>
36#include <sys/stat.h>
37#include <sys/mount.h>
ths39b9aae2007-02-11 18:36:44 +000038#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/resource.h>
40#include <sys/mman.h>
41#include <sys/swap.h>
42#include <signal.h>
43#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020044#ifdef __ia64__
45int __clone2(int (*fn)(void *), void *child_stack_base,
46 size_t stack_size, int flags, void *arg, ...);
47#endif
bellard31e31b82003-02-18 22:55:36 +000048#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000049#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000050#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000051#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000052#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000053#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000054#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000055#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000056#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000057#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000058#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000059//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000060#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000061#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020062#include <linux/wireless.h>
aurel320b6d3ae2008-09-15 07:43:43 +000063#include <qemu-common.h>
Juan Quintela9788c9c2009-07-27 16:13:02 +020064#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000065#include <sys/gmon.h>
66#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030067#ifdef CONFIG_EVENTFD
68#include <sys/eventfd.h>
69#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000070#ifdef CONFIG_EPOLL
71#include <sys/epoll.h>
72#endif
bellard31e31b82003-02-18 22:55:36 +000073
74#define termios host_termios
75#define winsize host_winsize
76#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000077#define sgttyb host_sgttyb /* same as target */
78#define tchars host_tchars /* same as target */
79#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000080
81#include <linux/termios.h>
82#include <linux/unistd.h>
83#include <linux/utsname.h>
84#include <linux/cdrom.h>
85#include <linux/hdreg.h>
86#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000087#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000088#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030089#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000090#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000091#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000092#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020093#include <linux/fb.h>
94#include <linux/vt.h>
pbrookd7e40362008-05-23 16:06:43 +000095#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +010096#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +000097
bellard3ef693a2003-03-23 20:17:16 +000098#include "qemu.h"
balrog526ccb72008-07-16 12:13:52 +000099#include "qemu-common.h"
bellard31e31b82003-02-18 22:55:36 +0000100
Juan Quintela2f7bb872009-07-27 16:13:24 +0200101#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000102#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
103 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
104#else
105/* XXX: Hardcode the above values. */
106#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000107#endif
108
bellard72f03902003-02-18 23:33:18 +0000109//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000110
bellard1a9353d2003-03-16 20:28:50 +0000111//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000112#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
113#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000114
bellard70a194b2003-08-11 22:20:16 +0000115
bellard70a194b2003-08-11 22:20:16 +0000116#undef _syscall0
117#undef _syscall1
118#undef _syscall2
119#undef _syscall3
120#undef _syscall4
121#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000122#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000123
bellard83fcb512006-06-14 13:37:16 +0000124#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000125static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000126{ \
127 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000128}
129
bellard83fcb512006-06-14 13:37:16 +0000130#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000131static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000132{ \
133 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000134}
135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
155 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000156static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000157{ \
158 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000159}
bellard83fcb512006-06-14 13:37:16 +0000160
161
162#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
163 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000164static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
165 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
168}
169
bellard70a194b2003-08-11 22:20:16 +0000170
bellard31e31b82003-02-18 22:55:36 +0000171#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000172#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000173#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000174#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000175#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000176#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000177#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000178#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000179#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000180#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000181#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000182#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000183#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000184#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000185#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000186#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000187#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000189#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000190#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000191#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000192#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000193#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000194#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000195#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000196#define __NR_sys_inotify_init __NR_inotify_init
197#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
198#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000199
Alexander Graf42a39fb2011-04-15 17:32:45 +0200200#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
201 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000202#define __NR__llseek __NR_lseek
203#endif
204
bellard72f03902003-02-18 23:33:18 +0000205#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000206_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000207#else
ths0da46a62007-10-20 20:23:07 +0000208/* This is a replacement for the host gettid() and must return a host
209 errno. */
bellard72f03902003-02-18 23:33:18 +0000210static int gettid(void) {
211 return -ENOSYS;
212}
213#endif
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000215#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
216_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
217#endif
218_syscall2(int, sys_getpriority, int, which, int, who);
Richard Hendersond35b2612010-06-04 12:14:10 -0700219#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000220_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
221 loff_t *, res, uint, wh);
222#endif
223_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
224_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
225#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
226_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
227#endif
228#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
229_syscall2(int,sys_tkill,int,tid,int,sig)
230#endif
231#ifdef __NR_exit_group
232_syscall1(int,exit_group,int,error_code)
233#endif
234#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
235_syscall1(int,set_tid_address,int *,tidptr)
236#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200237#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000238#if defined(TARGET_NR_futex) && defined(__NR_futex)
239_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
240 const struct timespec *,timeout,int *,uaddr2,int,val3)
241#endif
242#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500243#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
244_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
245 unsigned long *, user_mask_ptr);
246#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
247_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
248 unsigned long *, user_mask_ptr);
aurel323b3f24a2009-04-15 16:12:13 +0000249
250static bitmask_transtbl fcntl_flags_tbl[] = {
251 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
252 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
253 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
254 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
255 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
256 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
257 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
258 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
259 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
260 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
261 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
262 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
263 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
264#if defined(O_DIRECT)
265 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
266#endif
267 { 0, 0, 0, 0 }
268};
269
270#define COPY_UTSNAME_FIELD(dest, src) \
271 do { \
272 /* __NEW_UTS_LEN doesn't include terminating null */ \
273 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
274 (dest)[__NEW_UTS_LEN] = '\0'; \
275 } while (0)
276
277static int sys_uname(struct new_utsname *buf)
278{
279 struct utsname uts_buf;
280
281 if (uname(&uts_buf) < 0)
282 return (-1);
283
284 /*
285 * Just in case these have some differences, we
286 * translate utsname to new_utsname (which is the
287 * struct linux kernel uses).
288 */
289
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200290 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000291 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
292 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
293 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
294 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
295 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
296#ifdef _GNU_SOURCE
297 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
298#endif
299 return (0);
300
301#undef COPY_UTSNAME_FIELD
302}
303
304static int sys_getcwd1(char *buf, size_t size)
305{
306 if (getcwd(buf, size) == NULL) {
307 /* getcwd() sets errno */
308 return (-1);
309 }
aurel32aaf4ad32009-04-16 14:17:14 +0000310 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000311}
312
313#ifdef CONFIG_ATFILE
314/*
315 * Host system seems to have atfile syscall stubs available. We
316 * now enable them one by one as specified by target syscall_nr.h.
317 */
318
319#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000320static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000321{
aurel32465c9f02009-04-19 08:52:17 +0000322 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000323}
324#endif
325#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000326static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000327{
aurel32465c9f02009-04-19 08:52:17 +0000328 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000329}
330#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300331#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000332static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
333 gid_t group, int flags)
334{
335 return (fchownat(dirfd, pathname, owner, group, flags));
336}
337#endif
338#ifdef __NR_fstatat64
339static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
340 int flags)
341{
342 return (fstatat(dirfd, pathname, buf, flags));
343}
344#endif
345#ifdef __NR_newfstatat
346static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
347 int flags)
348{
349 return (fstatat(dirfd, pathname, buf, flags));
350}
351#endif
352#ifdef TARGET_NR_futimesat
353static int sys_futimesat(int dirfd, const char *pathname,
354 const struct timeval times[2])
355{
356 return (futimesat(dirfd, pathname, times));
357}
358#endif
359#ifdef TARGET_NR_linkat
360static int sys_linkat(int olddirfd, const char *oldpath,
361 int newdirfd, const char *newpath, int flags)
362{
363 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
364}
365#endif
366#ifdef TARGET_NR_mkdirat
367static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
368{
369 return (mkdirat(dirfd, pathname, mode));
370}
371#endif
372#ifdef TARGET_NR_mknodat
373static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
374 dev_t dev)
375{
376 return (mknodat(dirfd, pathname, mode, dev));
377}
378#endif
379#ifdef TARGET_NR_openat
380static int sys_openat(int dirfd, const char *pathname, int flags, ...)
381{
382 /*
383 * open(2) has extra parameter 'mode' when called with
384 * flag O_CREAT.
385 */
386 if ((flags & O_CREAT) != 0) {
387 va_list ap;
388 mode_t mode;
389
390 /*
391 * Get the 'mode' parameter and translate it to
392 * host bits.
393 */
394 va_start(ap, flags);
395 mode = va_arg(ap, mode_t);
396 mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
397 va_end(ap);
398
399 return (openat(dirfd, pathname, flags, mode));
400 }
401 return (openat(dirfd, pathname, flags));
402}
403#endif
404#ifdef TARGET_NR_readlinkat
405static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
406{
407 return (readlinkat(dirfd, pathname, buf, bufsiz));
408}
409#endif
410#ifdef TARGET_NR_renameat
411static int sys_renameat(int olddirfd, const char *oldpath,
412 int newdirfd, const char *newpath)
413{
414 return (renameat(olddirfd, oldpath, newdirfd, newpath));
415}
416#endif
417#ifdef TARGET_NR_symlinkat
418static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
419{
420 return (symlinkat(oldpath, newdirfd, newpath));
421}
422#endif
423#ifdef TARGET_NR_unlinkat
424static int sys_unlinkat(int dirfd, const char *pathname, int flags)
425{
426 return (unlinkat(dirfd, pathname, flags));
427}
428#endif
aurel323b3f24a2009-04-15 16:12:13 +0000429#else /* !CONFIG_ATFILE */
430
431/*
432 * Try direct syscalls instead
433 */
ths92a34c12007-09-24 09:27:49 +0000434#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000435_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000436#endif
ths814d7972007-09-24 09:26:51 +0000437#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000438_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000439#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300440#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000441_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
442 uid_t,owner,gid_t,group,int,flags)
443#endif
aurel329d33b762009-04-08 23:07:05 +0000444#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
445 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000446_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
447 struct stat *,buf,int,flags)
448#endif
balrogac8a6552008-09-20 02:25:39 +0000449#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
450_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
451 const struct timeval *,times)
452#endif
aurel323b3f24a2009-04-15 16:12:13 +0000453#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
454 defined(__NR_newfstatat)
455_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
456 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000457#endif
ths64f0ce42007-09-24 09:25:06 +0000458#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
459_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000460 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000461#endif
ths4472ad02007-09-24 09:22:32 +0000462#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
463_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
464#endif
ths75ac37a2007-09-24 09:23:05 +0000465#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
466_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
467 mode_t,mode,dev_t,dev)
468#endif
ths82424832007-09-24 09:21:55 +0000469#if defined(TARGET_NR_openat) && defined(__NR_openat)
470_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
471#endif
ths5e0ccb12007-09-24 09:26:10 +0000472#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
473_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
474 char *,buf,size_t,bufsize)
475#endif
ths722183f2007-09-24 09:24:37 +0000476#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
477_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
478 int,newdirfd,const char *,newpath)
479#endif
thsb51eaa82007-09-25 16:09:22 +0000480#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000481_syscall3(int,sys_symlinkat,const char *,oldpath,
482 int,newdirfd,const char *,newpath)
483#endif
ths8170f562007-09-24 09:24:11 +0000484#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
485_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
486#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300487
488#endif /* CONFIG_ATFILE */
489
490#ifdef CONFIG_UTIMENSAT
491static int sys_utimensat(int dirfd, const char *pathname,
492 const struct timespec times[2], int flags)
493{
494 if (pathname == NULL)
495 return futimens(dirfd, times);
496 else
497 return utimensat(dirfd, pathname, times, flags);
498}
499#else
ths9007f0e2007-09-25 17:50:37 +0000500#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
501_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
502 const struct timespec *,tsp,int,flags)
503#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300504#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000505
506#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000507#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000508
aurel3239b59762008-10-01 21:46:50 +0000509#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000510static int sys_inotify_init(void)
511{
512 return (inotify_init());
513}
aurel3239b59762008-10-01 21:46:50 +0000514#endif
515#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000516static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
517{
518 return (inotify_add_watch(fd, pathname, mask));
519}
aurel3239b59762008-10-01 21:46:50 +0000520#endif
521#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000522static int sys_inotify_rm_watch(int fd, int32_t wd)
523{
aurel328690e422009-04-17 13:50:32 +0000524 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000525}
aurel3239b59762008-10-01 21:46:50 +0000526#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000527#ifdef CONFIG_INOTIFY1
528#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
529static int sys_inotify_init1(int flags)
530{
531 return (inotify_init1(flags));
532}
533#endif
534#endif
aurel323b3f24a2009-04-15 16:12:13 +0000535#else
536/* Userspace can usually survive runtime without inotify */
537#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000538#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000539#undef TARGET_NR_inotify_add_watch
540#undef TARGET_NR_inotify_rm_watch
541#endif /* CONFIG_INOTIFY */
542
Mike Frysingerd8035d42011-02-07 01:05:51 -0500543#if defined(TARGET_NR_ppoll)
544#ifndef __NR_ppoll
545# define __NR_ppoll -1
546#endif
547#define __NR_sys_ppoll __NR_ppoll
548_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
549 struct timespec *, timeout, const __sigset_t *, sigmask,
550 size_t, sigsetsize)
551#endif
bellard66fb9762003-03-23 01:06:05 +0000552
Mike Frysinger055e0902011-06-03 17:01:49 -0400553#if defined(TARGET_NR_pselect6)
554#ifndef __NR_pselect6
555# define __NR_pselect6 -1
556#endif
557#define __NR_sys_pselect6 __NR_pselect6
558_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
559 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
560#endif
561
bellard66fb9762003-03-23 01:06:05 +0000562extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000563extern int flock(int, int);
564extern int setfsuid(int);
565extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000566extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000567
thsb92c47c2007-11-01 00:07:38 +0000568#define ERRNO_TABLE_SIZE 1200
569
570/* target_to_host_errno_table[] is initialized from
571 * host_to_target_errno_table[] in syscall_init(). */
572static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
573};
574
ths637947f2007-06-01 12:09:19 +0000575/*
thsfe8f0962007-07-12 10:59:21 +0000576 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000577 * minus the errnos that are not actually generic to all archs.
578 */
thsb92c47c2007-11-01 00:07:38 +0000579static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000580 [EIDRM] = TARGET_EIDRM,
581 [ECHRNG] = TARGET_ECHRNG,
582 [EL2NSYNC] = TARGET_EL2NSYNC,
583 [EL3HLT] = TARGET_EL3HLT,
584 [EL3RST] = TARGET_EL3RST,
585 [ELNRNG] = TARGET_ELNRNG,
586 [EUNATCH] = TARGET_EUNATCH,
587 [ENOCSI] = TARGET_ENOCSI,
588 [EL2HLT] = TARGET_EL2HLT,
589 [EDEADLK] = TARGET_EDEADLK,
590 [ENOLCK] = TARGET_ENOLCK,
591 [EBADE] = TARGET_EBADE,
592 [EBADR] = TARGET_EBADR,
593 [EXFULL] = TARGET_EXFULL,
594 [ENOANO] = TARGET_ENOANO,
595 [EBADRQC] = TARGET_EBADRQC,
596 [EBADSLT] = TARGET_EBADSLT,
597 [EBFONT] = TARGET_EBFONT,
598 [ENOSTR] = TARGET_ENOSTR,
599 [ENODATA] = TARGET_ENODATA,
600 [ETIME] = TARGET_ETIME,
601 [ENOSR] = TARGET_ENOSR,
602 [ENONET] = TARGET_ENONET,
603 [ENOPKG] = TARGET_ENOPKG,
604 [EREMOTE] = TARGET_EREMOTE,
605 [ENOLINK] = TARGET_ENOLINK,
606 [EADV] = TARGET_EADV,
607 [ESRMNT] = TARGET_ESRMNT,
608 [ECOMM] = TARGET_ECOMM,
609 [EPROTO] = TARGET_EPROTO,
610 [EDOTDOT] = TARGET_EDOTDOT,
611 [EMULTIHOP] = TARGET_EMULTIHOP,
612 [EBADMSG] = TARGET_EBADMSG,
613 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
614 [EOVERFLOW] = TARGET_EOVERFLOW,
615 [ENOTUNIQ] = TARGET_ENOTUNIQ,
616 [EBADFD] = TARGET_EBADFD,
617 [EREMCHG] = TARGET_EREMCHG,
618 [ELIBACC] = TARGET_ELIBACC,
619 [ELIBBAD] = TARGET_ELIBBAD,
620 [ELIBSCN] = TARGET_ELIBSCN,
621 [ELIBMAX] = TARGET_ELIBMAX,
622 [ELIBEXEC] = TARGET_ELIBEXEC,
623 [EILSEQ] = TARGET_EILSEQ,
624 [ENOSYS] = TARGET_ENOSYS,
625 [ELOOP] = TARGET_ELOOP,
626 [ERESTART] = TARGET_ERESTART,
627 [ESTRPIPE] = TARGET_ESTRPIPE,
628 [ENOTEMPTY] = TARGET_ENOTEMPTY,
629 [EUSERS] = TARGET_EUSERS,
630 [ENOTSOCK] = TARGET_ENOTSOCK,
631 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
632 [EMSGSIZE] = TARGET_EMSGSIZE,
633 [EPROTOTYPE] = TARGET_EPROTOTYPE,
634 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
635 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
636 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
637 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
638 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
639 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
640 [EADDRINUSE] = TARGET_EADDRINUSE,
641 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
642 [ENETDOWN] = TARGET_ENETDOWN,
643 [ENETUNREACH] = TARGET_ENETUNREACH,
644 [ENETRESET] = TARGET_ENETRESET,
645 [ECONNABORTED] = TARGET_ECONNABORTED,
646 [ECONNRESET] = TARGET_ECONNRESET,
647 [ENOBUFS] = TARGET_ENOBUFS,
648 [EISCONN] = TARGET_EISCONN,
649 [ENOTCONN] = TARGET_ENOTCONN,
650 [EUCLEAN] = TARGET_EUCLEAN,
651 [ENOTNAM] = TARGET_ENOTNAM,
652 [ENAVAIL] = TARGET_ENAVAIL,
653 [EISNAM] = TARGET_EISNAM,
654 [EREMOTEIO] = TARGET_EREMOTEIO,
655 [ESHUTDOWN] = TARGET_ESHUTDOWN,
656 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
657 [ETIMEDOUT] = TARGET_ETIMEDOUT,
658 [ECONNREFUSED] = TARGET_ECONNREFUSED,
659 [EHOSTDOWN] = TARGET_EHOSTDOWN,
660 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
661 [EALREADY] = TARGET_EALREADY,
662 [EINPROGRESS] = TARGET_EINPROGRESS,
663 [ESTALE] = TARGET_ESTALE,
664 [ECANCELED] = TARGET_ECANCELED,
665 [ENOMEDIUM] = TARGET_ENOMEDIUM,
666 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000667#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000668 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000669#endif
670#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000671 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000672#endif
673#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000674 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000675#endif
676#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000677 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000678#endif
679#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000680 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000681#endif
682#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000683 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000684#endif
thsb92c47c2007-11-01 00:07:38 +0000685};
ths637947f2007-06-01 12:09:19 +0000686
687static inline int host_to_target_errno(int err)
688{
689 if(host_to_target_errno_table[err])
690 return host_to_target_errno_table[err];
691 return err;
692}
693
thsb92c47c2007-11-01 00:07:38 +0000694static inline int target_to_host_errno(int err)
695{
696 if (target_to_host_errno_table[err])
697 return target_to_host_errno_table[err];
698 return err;
699}
700
blueswir1992f48a2007-10-14 16:27:31 +0000701static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000702{
703 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000704 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000705 else
706 return ret;
707}
708
blueswir1992f48a2007-10-14 16:27:31 +0000709static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000710{
blueswir1992f48a2007-10-14 16:27:31 +0000711 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000712}
713
thsb92c47c2007-11-01 00:07:38 +0000714char *target_strerror(int err)
715{
716 return strerror(target_to_host_errno(err));
717}
718
blueswir1992f48a2007-10-14 16:27:31 +0000719static abi_ulong target_brk;
720static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000721static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000722
blueswir1992f48a2007-10-14 16:27:31 +0000723void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000724{
blueswir14c1de732007-07-07 20:45:44 +0000725 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000726 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000727}
728
vincent4d1de872011-06-14 21:56:33 +0000729//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
730#define DEBUGF_BRK(message, args...)
731
ths0da46a62007-10-20 20:23:07 +0000732/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000733abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000734{
blueswir1992f48a2007-10-14 16:27:31 +0000735 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000736 int new_alloc_size;
737
vincent4d1de872011-06-14 21:56:33 +0000738 DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000739
vincent4d1de872011-06-14 21:56:33 +0000740 if (!new_brk) {
741 DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
742 return target_brk;
743 }
744 if (new_brk < target_original_brk) {
745 DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
746 return target_brk;
747 }
bellard31e31b82003-02-18 22:55:36 +0000748
vincent4d1de872011-06-14 21:56:33 +0000749 /* If the new brk is less than the highest page reserved to the
750 * target heap allocation, set it and we're almost done... */
751 if (new_brk <= brk_page) {
752 /* Heap contents are initialized to zero, as for anonymous
753 * mapped pages. */
754 if (new_brk > target_brk) {
755 memset(g2h(target_brk), 0, new_brk - target_brk);
756 }
bellard31e31b82003-02-18 22:55:36 +0000757 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000758 DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000759 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000760 }
761
Peter Maydell00faf082011-04-18 16:34:24 +0100762 /* We need to allocate more memory after the brk... Note that
763 * we don't use MAP_FIXED because that will map over the top of
764 * any existing mapping (like the one with the host libc or qemu
765 * itself); instead we treat "mapped but at wrong address" as
766 * a failure and unmap again.
767 */
vincent4d1de872011-06-14 21:56:33 +0000768 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000769 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000770 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100771 MAP_ANON|MAP_PRIVATE, 0, 0));
772
773 if (mapped_addr == brk_page) {
774 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000775 brk_page = HOST_PAGE_ALIGN(target_brk);
776 DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100777 return target_brk;
778 } else if (mapped_addr != -1) {
779 /* Mapped but at wrong address, meaning there wasn't actually
780 * enough space for this brk.
781 */
782 target_munmap(mapped_addr, new_alloc_size);
783 mapped_addr = -1;
vincent4d1de872011-06-14 21:56:33 +0000784 DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
785 }
786 else {
787 DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100788 }
balrog7ab240a2008-04-26 12:17:34 +0000789
Richard Henderson7dd46c02010-05-03 10:07:49 -0700790#if defined(TARGET_ALPHA)
791 /* We (partially) emulate OSF/1 on Alpha, which requires we
792 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100793 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700794#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100795 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000796 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000797}
798
ths26edcf42007-12-09 02:25:24 +0000799static inline abi_long copy_from_user_fdset(fd_set *fds,
800 abi_ulong target_fds_addr,
801 int n)
bellard31e31b82003-02-18 22:55:36 +0000802{
ths26edcf42007-12-09 02:25:24 +0000803 int i, nw, j, k;
804 abi_ulong b, *target_fds;
805
806 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
807 if (!(target_fds = lock_user(VERIFY_READ,
808 target_fds_addr,
809 sizeof(abi_ulong) * nw,
810 1)))
811 return -TARGET_EFAULT;
812
813 FD_ZERO(fds);
814 k = 0;
815 for (i = 0; i < nw; i++) {
816 /* grab the abi_ulong */
817 __get_user(b, &target_fds[i]);
818 for (j = 0; j < TARGET_ABI_BITS; j++) {
819 /* check the bit inside the abi_ulong */
820 if ((b >> j) & 1)
821 FD_SET(k, fds);
822 k++;
bellard31e31b82003-02-18 22:55:36 +0000823 }
bellard31e31b82003-02-18 22:55:36 +0000824 }
ths26edcf42007-12-09 02:25:24 +0000825
826 unlock_user(target_fds, target_fds_addr, 0);
827
828 return 0;
bellard31e31b82003-02-18 22:55:36 +0000829}
830
Mike Frysinger055e0902011-06-03 17:01:49 -0400831static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
832 abi_ulong target_fds_addr,
833 int n)
834{
835 if (target_fds_addr) {
836 if (copy_from_user_fdset(fds, target_fds_addr, n))
837 return -TARGET_EFAULT;
838 *fds_ptr = fds;
839 } else {
840 *fds_ptr = NULL;
841 }
842 return 0;
843}
844
ths26edcf42007-12-09 02:25:24 +0000845static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
846 const fd_set *fds,
847 int n)
bellard31e31b82003-02-18 22:55:36 +0000848{
bellard31e31b82003-02-18 22:55:36 +0000849 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000850 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000851 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000852
ths26edcf42007-12-09 02:25:24 +0000853 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
854 if (!(target_fds = lock_user(VERIFY_WRITE,
855 target_fds_addr,
856 sizeof(abi_ulong) * nw,
857 0)))
858 return -TARGET_EFAULT;
859
860 k = 0;
861 for (i = 0; i < nw; i++) {
862 v = 0;
863 for (j = 0; j < TARGET_ABI_BITS; j++) {
864 v |= ((FD_ISSET(k, fds) != 0) << j);
865 k++;
bellard31e31b82003-02-18 22:55:36 +0000866 }
ths26edcf42007-12-09 02:25:24 +0000867 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000868 }
ths26edcf42007-12-09 02:25:24 +0000869
870 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
871
872 return 0;
bellard31e31b82003-02-18 22:55:36 +0000873}
874
bellardc596ed12003-07-13 17:32:31 +0000875#if defined(__alpha__)
876#define HOST_HZ 1024
877#else
878#define HOST_HZ 100
879#endif
880
blueswir1992f48a2007-10-14 16:27:31 +0000881static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000882{
883#if HOST_HZ == TARGET_HZ
884 return ticks;
885#else
886 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
887#endif
888}
889
bellard579a97f2007-11-11 14:26:47 +0000890static inline abi_long host_to_target_rusage(abi_ulong target_addr,
891 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000892{
pbrook53a59602006-03-25 19:31:22 +0000893 struct target_rusage *target_rusage;
894
bellard579a97f2007-11-11 14:26:47 +0000895 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
896 return -TARGET_EFAULT;
bellardb4091862003-05-16 15:39:34 +0000897 target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
898 target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
899 target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
900 target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
901 target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
902 target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
903 target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
904 target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
905 target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
906 target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
907 target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
908 target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
909 target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
910 target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
911 target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
912 target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
913 target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
914 target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000915 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000916
917 return 0;
bellardb4091862003-05-16 15:39:34 +0000918}
919
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900920static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
921{
922 if (target_rlim == TARGET_RLIM_INFINITY)
923 return RLIM_INFINITY;
924 else
925 return tswapl(target_rlim);
926}
927
928static inline target_ulong host_to_target_rlim(rlim_t rlim)
929{
930 if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
931 return TARGET_RLIM_INFINITY;
932 else
933 return tswapl(rlim);
934}
935
ths788f5ec2007-12-09 02:37:05 +0000936static inline abi_long copy_from_user_timeval(struct timeval *tv,
937 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000938{
pbrook53a59602006-03-25 19:31:22 +0000939 struct target_timeval *target_tv;
940
ths788f5ec2007-12-09 02:37:05 +0000941 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000942 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000943
944 __get_user(tv->tv_sec, &target_tv->tv_sec);
945 __get_user(tv->tv_usec, &target_tv->tv_usec);
946
947 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000948
949 return 0;
bellard31e31b82003-02-18 22:55:36 +0000950}
951
ths788f5ec2007-12-09 02:37:05 +0000952static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
953 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000954{
pbrook53a59602006-03-25 19:31:22 +0000955 struct target_timeval *target_tv;
956
ths788f5ec2007-12-09 02:37:05 +0000957 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000958 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000959
960 __put_user(tv->tv_sec, &target_tv->tv_sec);
961 __put_user(tv->tv_usec, &target_tv->tv_usec);
962
963 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000964
965 return 0;
bellard31e31b82003-02-18 22:55:36 +0000966}
967
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700968#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
969#include <mqueue.h>
970
aurel3224e10032009-04-15 16:11:43 +0000971static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
972 abi_ulong target_mq_attr_addr)
973{
974 struct target_mq_attr *target_mq_attr;
975
976 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
977 target_mq_attr_addr, 1))
978 return -TARGET_EFAULT;
979
980 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
981 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
982 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
983 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
984
985 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
986
987 return 0;
988}
989
990static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
991 const struct mq_attr *attr)
992{
993 struct target_mq_attr *target_mq_attr;
994
995 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
996 target_mq_attr_addr, 0))
997 return -TARGET_EFAULT;
998
999 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1000 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1001 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1002 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1003
1004 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1005
1006 return 0;
1007}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001008#endif
bellard31e31b82003-02-18 22:55:36 +00001009
Mike Frysinger055e0902011-06-03 17:01:49 -04001010#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001011/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001012static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001013 abi_ulong rfd_addr, abi_ulong wfd_addr,
1014 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001015{
1016 fd_set rfds, wfds, efds;
1017 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1018 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001019 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001020
Mike Frysinger055e0902011-06-03 17:01:49 -04001021 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1022 if (ret) {
1023 return ret;
pbrook53a59602006-03-25 19:31:22 +00001024 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001025 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1026 if (ret) {
1027 return ret;
pbrook53a59602006-03-25 19:31:22 +00001028 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001029 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1030 if (ret) {
1031 return ret;
pbrook53a59602006-03-25 19:31:22 +00001032 }
ths3b46e622007-09-17 08:09:54 +00001033
ths26edcf42007-12-09 02:25:24 +00001034 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001035 if (copy_from_user_timeval(&tv, target_tv_addr))
1036 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001037 tv_ptr = &tv;
1038 } else {
1039 tv_ptr = NULL;
1040 }
ths26edcf42007-12-09 02:25:24 +00001041
bellard31e31b82003-02-18 22:55:36 +00001042 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001043
ths26edcf42007-12-09 02:25:24 +00001044 if (!is_error(ret)) {
1045 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1046 return -TARGET_EFAULT;
1047 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1048 return -TARGET_EFAULT;
1049 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1050 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001051
ths788f5ec2007-12-09 02:37:05 +00001052 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1053 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001054 }
bellard579a97f2007-11-11 14:26:47 +00001055
bellard31e31b82003-02-18 22:55:36 +00001056 return ret;
1057}
Mike Frysinger055e0902011-06-03 17:01:49 -04001058#endif
bellard31e31b82003-02-18 22:55:36 +00001059
Riku Voipio099d6b02009-05-05 12:10:04 +03001060static abi_long do_pipe2(int host_pipe[], int flags)
1061{
1062#ifdef CONFIG_PIPE2
1063 return pipe2(host_pipe, flags);
1064#else
1065 return -ENOSYS;
1066#endif
1067}
1068
Richard Hendersonfb41a662010-05-03 10:07:52 -07001069static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1070 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001071{
1072 int host_pipe[2];
1073 abi_long ret;
1074 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1075
1076 if (is_error(ret))
1077 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001078
1079 /* Several targets have special calling conventions for the original
1080 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1081 if (!is_pipe2) {
1082#if defined(TARGET_ALPHA)
1083 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1084 return host_pipe[0];
1085#elif defined(TARGET_MIPS)
1086 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1087 return host_pipe[0];
1088#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001089 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001090 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001091#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001092 }
1093
Riku Voipio099d6b02009-05-05 12:10:04 +03001094 if (put_user_s32(host_pipe[0], pipedes)
1095 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1096 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001097 return get_errno(ret);
1098}
1099
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001100static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1101 abi_ulong target_addr,
1102 socklen_t len)
1103{
1104 struct target_ip_mreqn *target_smreqn;
1105
1106 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1107 if (!target_smreqn)
1108 return -TARGET_EFAULT;
1109 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1110 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1111 if (len == sizeof(struct target_ip_mreqn))
1112 mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
1113 unlock_user(target_smreqn, target_addr, 0);
1114
1115 return 0;
1116}
1117
bellard579a97f2007-11-11 14:26:47 +00001118static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1119 abi_ulong target_addr,
1120 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001121{
aurel32607175e2009-04-15 16:11:59 +00001122 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1123 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001124 struct target_sockaddr *target_saddr;
1125
bellard579a97f2007-11-11 14:26:47 +00001126 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1127 if (!target_saddr)
1128 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001129
1130 sa_family = tswap16(target_saddr->sa_family);
1131
1132 /* Oops. The caller might send a incomplete sun_path; sun_path
1133 * must be terminated by \0 (see the manual page), but
1134 * unfortunately it is quite common to specify sockaddr_un
1135 * length as "strlen(x->sun_path)" while it should be
1136 * "strlen(...) + 1". We'll fix that here if needed.
1137 * Linux kernel has a similar feature.
1138 */
1139
1140 if (sa_family == AF_UNIX) {
1141 if (len < unix_maxlen && len > 0) {
1142 char *cp = (char*)target_saddr;
1143
1144 if ( cp[len-1] && !cp[len] )
1145 len++;
1146 }
1147 if (len > unix_maxlen)
1148 len = unix_maxlen;
1149 }
1150
pbrook53a59602006-03-25 19:31:22 +00001151 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001152 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001153 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001154
1155 return 0;
bellard7854b052003-03-29 17:22:23 +00001156}
1157
bellard579a97f2007-11-11 14:26:47 +00001158static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1159 struct sockaddr *addr,
1160 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001161{
pbrook53a59602006-03-25 19:31:22 +00001162 struct target_sockaddr *target_saddr;
1163
bellard579a97f2007-11-11 14:26:47 +00001164 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1165 if (!target_saddr)
1166 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001167 memcpy(target_saddr, addr, len);
1168 target_saddr->sa_family = tswap16(addr->sa_family);
1169 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001170
1171 return 0;
bellard7854b052003-03-29 17:22:23 +00001172}
1173
pbrook53a59602006-03-25 19:31:22 +00001174/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001175static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1176 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001177{
1178 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001179 abi_long msg_controllen;
1180 abi_ulong target_cmsg_addr;
1181 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001182 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001183
1184 msg_controllen = tswapl(target_msgh->msg_controllen);
1185 if (msg_controllen < sizeof (struct target_cmsghdr))
1186 goto the_end;
1187 target_cmsg_addr = tswapl(target_msgh->msg_control);
1188 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1189 if (!target_cmsg)
1190 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001191
1192 while (cmsg && target_cmsg) {
1193 void *data = CMSG_DATA(cmsg);
1194 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1195
ths5fafdf22007-09-16 21:08:06 +00001196 int len = tswapl(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001197 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1198
1199 space += CMSG_SPACE(len);
1200 if (space > msgh->msg_controllen) {
1201 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001202 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001203 break;
1204 }
1205
1206 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1207 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1208 cmsg->cmsg_len = CMSG_LEN(len);
1209
bellard3532fa72006-06-24 15:06:03 +00001210 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001211 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1212 memcpy(data, target_data, len);
1213 } else {
1214 int *fd = (int *)data;
1215 int *target_fd = (int *)target_data;
1216 int i, numfds = len / sizeof(int);
1217
1218 for (i = 0; i < numfds; i++)
1219 fd[i] = tswap32(target_fd[i]);
1220 }
1221
1222 cmsg = CMSG_NXTHDR(msgh, cmsg);
1223 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1224 }
bellard5a4a8982007-11-11 17:39:18 +00001225 unlock_user(target_cmsg, target_cmsg_addr, 0);
1226 the_end:
bellard7854b052003-03-29 17:22:23 +00001227 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001228 return 0;
bellard7854b052003-03-29 17:22:23 +00001229}
1230
pbrook53a59602006-03-25 19:31:22 +00001231/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001232static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1233 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001234{
1235 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001236 abi_long msg_controllen;
1237 abi_ulong target_cmsg_addr;
1238 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001239 socklen_t space = 0;
1240
bellard5a4a8982007-11-11 17:39:18 +00001241 msg_controllen = tswapl(target_msgh->msg_controllen);
1242 if (msg_controllen < sizeof (struct target_cmsghdr))
1243 goto the_end;
1244 target_cmsg_addr = tswapl(target_msgh->msg_control);
1245 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1246 if (!target_cmsg)
1247 return -TARGET_EFAULT;
1248
bellard7854b052003-03-29 17:22:23 +00001249 while (cmsg && target_cmsg) {
1250 void *data = CMSG_DATA(cmsg);
1251 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1252
1253 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1254
1255 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001256 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001257 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001258 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001259 break;
1260 }
1261
1262 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1263 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
1264 target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
1265
bellard3532fa72006-06-24 15:06:03 +00001266 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001267 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1268 memcpy(target_data, data, len);
1269 } else {
1270 int *fd = (int *)data;
1271 int *target_fd = (int *)target_data;
1272 int i, numfds = len / sizeof(int);
1273
1274 for (i = 0; i < numfds; i++)
1275 target_fd[i] = tswap32(fd[i]);
1276 }
1277
1278 cmsg = CMSG_NXTHDR(msgh, cmsg);
1279 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1280 }
bellard5a4a8982007-11-11 17:39:18 +00001281 unlock_user(target_cmsg, target_cmsg_addr, space);
1282 the_end:
1283 target_msgh->msg_controllen = tswapl(space);
1284 return 0;
bellard7854b052003-03-29 17:22:23 +00001285}
1286
ths0da46a62007-10-20 20:23:07 +00001287/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001288static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001289 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001290{
blueswir1992f48a2007-10-14 16:27:31 +00001291 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001292 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001293 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001294 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001295
bellard8853f862004-02-22 14:57:26 +00001296 switch(level) {
1297 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001298 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001299 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001300 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001301
bellard2f619692007-11-16 10:46:05 +00001302 if (get_user_u32(val, optval_addr))
1303 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001304 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1305 break;
1306 case SOL_IP:
1307 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001308 case IP_TOS:
1309 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001310 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001311 case IP_ROUTER_ALERT:
1312 case IP_RECVOPTS:
1313 case IP_RETOPTS:
1314 case IP_PKTINFO:
1315 case IP_MTU_DISCOVER:
1316 case IP_RECVERR:
1317 case IP_RECVTOS:
1318#ifdef IP_FREEBIND
1319 case IP_FREEBIND:
1320#endif
1321 case IP_MULTICAST_TTL:
1322 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001323 val = 0;
1324 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001325 if (get_user_u32(val, optval_addr))
1326 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001327 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001328 if (get_user_u8(val, optval_addr))
1329 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001330 }
1331 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1332 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001333 case IP_ADD_MEMBERSHIP:
1334 case IP_DROP_MEMBERSHIP:
1335 if (optlen < sizeof (struct target_ip_mreq) ||
1336 optlen > sizeof (struct target_ip_mreqn))
1337 return -TARGET_EINVAL;
1338
1339 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1340 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1341 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1342 break;
1343
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001344 case IP_BLOCK_SOURCE:
1345 case IP_UNBLOCK_SOURCE:
1346 case IP_ADD_SOURCE_MEMBERSHIP:
1347 case IP_DROP_SOURCE_MEMBERSHIP:
1348 if (optlen != sizeof (struct target_ip_mreq_source))
1349 return -TARGET_EINVAL;
1350
1351 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1352 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1353 unlock_user (ip_mreq_source, optval_addr, 0);
1354 break;
1355
bellard8853f862004-02-22 14:57:26 +00001356 default:
1357 goto unimplemented;
1358 }
1359 break;
bellard3532fa72006-06-24 15:06:03 +00001360 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001361 switch (optname) {
1362 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001363 case TARGET_SO_DEBUG:
1364 optname = SO_DEBUG;
1365 break;
1366 case TARGET_SO_REUSEADDR:
1367 optname = SO_REUSEADDR;
1368 break;
1369 case TARGET_SO_TYPE:
1370 optname = SO_TYPE;
1371 break;
1372 case TARGET_SO_ERROR:
1373 optname = SO_ERROR;
1374 break;
1375 case TARGET_SO_DONTROUTE:
1376 optname = SO_DONTROUTE;
1377 break;
1378 case TARGET_SO_BROADCAST:
1379 optname = SO_BROADCAST;
1380 break;
1381 case TARGET_SO_SNDBUF:
1382 optname = SO_SNDBUF;
1383 break;
1384 case TARGET_SO_RCVBUF:
1385 optname = SO_RCVBUF;
1386 break;
1387 case TARGET_SO_KEEPALIVE:
1388 optname = SO_KEEPALIVE;
1389 break;
1390 case TARGET_SO_OOBINLINE:
1391 optname = SO_OOBINLINE;
1392 break;
1393 case TARGET_SO_NO_CHECK:
1394 optname = SO_NO_CHECK;
1395 break;
1396 case TARGET_SO_PRIORITY:
1397 optname = SO_PRIORITY;
1398 break;
bellard5e83e8e2005-03-01 22:32:06 +00001399#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001400 case TARGET_SO_BSDCOMPAT:
1401 optname = SO_BSDCOMPAT;
1402 break;
bellard5e83e8e2005-03-01 22:32:06 +00001403#endif
bellard3532fa72006-06-24 15:06:03 +00001404 case TARGET_SO_PASSCRED:
1405 optname = SO_PASSCRED;
1406 break;
1407 case TARGET_SO_TIMESTAMP:
1408 optname = SO_TIMESTAMP;
1409 break;
1410 case TARGET_SO_RCVLOWAT:
1411 optname = SO_RCVLOWAT;
1412 break;
1413 case TARGET_SO_RCVTIMEO:
1414 optname = SO_RCVTIMEO;
1415 break;
1416 case TARGET_SO_SNDTIMEO:
1417 optname = SO_SNDTIMEO;
1418 break;
bellard8853f862004-02-22 14:57:26 +00001419 break;
1420 default:
1421 goto unimplemented;
1422 }
bellard3532fa72006-06-24 15:06:03 +00001423 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001424 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001425
bellard2f619692007-11-16 10:46:05 +00001426 if (get_user_u32(val, optval_addr))
1427 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001428 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001429 break;
bellard7854b052003-03-29 17:22:23 +00001430 default:
bellard8853f862004-02-22 14:57:26 +00001431 unimplemented:
1432 gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001433 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001434 }
bellard8853f862004-02-22 14:57:26 +00001435 return ret;
bellard7854b052003-03-29 17:22:23 +00001436}
1437
ths0da46a62007-10-20 20:23:07 +00001438/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001439static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001440 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001441{
blueswir1992f48a2007-10-14 16:27:31 +00001442 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001443 int len, val;
1444 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001445
1446 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001447 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001448 level = SOL_SOCKET;
1449 switch (optname) {
1450 /* These don't just return a single integer */
1451 case TARGET_SO_LINGER:
1452 case TARGET_SO_RCVTIMEO:
1453 case TARGET_SO_SNDTIMEO:
1454 case TARGET_SO_PEERCRED:
1455 case TARGET_SO_PEERNAME:
1456 goto unimplemented;
1457 /* Options with 'int' argument. */
1458 case TARGET_SO_DEBUG:
1459 optname = SO_DEBUG;
1460 goto int_case;
1461 case TARGET_SO_REUSEADDR:
1462 optname = SO_REUSEADDR;
1463 goto int_case;
1464 case TARGET_SO_TYPE:
1465 optname = SO_TYPE;
1466 goto int_case;
1467 case TARGET_SO_ERROR:
1468 optname = SO_ERROR;
1469 goto int_case;
1470 case TARGET_SO_DONTROUTE:
1471 optname = SO_DONTROUTE;
1472 goto int_case;
1473 case TARGET_SO_BROADCAST:
1474 optname = SO_BROADCAST;
1475 goto int_case;
1476 case TARGET_SO_SNDBUF:
1477 optname = SO_SNDBUF;
1478 goto int_case;
1479 case TARGET_SO_RCVBUF:
1480 optname = SO_RCVBUF;
1481 goto int_case;
1482 case TARGET_SO_KEEPALIVE:
1483 optname = SO_KEEPALIVE;
1484 goto int_case;
1485 case TARGET_SO_OOBINLINE:
1486 optname = SO_OOBINLINE;
1487 goto int_case;
1488 case TARGET_SO_NO_CHECK:
1489 optname = SO_NO_CHECK;
1490 goto int_case;
1491 case TARGET_SO_PRIORITY:
1492 optname = SO_PRIORITY;
1493 goto int_case;
1494#ifdef SO_BSDCOMPAT
1495 case TARGET_SO_BSDCOMPAT:
1496 optname = SO_BSDCOMPAT;
1497 goto int_case;
1498#endif
1499 case TARGET_SO_PASSCRED:
1500 optname = SO_PASSCRED;
1501 goto int_case;
1502 case TARGET_SO_TIMESTAMP:
1503 optname = SO_TIMESTAMP;
1504 goto int_case;
1505 case TARGET_SO_RCVLOWAT:
1506 optname = SO_RCVLOWAT;
1507 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001508 default:
bellard2efbe912005-07-23 15:10:20 +00001509 goto int_case;
1510 }
1511 break;
1512 case SOL_TCP:
1513 /* TCP options all take an 'int' value. */
1514 int_case:
bellard2f619692007-11-16 10:46:05 +00001515 if (get_user_u32(len, optlen))
1516 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001517 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001518 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001519 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001520 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1521 if (ret < 0)
1522 return ret;
bellard2efbe912005-07-23 15:10:20 +00001523 if (len > lv)
1524 len = lv;
bellard2f619692007-11-16 10:46:05 +00001525 if (len == 4) {
1526 if (put_user_u32(val, optval_addr))
1527 return -TARGET_EFAULT;
1528 } else {
1529 if (put_user_u8(val, optval_addr))
1530 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001531 }
bellard2f619692007-11-16 10:46:05 +00001532 if (put_user_u32(len, optlen))
1533 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001534 break;
1535 case SOL_IP:
1536 switch(optname) {
1537 case IP_TOS:
1538 case IP_TTL:
1539 case IP_HDRINCL:
1540 case IP_ROUTER_ALERT:
1541 case IP_RECVOPTS:
1542 case IP_RETOPTS:
1543 case IP_PKTINFO:
1544 case IP_MTU_DISCOVER:
1545 case IP_RECVERR:
1546 case IP_RECVTOS:
1547#ifdef IP_FREEBIND
1548 case IP_FREEBIND:
1549#endif
1550 case IP_MULTICAST_TTL:
1551 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001552 if (get_user_u32(len, optlen))
1553 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001554 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001555 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001556 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001557 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1558 if (ret < 0)
1559 return ret;
bellard2efbe912005-07-23 15:10:20 +00001560 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001561 len = 1;
bellard2f619692007-11-16 10:46:05 +00001562 if (put_user_u32(len, optlen)
1563 || put_user_u8(val, optval_addr))
1564 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001565 } else {
bellard2efbe912005-07-23 15:10:20 +00001566 if (len > sizeof(int))
1567 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001568 if (put_user_u32(len, optlen)
1569 || put_user_u32(val, optval_addr))
1570 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001571 }
bellard8853f862004-02-22 14:57:26 +00001572 break;
bellard2efbe912005-07-23 15:10:20 +00001573 default:
thsc02f4992007-12-18 02:39:59 +00001574 ret = -TARGET_ENOPROTOOPT;
1575 break;
bellard8853f862004-02-22 14:57:26 +00001576 }
1577 break;
1578 default:
1579 unimplemented:
1580 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1581 level, optname);
thsc02f4992007-12-18 02:39:59 +00001582 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001583 break;
1584 }
1585 return ret;
bellard7854b052003-03-29 17:22:23 +00001586}
1587
bellard579a97f2007-11-11 14:26:47 +00001588/* FIXME
1589 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1590 * other lock functions have a return code of 0 for failure.
1591 */
1592static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1593 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001594{
1595 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001596 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001597 int i;
pbrook53a59602006-03-25 19:31:22 +00001598
bellard579a97f2007-11-11 14:26:47 +00001599 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1600 if (!target_vec)
1601 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001602 for(i = 0;i < count; i++) {
1603 base = tswapl(target_vec[i].iov_base);
1604 vec[i].iov_len = tswapl(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001605 if (vec[i].iov_len != 0) {
1606 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001607 /* Don't check lock_user return value. We must call writev even
1608 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001609 } else {
1610 /* zero length pointer is ignored */
1611 vec[i].iov_base = NULL;
1612 }
pbrook53a59602006-03-25 19:31:22 +00001613 }
1614 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001615 return 0;
pbrook53a59602006-03-25 19:31:22 +00001616}
1617
bellard579a97f2007-11-11 14:26:47 +00001618static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1619 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001620{
1621 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001622 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001623 int i;
1624
bellard579a97f2007-11-11 14:26:47 +00001625 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1626 if (!target_vec)
1627 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001628 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001629 if (target_vec[i].iov_base) {
1630 base = tswapl(target_vec[i].iov_base);
1631 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1632 }
pbrook53a59602006-03-25 19:31:22 +00001633 }
1634 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001635
1636 return 0;
pbrook53a59602006-03-25 19:31:22 +00001637}
1638
ths0da46a62007-10-20 20:23:07 +00001639/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001640static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001641{
1642#if defined(TARGET_MIPS)
1643 switch(type) {
1644 case TARGET_SOCK_DGRAM:
1645 type = SOCK_DGRAM;
1646 break;
1647 case TARGET_SOCK_STREAM:
1648 type = SOCK_STREAM;
1649 break;
1650 case TARGET_SOCK_RAW:
1651 type = SOCK_RAW;
1652 break;
1653 case TARGET_SOCK_RDM:
1654 type = SOCK_RDM;
1655 break;
1656 case TARGET_SOCK_SEQPACKET:
1657 type = SOCK_SEQPACKET;
1658 break;
1659 case TARGET_SOCK_PACKET:
1660 type = SOCK_PACKET;
1661 break;
1662 }
1663#endif
balrog12bc92a2007-10-30 21:06:14 +00001664 if (domain == PF_NETLINK)
1665 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001666 return get_errno(socket(domain, type, protocol));
1667}
1668
ths0da46a62007-10-20 20:23:07 +00001669/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001670static abi_long do_bind(int sockfd, abi_ulong target_addr,
1671 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001672{
aurel328f7aeaf2009-01-30 19:47:57 +00001673 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001674 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001675
Blue Swirl38724252010-09-18 05:53:14 +00001676 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001677 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001678 }
aurel328f7aeaf2009-01-30 19:47:57 +00001679
aurel32607175e2009-04-15 16:11:59 +00001680 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001681
Arnaud Patard917507b2009-06-19 10:44:45 +03001682 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1683 if (ret)
1684 return ret;
1685
bellard3532fa72006-06-24 15:06:03 +00001686 return get_errno(bind(sockfd, addr, addrlen));
1687}
1688
ths0da46a62007-10-20 20:23:07 +00001689/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001690static abi_long do_connect(int sockfd, abi_ulong target_addr,
1691 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001692{
aurel328f7aeaf2009-01-30 19:47:57 +00001693 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001694 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001695
Blue Swirl38724252010-09-18 05:53:14 +00001696 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001697 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001698 }
aurel328f7aeaf2009-01-30 19:47:57 +00001699
1700 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001701
Arnaud Patard917507b2009-06-19 10:44:45 +03001702 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1703 if (ret)
1704 return ret;
1705
bellard3532fa72006-06-24 15:06:03 +00001706 return get_errno(connect(sockfd, addr, addrlen));
1707}
1708
ths0da46a62007-10-20 20:23:07 +00001709/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001710static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1711 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001712{
balrog6de645c2008-10-28 10:26:29 +00001713 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001714 struct target_msghdr *msgp;
1715 struct msghdr msg;
1716 int count;
1717 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001718 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001719
bellard579a97f2007-11-11 14:26:47 +00001720 /* FIXME */
1721 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1722 msgp,
1723 target_msg,
1724 send ? 1 : 0))
1725 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001726 if (msgp->msg_name) {
1727 msg.msg_namelen = tswap32(msgp->msg_namelen);
1728 msg.msg_name = alloca(msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001729 ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001730 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001731 if (ret) {
1732 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1733 return ret;
1734 }
bellard3532fa72006-06-24 15:06:03 +00001735 } else {
1736 msg.msg_name = NULL;
1737 msg.msg_namelen = 0;
1738 }
1739 msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
1740 msg.msg_control = alloca(msg.msg_controllen);
1741 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001742
bellard3532fa72006-06-24 15:06:03 +00001743 count = tswapl(msgp->msg_iovlen);
1744 vec = alloca(count * sizeof(struct iovec));
1745 target_vec = tswapl(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001746 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001747 msg.msg_iovlen = count;
1748 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001749
bellard3532fa72006-06-24 15:06:03 +00001750 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001751 ret = target_to_host_cmsg(&msg, msgp);
1752 if (ret == 0)
1753 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001754 } else {
1755 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001756 if (!is_error(ret)) {
1757 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001758 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001759 if (!is_error(ret))
1760 ret = len;
1761 }
bellard3532fa72006-06-24 15:06:03 +00001762 }
1763 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001764 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001765 return ret;
1766}
1767
ths0da46a62007-10-20 20:23:07 +00001768/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001769static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001770 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001771{
bellard2f619692007-11-16 10:46:05 +00001772 socklen_t addrlen;
1773 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001774 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001775
Arnaud Patard917507b2009-06-19 10:44:45 +03001776 if (target_addr == 0)
1777 return get_errno(accept(fd, NULL, NULL));
1778
1779 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001780 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001781 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001782
Blue Swirl38724252010-09-18 05:53:14 +00001783 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001784 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001785 }
aurel328f7aeaf2009-01-30 19:47:57 +00001786
Arnaud Patard917507b2009-06-19 10:44:45 +03001787 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1788 return -TARGET_EINVAL;
1789
bellard2f619692007-11-16 10:46:05 +00001790 addr = alloca(addrlen);
1791
pbrook1be9e1d2006-11-19 15:26:04 +00001792 ret = get_errno(accept(fd, addr, &addrlen));
1793 if (!is_error(ret)) {
1794 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001795 if (put_user_u32(addrlen, target_addrlen_addr))
1796 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001797 }
1798 return ret;
1799}
1800
ths0da46a62007-10-20 20:23:07 +00001801/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001802static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001803 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001804{
bellard2f619692007-11-16 10:46:05 +00001805 socklen_t addrlen;
1806 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001807 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001808
bellard2f619692007-11-16 10:46:05 +00001809 if (get_user_u32(addrlen, target_addrlen_addr))
1810 return -TARGET_EFAULT;
1811
Blue Swirl38724252010-09-18 05:53:14 +00001812 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001813 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001814 }
aurel328f7aeaf2009-01-30 19:47:57 +00001815
Arnaud Patard917507b2009-06-19 10:44:45 +03001816 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1817 return -TARGET_EFAULT;
1818
bellard2f619692007-11-16 10:46:05 +00001819 addr = alloca(addrlen);
1820
pbrook1be9e1d2006-11-19 15:26:04 +00001821 ret = get_errno(getpeername(fd, addr, &addrlen));
1822 if (!is_error(ret)) {
1823 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001824 if (put_user_u32(addrlen, target_addrlen_addr))
1825 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001826 }
1827 return ret;
1828}
1829
ths0da46a62007-10-20 20:23:07 +00001830/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001831static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001832 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001833{
bellard2f619692007-11-16 10:46:05 +00001834 socklen_t addrlen;
1835 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001836 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001837
bellard2f619692007-11-16 10:46:05 +00001838 if (get_user_u32(addrlen, target_addrlen_addr))
1839 return -TARGET_EFAULT;
1840
Blue Swirl38724252010-09-18 05:53:14 +00001841 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001842 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001843 }
aurel328f7aeaf2009-01-30 19:47:57 +00001844
Arnaud Patard917507b2009-06-19 10:44:45 +03001845 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1846 return -TARGET_EFAULT;
1847
bellard2f619692007-11-16 10:46:05 +00001848 addr = alloca(addrlen);
1849
pbrook1be9e1d2006-11-19 15:26:04 +00001850 ret = get_errno(getsockname(fd, addr, &addrlen));
1851 if (!is_error(ret)) {
1852 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001853 if (put_user_u32(addrlen, target_addrlen_addr))
1854 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001855 }
1856 return ret;
1857}
1858
ths0da46a62007-10-20 20:23:07 +00001859/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001860static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001861 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001862{
1863 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001864 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001865
1866 ret = get_errno(socketpair(domain, type, protocol, tab));
1867 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001868 if (put_user_s32(tab[0], target_tab_addr)
1869 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1870 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001871 }
1872 return ret;
1873}
1874
ths0da46a62007-10-20 20:23:07 +00001875/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001876static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1877 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001878{
1879 void *addr;
1880 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001881 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001882
Blue Swirl38724252010-09-18 05:53:14 +00001883 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001884 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001885 }
aurel328f7aeaf2009-01-30 19:47:57 +00001886
bellard579a97f2007-11-11 14:26:47 +00001887 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1888 if (!host_msg)
1889 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001890 if (target_addr) {
1891 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001892 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1893 if (ret) {
1894 unlock_user(host_msg, msg, 0);
1895 return ret;
1896 }
pbrook1be9e1d2006-11-19 15:26:04 +00001897 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1898 } else {
1899 ret = get_errno(send(fd, host_msg, len, flags));
1900 }
1901 unlock_user(host_msg, msg, 0);
1902 return ret;
1903}
1904
ths0da46a62007-10-20 20:23:07 +00001905/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001906static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1907 abi_ulong target_addr,
1908 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001909{
1910 socklen_t addrlen;
1911 void *addr;
1912 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001913 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001914
bellard579a97f2007-11-11 14:26:47 +00001915 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
1916 if (!host_msg)
1917 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001918 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00001919 if (get_user_u32(addrlen, target_addrlen)) {
1920 ret = -TARGET_EFAULT;
1921 goto fail;
1922 }
Blue Swirl38724252010-09-18 05:53:14 +00001923 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001924 ret = -TARGET_EINVAL;
1925 goto fail;
1926 }
pbrook1be9e1d2006-11-19 15:26:04 +00001927 addr = alloca(addrlen);
1928 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
1929 } else {
1930 addr = NULL; /* To keep compiler quiet. */
1931 ret = get_errno(recv(fd, host_msg, len, flags));
1932 }
1933 if (!is_error(ret)) {
1934 if (target_addr) {
1935 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001936 if (put_user_u32(addrlen, target_addrlen)) {
1937 ret = -TARGET_EFAULT;
1938 goto fail;
1939 }
pbrook1be9e1d2006-11-19 15:26:04 +00001940 }
1941 unlock_user(host_msg, msg, len);
1942 } else {
bellard2f619692007-11-16 10:46:05 +00001943fail:
pbrook1be9e1d2006-11-19 15:26:04 +00001944 unlock_user(host_msg, msg, 0);
1945 }
1946 return ret;
1947}
1948
j_mayer32407102007-09-26 23:01:49 +00001949#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00001950/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001951static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00001952{
blueswir1992f48a2007-10-14 16:27:31 +00001953 abi_long ret;
1954 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00001955
1956 switch(num) {
1957 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00001958 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001959 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00001960
Ulrich Hecht98818182009-07-03 17:09:28 +02001961 if (get_user_ual(domain, vptr)
1962 || get_user_ual(type, vptr + n)
1963 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001964 return -TARGET_EFAULT;
1965
bellard3532fa72006-06-24 15:06:03 +00001966 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00001967 }
bellard31e31b82003-02-18 22:55:36 +00001968 break;
1969 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00001970 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001971 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001972 abi_ulong target_addr;
1973 socklen_t addrlen;
1974
Ulrich Hecht98818182009-07-03 17:09:28 +02001975 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001976 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001977 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001978 return -TARGET_EFAULT;
1979
bellard3532fa72006-06-24 15:06:03 +00001980 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00001981 }
bellard31e31b82003-02-18 22:55:36 +00001982 break;
1983 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00001984 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001985 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00001986 abi_ulong target_addr;
1987 socklen_t addrlen;
1988
Ulrich Hecht98818182009-07-03 17:09:28 +02001989 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00001990 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02001991 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00001992 return -TARGET_EFAULT;
1993
bellard3532fa72006-06-24 15:06:03 +00001994 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00001995 }
bellard31e31b82003-02-18 22:55:36 +00001996 break;
1997 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00001998 {
Ulrich Hecht98818182009-07-03 17:09:28 +02001999 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002000
Ulrich Hecht98818182009-07-03 17:09:28 +02002001 if (get_user_ual(sockfd, vptr)
2002 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002003 return -TARGET_EFAULT;
2004
bellard7854b052003-03-29 17:22:23 +00002005 ret = get_errno(listen(sockfd, backlog));
2006 }
bellard31e31b82003-02-18 22:55:36 +00002007 break;
2008 case SOCKOP_accept:
2009 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002010 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002011 abi_ulong target_addr, target_addrlen;
2012
Ulrich Hecht98818182009-07-03 17:09:28 +02002013 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002014 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002015 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002016 return -TARGET_EFAULT;
2017
pbrook1be9e1d2006-11-19 15:26:04 +00002018 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002019 }
2020 break;
2021 case SOCKOP_getsockname:
2022 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002023 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002024 abi_ulong target_addr, target_addrlen;
2025
Ulrich Hecht98818182009-07-03 17:09:28 +02002026 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002027 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002028 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002029 return -TARGET_EFAULT;
2030
pbrook1be9e1d2006-11-19 15:26:04 +00002031 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002032 }
2033 break;
2034 case SOCKOP_getpeername:
2035 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002036 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002037 abi_ulong target_addr, target_addrlen;
2038
Ulrich Hecht98818182009-07-03 17:09:28 +02002039 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002040 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002041 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002042 return -TARGET_EFAULT;
2043
pbrook1be9e1d2006-11-19 15:26:04 +00002044 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002045 }
2046 break;
2047 case SOCKOP_socketpair:
2048 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002049 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002050 abi_ulong tab;
2051
Ulrich Hecht98818182009-07-03 17:09:28 +02002052 if (get_user_ual(domain, vptr)
2053 || get_user_ual(type, vptr + n)
2054 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002055 || get_user_ual(tab, vptr + 3 * n))
2056 return -TARGET_EFAULT;
2057
pbrook1be9e1d2006-11-19 15:26:04 +00002058 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002059 }
2060 break;
2061 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002062 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002063 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002064 abi_ulong msg;
2065 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002066 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002067
Ulrich Hecht98818182009-07-03 17:09:28 +02002068 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002069 || get_user_ual(msg, vptr + n)
2070 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002071 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002072 return -TARGET_EFAULT;
2073
pbrook1be9e1d2006-11-19 15:26:04 +00002074 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002075 }
bellard31e31b82003-02-18 22:55:36 +00002076 break;
2077 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002078 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002079 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002080 abi_ulong msg;
2081 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002082 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002083
Ulrich Hecht98818182009-07-03 17:09:28 +02002084 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002085 || get_user_ual(msg, vptr + n)
2086 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002087 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002088 return -TARGET_EFAULT;
2089
pbrook1be9e1d2006-11-19 15:26:04 +00002090 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002091 }
bellard31e31b82003-02-18 22:55:36 +00002092 break;
2093 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002094 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002095 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002096 abi_ulong msg;
2097 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002098 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002099 abi_ulong addr;
2100 socklen_t 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(msg, vptr + n)
2104 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002105 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002106 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002107 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002108 return -TARGET_EFAULT;
2109
pbrook1be9e1d2006-11-19 15:26:04 +00002110 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002111 }
bellard31e31b82003-02-18 22:55:36 +00002112 break;
2113 case SOCKOP_recvfrom:
2114 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002115 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002116 abi_ulong msg;
2117 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002118 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002119 abi_ulong addr;
2120 socklen_t addrlen;
2121
Ulrich Hecht98818182009-07-03 17:09:28 +02002122 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002123 || get_user_ual(msg, vptr + n)
2124 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002125 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002126 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002127 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002128 return -TARGET_EFAULT;
2129
pbrook1be9e1d2006-11-19 15:26:04 +00002130 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002131 }
2132 break;
2133 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002134 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002135 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002136
Ulrich Hecht98818182009-07-03 17:09:28 +02002137 if (get_user_ual(sockfd, vptr)
2138 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002139 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002140
2141 ret = get_errno(shutdown(sockfd, how));
2142 }
bellard31e31b82003-02-18 22:55:36 +00002143 break;
2144 case SOCKOP_sendmsg:
2145 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002146 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002147 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002148 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002149 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002150
Ulrich Hecht98818182009-07-03 17:09:28 +02002151 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002152 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002153 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002154 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002155
ths5fafdf22007-09-16 21:08:06 +00002156 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002157 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002158 }
2159 break;
bellard31e31b82003-02-18 22:55:36 +00002160 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002161 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002162 abi_ulong sockfd;
2163 abi_ulong level;
2164 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002165 abi_ulong optval;
2166 socklen_t optlen;
2167
Ulrich Hecht98818182009-07-03 17:09:28 +02002168 if (get_user_ual(sockfd, vptr)
2169 || get_user_ual(level, vptr + n)
2170 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002171 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002172 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002173 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002174
2175 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2176 }
2177 break;
bellard31e31b82003-02-18 22:55:36 +00002178 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002179 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002180 abi_ulong sockfd;
2181 abi_ulong level;
2182 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002183 abi_ulong optval;
2184 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002185
Ulrich Hecht98818182009-07-03 17:09:28 +02002186 if (get_user_ual(sockfd, vptr)
2187 || get_user_ual(level, vptr + n)
2188 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002189 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002190 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002191 return -TARGET_EFAULT;
2192
2193 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002194 }
2195 break;
bellard31e31b82003-02-18 22:55:36 +00002196 default:
2197 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002198 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002199 break;
2200 }
2201 return ret;
2202}
j_mayer32407102007-09-26 23:01:49 +00002203#endif
bellard31e31b82003-02-18 22:55:36 +00002204
bellard8853f862004-02-22 14:57:26 +00002205#define N_SHM_REGIONS 32
2206
2207static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002208 abi_ulong start;
2209 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002210} shm_regions[N_SHM_REGIONS];
2211
ths3eb6b042007-06-03 14:26:27 +00002212struct target_ipc_perm
2213{
blueswir1992f48a2007-10-14 16:27:31 +00002214 abi_long __key;
2215 abi_ulong uid;
2216 abi_ulong gid;
2217 abi_ulong cuid;
2218 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002219 unsigned short int mode;
2220 unsigned short int __pad1;
2221 unsigned short int __seq;
2222 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002223 abi_ulong __unused1;
2224 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002225};
2226
2227struct target_semid_ds
2228{
2229 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002230 abi_ulong sem_otime;
2231 abi_ulong __unused1;
2232 abi_ulong sem_ctime;
2233 abi_ulong __unused2;
2234 abi_ulong sem_nsems;
2235 abi_ulong __unused3;
2236 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002237};
2238
bellard579a97f2007-11-11 14:26:47 +00002239static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2240 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002241{
2242 struct target_ipc_perm *target_ip;
2243 struct target_semid_ds *target_sd;
2244
bellard579a97f2007-11-11 14:26:47 +00002245 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2246 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002247 target_ip = &(target_sd->sem_perm);
ths3eb6b042007-06-03 14:26:27 +00002248 host_ip->__key = tswapl(target_ip->__key);
2249 host_ip->uid = tswapl(target_ip->uid);
2250 host_ip->gid = tswapl(target_ip->gid);
2251 host_ip->cuid = tswapl(target_ip->cuid);
2252 host_ip->cgid = tswapl(target_ip->cgid);
2253 host_ip->mode = tswapl(target_ip->mode);
2254 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002255 return 0;
ths3eb6b042007-06-03 14:26:27 +00002256}
2257
bellard579a97f2007-11-11 14:26:47 +00002258static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2259 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002260{
2261 struct target_ipc_perm *target_ip;
2262 struct target_semid_ds *target_sd;
2263
bellard579a97f2007-11-11 14:26:47 +00002264 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2265 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002266 target_ip = &(target_sd->sem_perm);
2267 target_ip->__key = tswapl(host_ip->__key);
2268 target_ip->uid = tswapl(host_ip->uid);
2269 target_ip->gid = tswapl(host_ip->gid);
2270 target_ip->cuid = tswapl(host_ip->cuid);
2271 target_ip->cgid = tswapl(host_ip->cgid);
2272 target_ip->mode = tswapl(host_ip->mode);
2273 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002274 return 0;
ths3eb6b042007-06-03 14:26:27 +00002275}
2276
bellard579a97f2007-11-11 14:26:47 +00002277static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2278 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002279{
2280 struct target_semid_ds *target_sd;
2281
bellard579a97f2007-11-11 14:26:47 +00002282 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2283 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002284 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2285 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002286 host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
2287 host_sd->sem_otime = tswapl(target_sd->sem_otime);
2288 host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
2289 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002290 return 0;
ths3eb6b042007-06-03 14:26:27 +00002291}
2292
bellard579a97f2007-11-11 14:26:47 +00002293static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2294 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002295{
2296 struct target_semid_ds *target_sd;
2297
bellard579a97f2007-11-11 14:26:47 +00002298 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2299 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002300 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2301 return -TARGET_EFAULT;;
ths3eb6b042007-06-03 14:26:27 +00002302 target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
2303 target_sd->sem_otime = tswapl(host_sd->sem_otime);
2304 target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
2305 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002306 return 0;
ths3eb6b042007-06-03 14:26:27 +00002307}
2308
aurel32e5289082009-04-18 16:16:12 +00002309struct target_seminfo {
2310 int semmap;
2311 int semmni;
2312 int semmns;
2313 int semmnu;
2314 int semmsl;
2315 int semopm;
2316 int semume;
2317 int semusz;
2318 int semvmx;
2319 int semaem;
2320};
2321
2322static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2323 struct seminfo *host_seminfo)
2324{
2325 struct target_seminfo *target_seminfo;
2326 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2327 return -TARGET_EFAULT;
2328 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2329 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2330 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2331 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2332 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2333 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2334 __put_user(host_seminfo->semume, &target_seminfo->semume);
2335 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2336 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2337 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2338 unlock_user_struct(target_seminfo, target_addr, 1);
2339 return 0;
2340}
2341
thsfa294812007-02-02 22:05:00 +00002342union semun {
2343 int val;
ths3eb6b042007-06-03 14:26:27 +00002344 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002345 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002346 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002347};
2348
ths3eb6b042007-06-03 14:26:27 +00002349union target_semun {
2350 int val;
aurel32e5289082009-04-18 16:16:12 +00002351 abi_ulong buf;
2352 abi_ulong array;
2353 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002354};
2355
aurel32e5289082009-04-18 16:16:12 +00002356static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2357 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002358{
aurel32e5289082009-04-18 16:16:12 +00002359 int nsems;
2360 unsigned short *array;
2361 union semun semun;
2362 struct semid_ds semid_ds;
2363 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002364
aurel32e5289082009-04-18 16:16:12 +00002365 semun.buf = &semid_ds;
2366
2367 ret = semctl(semid, 0, IPC_STAT, semun);
2368 if (ret == -1)
2369 return get_errno(ret);
2370
2371 nsems = semid_ds.sem_nsems;
2372
2373 *host_array = malloc(nsems*sizeof(unsigned short));
2374 array = lock_user(VERIFY_READ, target_addr,
2375 nsems*sizeof(unsigned short), 1);
2376 if (!array)
2377 return -TARGET_EFAULT;
2378
2379 for(i=0; i<nsems; i++) {
2380 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002381 }
aurel32e5289082009-04-18 16:16:12 +00002382 unlock_user(array, target_addr, 0);
2383
bellard579a97f2007-11-11 14:26:47 +00002384 return 0;
ths3eb6b042007-06-03 14:26:27 +00002385}
2386
aurel32e5289082009-04-18 16:16:12 +00002387static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2388 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002389{
aurel32e5289082009-04-18 16:16:12 +00002390 int nsems;
2391 unsigned short *array;
2392 union semun semun;
2393 struct semid_ds semid_ds;
2394 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002395
aurel32e5289082009-04-18 16:16:12 +00002396 semun.buf = &semid_ds;
2397
2398 ret = semctl(semid, 0, IPC_STAT, semun);
2399 if (ret == -1)
2400 return get_errno(ret);
2401
2402 nsems = semid_ds.sem_nsems;
2403
2404 array = lock_user(VERIFY_WRITE, target_addr,
2405 nsems*sizeof(unsigned short), 0);
2406 if (!array)
2407 return -TARGET_EFAULT;
2408
2409 for(i=0; i<nsems; i++) {
2410 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002411 }
aurel32e5289082009-04-18 16:16:12 +00002412 free(*host_array);
2413 unlock_user(array, target_addr, 1);
2414
bellard579a97f2007-11-11 14:26:47 +00002415 return 0;
ths3eb6b042007-06-03 14:26:27 +00002416}
2417
aurel32e5289082009-04-18 16:16:12 +00002418static inline abi_long do_semctl(int semid, int semnum, int cmd,
2419 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002420{
2421 union semun arg;
2422 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302423 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002424 struct seminfo seminfo;
2425 abi_long ret = -TARGET_EINVAL;
2426 abi_long err;
2427 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002428
2429 switch( cmd ) {
2430 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002431 case SETVAL:
aurel32e5289082009-04-18 16:16:12 +00002432 arg.val = tswapl(target_su.val);
2433 ret = get_errno(semctl(semid, semnum, cmd, arg));
2434 target_su.val = tswapl(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002435 break;
2436 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002437 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002438 err = target_to_host_semarray(semid, &array, target_su.array);
2439 if (err)
2440 return err;
2441 arg.array = array;
2442 ret = get_errno(semctl(semid, semnum, cmd, arg));
2443 err = host_to_target_semarray(semid, target_su.array, &array);
2444 if (err)
2445 return err;
ths3eb6b042007-06-03 14:26:27 +00002446 break;
2447 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002448 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002449 case SEM_STAT:
2450 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2451 if (err)
2452 return err;
2453 arg.buf = &dsarg;
2454 ret = get_errno(semctl(semid, semnum, cmd, arg));
2455 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2456 if (err)
2457 return err;
ths3eb6b042007-06-03 14:26:27 +00002458 break;
aurel32e5289082009-04-18 16:16:12 +00002459 case IPC_INFO:
2460 case SEM_INFO:
2461 arg.__buf = &seminfo;
2462 ret = get_errno(semctl(semid, semnum, cmd, arg));
2463 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2464 if (err)
2465 return err;
2466 break;
2467 case IPC_RMID:
2468 case GETPID:
2469 case GETNCNT:
2470 case GETZCNT:
2471 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2472 break;
ths3eb6b042007-06-03 14:26:27 +00002473 }
2474
2475 return ret;
2476}
2477
aurel32e5289082009-04-18 16:16:12 +00002478struct target_sembuf {
2479 unsigned short sem_num;
2480 short sem_op;
2481 short sem_flg;
2482};
2483
2484static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2485 abi_ulong target_addr,
2486 unsigned nsops)
2487{
2488 struct target_sembuf *target_sembuf;
2489 int i;
2490
2491 target_sembuf = lock_user(VERIFY_READ, target_addr,
2492 nsops*sizeof(struct target_sembuf), 1);
2493 if (!target_sembuf)
2494 return -TARGET_EFAULT;
2495
2496 for(i=0; i<nsops; i++) {
2497 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2498 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2499 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2500 }
2501
2502 unlock_user(target_sembuf, target_addr, 0);
2503
2504 return 0;
2505}
2506
2507static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2508{
2509 struct sembuf sops[nsops];
2510
2511 if (target_to_host_sembuf(sops, ptr, nsops))
2512 return -TARGET_EFAULT;
2513
2514 return semop(semid, sops, nsops);
2515}
2516
ths1bc012f2007-06-03 14:27:49 +00002517struct target_msqid_ds
2518{
aurel321c54ff92008-10-13 21:08:44 +00002519 struct target_ipc_perm msg_perm;
2520 abi_ulong msg_stime;
2521#if TARGET_ABI_BITS == 32
2522 abi_ulong __unused1;
2523#endif
2524 abi_ulong msg_rtime;
2525#if TARGET_ABI_BITS == 32
2526 abi_ulong __unused2;
2527#endif
2528 abi_ulong msg_ctime;
2529#if TARGET_ABI_BITS == 32
2530 abi_ulong __unused3;
2531#endif
2532 abi_ulong __msg_cbytes;
2533 abi_ulong msg_qnum;
2534 abi_ulong msg_qbytes;
2535 abi_ulong msg_lspid;
2536 abi_ulong msg_lrpid;
2537 abi_ulong __unused4;
2538 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002539};
2540
bellard579a97f2007-11-11 14:26:47 +00002541static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2542 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002543{
2544 struct target_msqid_ds *target_md;
2545
bellard579a97f2007-11-11 14:26:47 +00002546 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2547 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002548 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2549 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002550 host_md->msg_stime = tswapl(target_md->msg_stime);
2551 host_md->msg_rtime = tswapl(target_md->msg_rtime);
2552 host_md->msg_ctime = tswapl(target_md->msg_ctime);
2553 host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
2554 host_md->msg_qnum = tswapl(target_md->msg_qnum);
2555 host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
2556 host_md->msg_lspid = tswapl(target_md->msg_lspid);
2557 host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
2558 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002559 return 0;
ths1bc012f2007-06-03 14:27:49 +00002560}
2561
bellard579a97f2007-11-11 14:26:47 +00002562static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2563 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002564{
2565 struct target_msqid_ds *target_md;
2566
bellard579a97f2007-11-11 14:26:47 +00002567 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2568 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002569 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2570 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002571 target_md->msg_stime = tswapl(host_md->msg_stime);
2572 target_md->msg_rtime = tswapl(host_md->msg_rtime);
2573 target_md->msg_ctime = tswapl(host_md->msg_ctime);
2574 target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
2575 target_md->msg_qnum = tswapl(host_md->msg_qnum);
2576 target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
2577 target_md->msg_lspid = tswapl(host_md->msg_lspid);
2578 target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
2579 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002580 return 0;
ths1bc012f2007-06-03 14:27:49 +00002581}
2582
aurel321c54ff92008-10-13 21:08:44 +00002583struct target_msginfo {
2584 int msgpool;
2585 int msgmap;
2586 int msgmax;
2587 int msgmnb;
2588 int msgmni;
2589 int msgssz;
2590 int msgtql;
2591 unsigned short int msgseg;
2592};
2593
2594static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2595 struct msginfo *host_msginfo)
2596{
2597 struct target_msginfo *target_msginfo;
2598 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2599 return -TARGET_EFAULT;
2600 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2601 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2602 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2603 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2604 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2605 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2606 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2607 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2608 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002609 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002610}
2611
2612static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002613{
2614 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002615 struct msginfo msginfo;
2616 abi_long ret = -TARGET_EINVAL;
2617
2618 cmd &= 0xff;
2619
2620 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002621 case IPC_STAT:
2622 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002623 case MSG_STAT:
2624 if (target_to_host_msqid_ds(&dsarg,ptr))
2625 return -TARGET_EFAULT;
2626 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2627 if (host_to_target_msqid_ds(ptr,&dsarg))
2628 return -TARGET_EFAULT;
2629 break;
2630 case IPC_RMID:
2631 ret = get_errno(msgctl(msgid, cmd, NULL));
2632 break;
2633 case IPC_INFO:
2634 case MSG_INFO:
2635 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2636 if (host_to_target_msginfo(ptr, &msginfo))
2637 return -TARGET_EFAULT;
2638 break;
ths1bc012f2007-06-03 14:27:49 +00002639 }
aurel321c54ff92008-10-13 21:08:44 +00002640
ths1bc012f2007-06-03 14:27:49 +00002641 return ret;
2642}
2643
2644struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002645 abi_long mtype;
2646 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002647};
2648
blueswir1992f48a2007-10-14 16:27:31 +00002649static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2650 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002651{
2652 struct target_msgbuf *target_mb;
2653 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002654 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002655
bellard579a97f2007-11-11 14:26:47 +00002656 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2657 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002658 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002659 host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
2660 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002661 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2662 free(host_mb);
2663 unlock_user_struct(target_mb, msgp, 0);
2664
2665 return ret;
2666}
2667
blueswir1992f48a2007-10-14 16:27:31 +00002668static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002669 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002670 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002671{
2672 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002673 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002674 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002675 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002676
bellard579a97f2007-11-11 14:26:47 +00002677 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2678 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002679
ths1bc012f2007-06-03 14:27:49 +00002680 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002681 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
2682
bellard579a97f2007-11-11 14:26:47 +00002683 if (ret > 0) {
2684 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2685 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2686 if (!target_mtext) {
2687 ret = -TARGET_EFAULT;
2688 goto end;
2689 }
aurel321c54ff92008-10-13 21:08:44 +00002690 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002691 unlock_user(target_mtext, target_mtext_addr, ret);
2692 }
aurel321c54ff92008-10-13 21:08:44 +00002693
ths1bc012f2007-06-03 14:27:49 +00002694 target_mb->mtype = tswapl(host_mb->mtype);
2695 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002696
bellard579a97f2007-11-11 14:26:47 +00002697end:
2698 if (target_mb)
2699 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002700 return ret;
2701}
2702
Riku Voipio88a8c982009-04-03 10:42:00 +03002703struct target_shmid_ds
2704{
2705 struct target_ipc_perm shm_perm;
2706 abi_ulong shm_segsz;
2707 abi_ulong shm_atime;
2708#if TARGET_ABI_BITS == 32
2709 abi_ulong __unused1;
2710#endif
2711 abi_ulong shm_dtime;
2712#if TARGET_ABI_BITS == 32
2713 abi_ulong __unused2;
2714#endif
2715 abi_ulong shm_ctime;
2716#if TARGET_ABI_BITS == 32
2717 abi_ulong __unused3;
2718#endif
2719 int shm_cpid;
2720 int shm_lpid;
2721 abi_ulong shm_nattch;
2722 unsigned long int __unused4;
2723 unsigned long int __unused5;
2724};
2725
2726static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2727 abi_ulong target_addr)
2728{
2729 struct target_shmid_ds *target_sd;
2730
2731 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2732 return -TARGET_EFAULT;
2733 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2734 return -TARGET_EFAULT;
2735 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2736 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2737 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2738 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2739 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2740 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2741 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2742 unlock_user_struct(target_sd, target_addr, 0);
2743 return 0;
2744}
2745
2746static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2747 struct shmid_ds *host_sd)
2748{
2749 struct target_shmid_ds *target_sd;
2750
2751 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2752 return -TARGET_EFAULT;
2753 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2754 return -TARGET_EFAULT;
2755 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2756 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2757 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2758 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2759 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2760 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2761 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2762 unlock_user_struct(target_sd, target_addr, 1);
2763 return 0;
2764}
2765
2766struct target_shminfo {
2767 abi_ulong shmmax;
2768 abi_ulong shmmin;
2769 abi_ulong shmmni;
2770 abi_ulong shmseg;
2771 abi_ulong shmall;
2772};
2773
2774static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2775 struct shminfo *host_shminfo)
2776{
2777 struct target_shminfo *target_shminfo;
2778 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2779 return -TARGET_EFAULT;
2780 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2781 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2782 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2783 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2784 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2785 unlock_user_struct(target_shminfo, target_addr, 1);
2786 return 0;
2787}
2788
2789struct target_shm_info {
2790 int used_ids;
2791 abi_ulong shm_tot;
2792 abi_ulong shm_rss;
2793 abi_ulong shm_swp;
2794 abi_ulong swap_attempts;
2795 abi_ulong swap_successes;
2796};
2797
2798static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2799 struct shm_info *host_shm_info)
2800{
2801 struct target_shm_info *target_shm_info;
2802 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2803 return -TARGET_EFAULT;
2804 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2805 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2806 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2807 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2808 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2809 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2810 unlock_user_struct(target_shm_info, target_addr, 1);
2811 return 0;
2812}
2813
2814static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2815{
2816 struct shmid_ds dsarg;
2817 struct shminfo shminfo;
2818 struct shm_info shm_info;
2819 abi_long ret = -TARGET_EINVAL;
2820
2821 cmd &= 0xff;
2822
2823 switch(cmd) {
2824 case IPC_STAT:
2825 case IPC_SET:
2826 case SHM_STAT:
2827 if (target_to_host_shmid_ds(&dsarg, buf))
2828 return -TARGET_EFAULT;
2829 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2830 if (host_to_target_shmid_ds(buf, &dsarg))
2831 return -TARGET_EFAULT;
2832 break;
2833 case IPC_INFO:
2834 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2835 if (host_to_target_shminfo(buf, &shminfo))
2836 return -TARGET_EFAULT;
2837 break;
2838 case SHM_INFO:
2839 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2840 if (host_to_target_shm_info(buf, &shm_info))
2841 return -TARGET_EFAULT;
2842 break;
2843 case IPC_RMID:
2844 case SHM_LOCK:
2845 case SHM_UNLOCK:
2846 ret = get_errno(shmctl(shmid, cmd, NULL));
2847 break;
2848 }
2849
2850 return ret;
2851}
2852
2853static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2854{
2855 abi_long raddr;
2856 void *host_raddr;
2857 struct shmid_ds shm_info;
2858 int i,ret;
2859
2860 /* find out the length of the shared memory segment */
2861 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2862 if (is_error(ret)) {
2863 /* can't get length, bail out */
2864 return ret;
2865 }
2866
2867 mmap_lock();
2868
2869 if (shmaddr)
2870 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2871 else {
2872 abi_ulong mmap_start;
2873
2874 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2875
2876 if (mmap_start == -1) {
2877 errno = ENOMEM;
2878 host_raddr = (void *)-1;
2879 } else
2880 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2881 }
2882
2883 if (host_raddr == (void *)-1) {
2884 mmap_unlock();
2885 return get_errno((long)host_raddr);
2886 }
2887 raddr=h2g((unsigned long)host_raddr);
2888
2889 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2890 PAGE_VALID | PAGE_READ |
2891 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2892
2893 for (i = 0; i < N_SHM_REGIONS; i++) {
2894 if (shm_regions[i].start == 0) {
2895 shm_regions[i].start = raddr;
2896 shm_regions[i].size = shm_info.shm_segsz;
2897 break;
2898 }
2899 }
2900
2901 mmap_unlock();
2902 return raddr;
2903
2904}
2905
2906static inline abi_long do_shmdt(abi_ulong shmaddr)
2907{
2908 int i;
2909
2910 for (i = 0; i < N_SHM_REGIONS; ++i) {
2911 if (shm_regions[i].start == shmaddr) {
2912 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09002913 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03002914 break;
2915 }
2916 }
2917
2918 return get_errno(shmdt(g2h(shmaddr)));
2919}
2920
aurel321c54ff92008-10-13 21:08:44 +00002921#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00002922/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00002923/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002924static abi_long do_ipc(unsigned int call, int first,
2925 int second, int third,
2926 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00002927{
2928 int version;
blueswir1992f48a2007-10-14 16:27:31 +00002929 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00002930
2931 version = call >> 16;
2932 call &= 0xffff;
2933
2934 switch (call) {
thsfa294812007-02-02 22:05:00 +00002935 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00002936 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00002937 break;
2938
2939 case IPCOP_semget:
2940 ret = get_errno(semget(first, second, third));
2941 break;
2942
2943 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00002944 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00002945 break;
thsd96372e2007-02-02 22:05:44 +00002946
aurel321c54ff92008-10-13 21:08:44 +00002947 case IPCOP_msgget:
2948 ret = get_errno(msgget(first, second));
2949 break;
thsd96372e2007-02-02 22:05:44 +00002950
aurel321c54ff92008-10-13 21:08:44 +00002951 case IPCOP_msgsnd:
2952 ret = do_msgsnd(first, ptr, second, third);
2953 break;
thsd96372e2007-02-02 22:05:44 +00002954
aurel321c54ff92008-10-13 21:08:44 +00002955 case IPCOP_msgctl:
2956 ret = do_msgctl(first, second, ptr);
2957 break;
thsd96372e2007-02-02 22:05:44 +00002958
aurel321c54ff92008-10-13 21:08:44 +00002959 case IPCOP_msgrcv:
2960 switch (version) {
2961 case 0:
2962 {
2963 struct target_ipc_kludge {
2964 abi_long msgp;
2965 abi_long msgtyp;
2966 } *tmp;
thsd96372e2007-02-02 22:05:44 +00002967
aurel321c54ff92008-10-13 21:08:44 +00002968 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
2969 ret = -TARGET_EFAULT;
2970 break;
ths1bc012f2007-06-03 14:27:49 +00002971 }
aurel321c54ff92008-10-13 21:08:44 +00002972
2973 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
2974
2975 unlock_user_struct(tmp, ptr, 0);
2976 break;
2977 }
2978 default:
2979 ret = do_msgrcv(first, ptr, second, fifth, third);
2980 }
2981 break;
thsd96372e2007-02-02 22:05:44 +00002982
bellard8853f862004-02-22 14:57:26 +00002983 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03002984 switch (version) {
2985 default:
bellard5a4a8982007-11-11 17:39:18 +00002986 {
2987 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03002988 raddr = do_shmat(first, ptr, second);
2989 if (is_error(raddr))
2990 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00002991 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00002992 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03002993 break;
2994 }
2995 case 1:
2996 ret = -TARGET_EINVAL;
2997 break;
bellard5a4a8982007-11-11 17:39:18 +00002998 }
bellard8853f862004-02-22 14:57:26 +00002999 break;
3000 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003001 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003002 break;
3003
3004 case IPCOP_shmget:
3005 /* IPC_* flag values are the same on all linux platforms */
3006 ret = get_errno(shmget(first, second, third));
3007 break;
3008
3009 /* IPC_* and SHM_* command values are the same on all linux platforms */
3010 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003011 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003012 break;
3013 default:
j_mayer32407102007-09-26 23:01:49 +00003014 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003015 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003016 break;
3017 }
3018 return ret;
3019}
j_mayer32407102007-09-26 23:01:49 +00003020#endif
bellard8853f862004-02-22 14:57:26 +00003021
bellard31e31b82003-02-18 22:55:36 +00003022/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003023
Blue Swirl001faf32009-05-13 17:53:17 +00003024#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003025#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3026enum {
3027#include "syscall_types.h"
3028};
3029#undef STRUCT
3030#undef STRUCT_SPECIAL
3031
Blue Swirl001faf32009-05-13 17:53:17 +00003032#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003033#define STRUCT_SPECIAL(name)
3034#include "syscall_types.h"
3035#undef STRUCT
3036#undef STRUCT_SPECIAL
3037
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003038typedef struct IOCTLEntry IOCTLEntry;
3039
3040typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3041 int fd, abi_long cmd, abi_long arg);
3042
3043struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003044 unsigned int target_cmd;
3045 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003046 const char *name;
3047 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003048 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003049 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003050};
bellard31e31b82003-02-18 22:55:36 +00003051
3052#define IOC_R 0x0001
3053#define IOC_W 0x0002
3054#define IOC_RW (IOC_R | IOC_W)
3055
3056#define MAX_STRUCT_SIZE 4096
3057
Peter Maydelldace20d2011-01-10 13:11:24 +00003058#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003059/* So fiemap access checks don't overflow on 32 bit systems.
3060 * This is very slightly smaller than the limit imposed by
3061 * the underlying kernel.
3062 */
3063#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3064 / sizeof(struct fiemap_extent))
3065
3066static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3067 int fd, abi_long cmd, abi_long arg)
3068{
3069 /* The parameter for this ioctl is a struct fiemap followed
3070 * by an array of struct fiemap_extent whose size is set
3071 * in fiemap->fm_extent_count. The array is filled in by the
3072 * ioctl.
3073 */
3074 int target_size_in, target_size_out;
3075 struct fiemap *fm;
3076 const argtype *arg_type = ie->arg_type;
3077 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3078 void *argptr, *p;
3079 abi_long ret;
3080 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3081 uint32_t outbufsz;
3082 int free_fm = 0;
3083
3084 assert(arg_type[0] == TYPE_PTR);
3085 assert(ie->access == IOC_RW);
3086 arg_type++;
3087 target_size_in = thunk_type_size(arg_type, 0);
3088 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3089 if (!argptr) {
3090 return -TARGET_EFAULT;
3091 }
3092 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3093 unlock_user(argptr, arg, 0);
3094 fm = (struct fiemap *)buf_temp;
3095 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3096 return -TARGET_EINVAL;
3097 }
3098
3099 outbufsz = sizeof (*fm) +
3100 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3101
3102 if (outbufsz > MAX_STRUCT_SIZE) {
3103 /* We can't fit all the extents into the fixed size buffer.
3104 * Allocate one that is large enough and use it instead.
3105 */
3106 fm = malloc(outbufsz);
3107 if (!fm) {
3108 return -TARGET_ENOMEM;
3109 }
3110 memcpy(fm, buf_temp, sizeof(struct fiemap));
3111 free_fm = 1;
3112 }
3113 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3114 if (!is_error(ret)) {
3115 target_size_out = target_size_in;
3116 /* An extent_count of 0 means we were only counting the extents
3117 * so there are no structs to copy
3118 */
3119 if (fm->fm_extent_count != 0) {
3120 target_size_out += fm->fm_mapped_extents * extent_size;
3121 }
3122 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3123 if (!argptr) {
3124 ret = -TARGET_EFAULT;
3125 } else {
3126 /* Convert the struct fiemap */
3127 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3128 if (fm->fm_extent_count != 0) {
3129 p = argptr + target_size_in;
3130 /* ...and then all the struct fiemap_extents */
3131 for (i = 0; i < fm->fm_mapped_extents; i++) {
3132 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3133 THUNK_TARGET);
3134 p += extent_size;
3135 }
3136 }
3137 unlock_user(argptr, arg, target_size_out);
3138 }
3139 }
3140 if (free_fm) {
3141 free(fm);
3142 }
3143 return ret;
3144}
Peter Maydelldace20d2011-01-10 13:11:24 +00003145#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003146
Laurent Vivier059c2f22011-03-30 00:12:12 +02003147static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3148 int fd, abi_long cmd, abi_long arg)
3149{
3150 const argtype *arg_type = ie->arg_type;
3151 int target_size;
3152 void *argptr;
3153 int ret;
3154 struct ifconf *host_ifconf;
3155 uint32_t outbufsz;
3156 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3157 int target_ifreq_size;
3158 int nb_ifreq;
3159 int free_buf = 0;
3160 int i;
3161 int target_ifc_len;
3162 abi_long target_ifc_buf;
3163 int host_ifc_len;
3164 char *host_ifc_buf;
3165
3166 assert(arg_type[0] == TYPE_PTR);
3167 assert(ie->access == IOC_RW);
3168
3169 arg_type++;
3170 target_size = thunk_type_size(arg_type, 0);
3171
3172 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3173 if (!argptr)
3174 return -TARGET_EFAULT;
3175 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3176 unlock_user(argptr, arg, 0);
3177
3178 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3179 target_ifc_len = host_ifconf->ifc_len;
3180 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3181
3182 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3183 nb_ifreq = target_ifc_len / target_ifreq_size;
3184 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3185
3186 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3187 if (outbufsz > MAX_STRUCT_SIZE) {
3188 /* We can't fit all the extents into the fixed size buffer.
3189 * Allocate one that is large enough and use it instead.
3190 */
3191 host_ifconf = malloc(outbufsz);
3192 if (!host_ifconf) {
3193 return -TARGET_ENOMEM;
3194 }
3195 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3196 free_buf = 1;
3197 }
3198 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3199
3200 host_ifconf->ifc_len = host_ifc_len;
3201 host_ifconf->ifc_buf = host_ifc_buf;
3202
3203 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3204 if (!is_error(ret)) {
3205 /* convert host ifc_len to target ifc_len */
3206
3207 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3208 target_ifc_len = nb_ifreq * target_ifreq_size;
3209 host_ifconf->ifc_len = target_ifc_len;
3210
3211 /* restore target ifc_buf */
3212
3213 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3214
3215 /* copy struct ifconf to target user */
3216
3217 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3218 if (!argptr)
3219 return -TARGET_EFAULT;
3220 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3221 unlock_user(argptr, arg, target_size);
3222
3223 /* copy ifreq[] to target user */
3224
3225 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3226 for (i = 0; i < nb_ifreq ; i++) {
3227 thunk_convert(argptr + i * target_ifreq_size,
3228 host_ifc_buf + i * sizeof(struct ifreq),
3229 ifreq_arg_type, THUNK_TARGET);
3230 }
3231 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3232 }
3233
3234 if (free_buf) {
3235 free(host_ifconf);
3236 }
3237
3238 return ret;
3239}
3240
blueswir19f106a72008-10-05 10:52:52 +00003241static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003242#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003243 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3244#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3245 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003246#include "ioctls.h"
3247 { 0, 0, },
3248};
3249
pbrook53a59602006-03-25 19:31:22 +00003250/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003251/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003252static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003253{
3254 const IOCTLEntry *ie;
3255 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003256 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003257 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003258 int target_size;
3259 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003260
3261 ie = ioctl_entries;
3262 for(;;) {
3263 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003264 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003265 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003266 }
3267 if (ie->target_cmd == cmd)
3268 break;
3269 ie++;
3270 }
3271 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003272#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003273 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003274#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003275 if (ie->do_ioctl) {
3276 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3277 }
3278
bellard31e31b82003-02-18 22:55:36 +00003279 switch(arg_type[0]) {
3280 case TYPE_NULL:
3281 /* no argument */
3282 ret = get_errno(ioctl(fd, ie->host_cmd));
3283 break;
3284 case TYPE_PTRVOID:
3285 case TYPE_INT:
3286 /* int argment */
3287 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3288 break;
3289 case TYPE_PTR:
3290 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003291 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003292 switch(ie->access) {
3293 case IOC_R:
3294 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3295 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003296 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3297 if (!argptr)
3298 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003299 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3300 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003301 }
3302 break;
3303 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003304 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3305 if (!argptr)
3306 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003307 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3308 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003309 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3310 break;
3311 default:
3312 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003313 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3314 if (!argptr)
3315 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003316 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3317 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003318 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3319 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003320 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3321 if (!argptr)
3322 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003323 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3324 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003325 }
3326 break;
3327 }
3328 break;
3329 default:
j_mayer32407102007-09-26 23:01:49 +00003330 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3331 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003332 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003333 break;
3334 }
3335 return ret;
3336}
3337
blueswir1b39bc502008-10-05 10:51:10 +00003338static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003339 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3340 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3341 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3342 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3343 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3344 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3345 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3346 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3347 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3348 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3349 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3350 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3351 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3352 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3353 { 0, 0, 0, 0 }
3354};
3355
blueswir1b39bc502008-10-05 10:51:10 +00003356static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003357 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3358 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3359 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3360 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3361 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3362 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3363 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3364 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3365 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3366 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3367 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3368 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3369 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3370 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3371 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3372 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3373 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3374 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3375 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3376 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3377 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3378 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3379 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3380 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3381 { 0, 0, 0, 0 }
3382};
3383
blueswir1b39bc502008-10-05 10:51:10 +00003384static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003385 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3386 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3387 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3388 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3389 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3390 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3391 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3392 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3393 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3394 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3395 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3396 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3397 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3398 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3399 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3400 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3401 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3402 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3403 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3404 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3405 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3406 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3407 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3408 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3409 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3410 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3411 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3412 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3413 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3414 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3415 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3416 { 0, 0, 0, 0 }
3417};
3418
blueswir1b39bc502008-10-05 10:51:10 +00003419static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003420 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3421 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3422 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3423 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3424 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3425 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3426 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3427 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3428 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3429 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3430 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3431 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3432 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3433 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3434 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3435 { 0, 0, 0, 0 }
3436};
3437
3438static void target_to_host_termios (void *dst, const void *src)
3439{
3440 struct host_termios *host = dst;
3441 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003442
ths5fafdf22007-09-16 21:08:06 +00003443 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003444 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003445 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003446 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003447 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003448 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003449 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003450 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3451 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003452
Arnaud Patard44607122009-04-21 17:39:08 +03003453 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003454 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3455 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003456 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003457 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003458 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003459 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003460 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003461 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003462 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003463 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3464 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003465 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3466 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3467 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3468 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3469 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003470 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003471}
ths3b46e622007-09-17 08:09:54 +00003472
bellard31e31b82003-02-18 22:55:36 +00003473static void host_to_target_termios (void *dst, const void *src)
3474{
3475 struct target_termios *target = dst;
3476 const struct host_termios *host = src;
3477
ths5fafdf22007-09-16 21:08:06 +00003478 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003479 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003480 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003481 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003482 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003483 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003484 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003485 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3486 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003487
Arnaud Patard44607122009-04-21 17:39:08 +03003488 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003489 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3490 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3491 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3492 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3493 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3494 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3495 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3496 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3497 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3498 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3499 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3500 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3501 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3502 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3503 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3504 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3505 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3506}
3507
blueswir18e853dc2008-10-05 10:49:32 +00003508static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003509 .convert = { host_to_target_termios, target_to_host_termios },
3510 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3511 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3512};
3513
bellard5286db72003-06-05 00:57:30 +00003514static bitmask_transtbl mmap_flags_tbl[] = {
3515 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3516 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3517 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3518 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3519 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3520 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3521 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3522 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3523 { 0, 0, 0, 0 }
3524};
3525
bellard2ab83ea2003-06-15 19:56:46 +00003526#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003527
3528/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003529static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003530
bellard03acab62007-11-11 14:57:14 +00003531static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003532{
3533 int size;
pbrook53a59602006-03-25 19:31:22 +00003534 void *p;
bellard6dbad632003-03-16 18:05:05 +00003535
3536 if (!ldt_table)
3537 return 0;
3538 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3539 if (size > bytecount)
3540 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003541 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3542 if (!p)
bellard03acab62007-11-11 14:57:14 +00003543 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003544 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003545 memcpy(p, ldt_table, size);
3546 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003547 return size;
3548}
3549
3550/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003551static abi_long write_ldt(CPUX86State *env,
3552 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003553{
3554 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003555 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003556 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003557 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003558 uint32_t *lp, entry_1, entry_2;
3559
3560 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003561 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003562 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003563 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003564 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3565 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3566 ldt_info.limit = tswap32(target_ldt_info->limit);
3567 ldt_info.flags = tswap32(target_ldt_info->flags);
3568 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003569
bellard6dbad632003-03-16 18:05:05 +00003570 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003571 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003572 seg_32bit = ldt_info.flags & 1;
3573 contents = (ldt_info.flags >> 1) & 3;
3574 read_exec_only = (ldt_info.flags >> 3) & 1;
3575 limit_in_pages = (ldt_info.flags >> 4) & 1;
3576 seg_not_present = (ldt_info.flags >> 5) & 1;
3577 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003578#ifdef TARGET_ABI32
3579 lm = 0;
3580#else
3581 lm = (ldt_info.flags >> 7) & 1;
3582#endif
bellard6dbad632003-03-16 18:05:05 +00003583 if (contents == 3) {
3584 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003585 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003586 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003587 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003588 }
3589 /* allocate the LDT */
3590 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003591 env->ldt.base = target_mmap(0,
3592 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3593 PROT_READ|PROT_WRITE,
3594 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3595 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003596 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003597 memset(g2h(env->ldt.base), 0,
3598 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003599 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003600 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003601 }
3602
3603 /* NOTE: same code as Linux kernel */
3604 /* Allow LDTs to be cleared by the user. */
3605 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3606 if (oldmode ||
3607 (contents == 0 &&
3608 read_exec_only == 1 &&
3609 seg_32bit == 0 &&
3610 limit_in_pages == 0 &&
3611 seg_not_present == 1 &&
3612 useable == 0 )) {
3613 entry_1 = 0;
3614 entry_2 = 0;
3615 goto install;
3616 }
3617 }
ths3b46e622007-09-17 08:09:54 +00003618
bellard6dbad632003-03-16 18:05:05 +00003619 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3620 (ldt_info.limit & 0x0ffff);
3621 entry_2 = (ldt_info.base_addr & 0xff000000) |
3622 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3623 (ldt_info.limit & 0xf0000) |
3624 ((read_exec_only ^ 1) << 9) |
3625 (contents << 10) |
3626 ((seg_not_present ^ 1) << 15) |
3627 (seg_32bit << 22) |
3628 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003629 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003630 0x7000;
3631 if (!oldmode)
3632 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003633
bellard6dbad632003-03-16 18:05:05 +00003634 /* Install the new entry ... */
3635install:
3636 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3637 lp[0] = tswap32(entry_1);
3638 lp[1] = tswap32(entry_2);
3639 return 0;
3640}
3641
3642/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003643static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3644 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003645{
bellard03acab62007-11-11 14:57:14 +00003646 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003647
bellard6dbad632003-03-16 18:05:05 +00003648 switch (func) {
3649 case 0:
3650 ret = read_ldt(ptr, bytecount);
3651 break;
3652 case 1:
3653 ret = write_ldt(env, ptr, bytecount, 1);
3654 break;
3655 case 0x11:
3656 ret = write_ldt(env, ptr, bytecount, 0);
3657 break;
bellard03acab62007-11-11 14:57:14 +00003658 default:
3659 ret = -TARGET_ENOSYS;
3660 break;
bellard6dbad632003-03-16 18:05:05 +00003661 }
3662 return ret;
3663}
bellard1b6b0292003-03-22 17:31:38 +00003664
blueswir14583f582008-08-24 10:35:55 +00003665#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003666static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003667{
3668 uint64_t *gdt_table = g2h(env->gdt.base);
3669 struct target_modify_ldt_ldt_s ldt_info;
3670 struct target_modify_ldt_ldt_s *target_ldt_info;
3671 int seg_32bit, contents, read_exec_only, limit_in_pages;
3672 int seg_not_present, useable, lm;
3673 uint32_t *lp, entry_1, entry_2;
3674 int i;
3675
3676 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3677 if (!target_ldt_info)
3678 return -TARGET_EFAULT;
3679 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3680 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3681 ldt_info.limit = tswap32(target_ldt_info->limit);
3682 ldt_info.flags = tswap32(target_ldt_info->flags);
3683 if (ldt_info.entry_number == -1) {
3684 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3685 if (gdt_table[i] == 0) {
3686 ldt_info.entry_number = i;
3687 target_ldt_info->entry_number = tswap32(i);
3688 break;
3689 }
3690 }
3691 }
3692 unlock_user_struct(target_ldt_info, ptr, 1);
3693
3694 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
3695 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
3696 return -TARGET_EINVAL;
3697 seg_32bit = ldt_info.flags & 1;
3698 contents = (ldt_info.flags >> 1) & 3;
3699 read_exec_only = (ldt_info.flags >> 3) & 1;
3700 limit_in_pages = (ldt_info.flags >> 4) & 1;
3701 seg_not_present = (ldt_info.flags >> 5) & 1;
3702 useable = (ldt_info.flags >> 6) & 1;
3703#ifdef TARGET_ABI32
3704 lm = 0;
3705#else
3706 lm = (ldt_info.flags >> 7) & 1;
3707#endif
3708
3709 if (contents == 3) {
3710 if (seg_not_present == 0)
3711 return -TARGET_EINVAL;
3712 }
3713
3714 /* NOTE: same code as Linux kernel */
3715 /* Allow LDTs to be cleared by the user. */
3716 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3717 if ((contents == 0 &&
3718 read_exec_only == 1 &&
3719 seg_32bit == 0 &&
3720 limit_in_pages == 0 &&
3721 seg_not_present == 1 &&
3722 useable == 0 )) {
3723 entry_1 = 0;
3724 entry_2 = 0;
3725 goto install;
3726 }
3727 }
3728
3729 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3730 (ldt_info.limit & 0x0ffff);
3731 entry_2 = (ldt_info.base_addr & 0xff000000) |
3732 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3733 (ldt_info.limit & 0xf0000) |
3734 ((read_exec_only ^ 1) << 9) |
3735 (contents << 10) |
3736 ((seg_not_present ^ 1) << 15) |
3737 (seg_32bit << 22) |
3738 (limit_in_pages << 23) |
3739 (useable << 20) |
3740 (lm << 21) |
3741 0x7000;
3742
3743 /* Install the new entry ... */
3744install:
3745 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
3746 lp[0] = tswap32(entry_1);
3747 lp[1] = tswap32(entry_2);
3748 return 0;
3749}
3750
blueswir18fcd3692008-08-17 20:26:25 +00003751static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003752{
3753 struct target_modify_ldt_ldt_s *target_ldt_info;
3754 uint64_t *gdt_table = g2h(env->gdt.base);
3755 uint32_t base_addr, limit, flags;
3756 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
3757 int seg_not_present, useable, lm;
3758 uint32_t *lp, entry_1, entry_2;
3759
3760 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3761 if (!target_ldt_info)
3762 return -TARGET_EFAULT;
3763 idx = tswap32(target_ldt_info->entry_number);
3764 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
3765 idx > TARGET_GDT_ENTRY_TLS_MAX) {
3766 unlock_user_struct(target_ldt_info, ptr, 1);
3767 return -TARGET_EINVAL;
3768 }
3769 lp = (uint32_t *)(gdt_table + idx);
3770 entry_1 = tswap32(lp[0]);
3771 entry_2 = tswap32(lp[1]);
3772
3773 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
3774 contents = (entry_2 >> 10) & 3;
3775 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
3776 seg_32bit = (entry_2 >> 22) & 1;
3777 limit_in_pages = (entry_2 >> 23) & 1;
3778 useable = (entry_2 >> 20) & 1;
3779#ifdef TARGET_ABI32
3780 lm = 0;
3781#else
3782 lm = (entry_2 >> 21) & 1;
3783#endif
3784 flags = (seg_32bit << 0) | (contents << 1) |
3785 (read_exec_only << 3) | (limit_in_pages << 4) |
3786 (seg_not_present << 5) | (useable << 6) | (lm << 7);
3787 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
3788 base_addr = (entry_1 >> 16) |
3789 (entry_2 & 0xff000000) |
3790 ((entry_2 & 0xff) << 16);
3791 target_ldt_info->base_addr = tswapl(base_addr);
3792 target_ldt_info->limit = tswap32(limit);
3793 target_ldt_info->flags = tswap32(flags);
3794 unlock_user_struct(target_ldt_info, ptr, 1);
3795 return 0;
3796}
blueswir14583f582008-08-24 10:35:55 +00003797#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00003798
bellardd2fd1af2007-11-14 18:08:56 +00003799#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00003800static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00003801{
Juan Quintela1add8692011-06-16 17:37:09 +01003802 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00003803 abi_ulong val;
3804 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01003805
bellardd2fd1af2007-11-14 18:08:56 +00003806 switch(code) {
3807 case TARGET_ARCH_SET_GS:
3808 case TARGET_ARCH_SET_FS:
3809 if (code == TARGET_ARCH_SET_GS)
3810 idx = R_GS;
3811 else
3812 idx = R_FS;
3813 cpu_x86_load_seg(env, idx, 0);
3814 env->segs[idx].base = addr;
3815 break;
3816 case TARGET_ARCH_GET_GS:
3817 case TARGET_ARCH_GET_FS:
3818 if (code == TARGET_ARCH_GET_GS)
3819 idx = R_GS;
3820 else
3821 idx = R_FS;
3822 val = env->segs[idx].base;
3823 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01003824 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00003825 break;
3826 default:
3827 ret = -TARGET_EINVAL;
3828 break;
3829 }
Juan Quintela1add8692011-06-16 17:37:09 +01003830 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00003831}
3832#endif
3833
bellard2ab83ea2003-06-15 19:56:46 +00003834#endif /* defined(TARGET_I386) */
3835
Riku Voipio05098a92011-03-04 15:27:29 +02003836#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00003837
Riku Voipio05098a92011-03-04 15:27:29 +02003838#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003839
3840static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
3841typedef struct {
3842 CPUState *env;
3843 pthread_mutex_t mutex;
3844 pthread_cond_t cond;
3845 pthread_t thread;
3846 uint32_t tid;
3847 abi_ulong child_tidptr;
3848 abi_ulong parent_tidptr;
3849 sigset_t sigmask;
3850} new_thread_info;
3851
3852static void *clone_func(void *arg)
3853{
3854 new_thread_info *info = arg;
3855 CPUState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003856 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00003857
3858 env = info->env;
3859 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003860 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00003861 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07003862 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003863 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00003864 if (info->child_tidptr)
3865 put_user_u32(info->tid, info->child_tidptr);
3866 if (info->parent_tidptr)
3867 put_user_u32(info->tid, info->parent_tidptr);
3868 /* Enable signals. */
3869 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
3870 /* Signal to the parent that we're ready. */
3871 pthread_mutex_lock(&info->mutex);
3872 pthread_cond_broadcast(&info->cond);
3873 pthread_mutex_unlock(&info->mutex);
3874 /* Wait until the parent has finshed initializing the tls state. */
3875 pthread_mutex_lock(&clone_lock);
3876 pthread_mutex_unlock(&clone_lock);
3877 cpu_loop(env);
3878 /* never exits */
3879 return NULL;
3880}
3881#else
bellard1b6b0292003-03-22 17:31:38 +00003882
3883static int clone_func(void *arg)
3884{
bellard2ab83ea2003-06-15 19:56:46 +00003885 CPUState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00003886 cpu_loop(env);
3887 /* never exits */
3888 return 0;
3889}
pbrookd865bab2008-06-07 22:12:17 +00003890#endif
bellard1b6b0292003-03-22 17:31:38 +00003891
ths0da46a62007-10-20 20:23:07 +00003892/* do_fork() Must return host values and target errnos (unlike most
3893 do_*() functions). */
pbrookd865bab2008-06-07 22:12:17 +00003894static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3895 abi_ulong parent_tidptr, target_ulong newtls,
3896 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00003897{
3898 int ret;
bellard5cd43932003-03-29 16:54:36 +00003899 TaskState *ts;
bellard2ab83ea2003-06-15 19:56:46 +00003900 CPUState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003901#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003902 unsigned int nptl_flags;
3903 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02003904#else
3905 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00003906#endif
ths3b46e622007-09-17 08:09:54 +00003907
balrog436d1242008-09-21 02:39:45 +00003908 /* Emulate vfork() with fork() */
3909 if (flags & CLONE_VFORK)
3910 flags &= ~(CLONE_VFORK | CLONE_VM);
3911
bellard1b6b0292003-03-22 17:31:38 +00003912 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003913 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003914#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003915 new_thread_info info;
3916 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00003917#endif
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003918 ts = qemu_mallocz(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00003919 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00003920 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00003921 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00003922#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3923 cpu_reset(new_env);
3924#endif
pbrook6e68e072008-05-30 17:22:15 +00003925 /* Init regs that differ from the parent. */
3926 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00003927 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003928 ts->bprm = parent_ts->bprm;
3929 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003930#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003931 nptl_flags = flags;
3932 flags &= ~CLONE_NPTL_FLAGS2;
3933
pbrookc2764712009-03-07 15:24:59 +00003934 if (nptl_flags & CLONE_CHILD_CLEARTID) {
3935 ts->child_tidptr = child_tidptr;
3936 }
3937
pbrookd865bab2008-06-07 22:12:17 +00003938 if (nptl_flags & CLONE_SETTLS)
3939 cpu_set_tls (new_env, newtls);
3940
3941 /* Grab a mutex so that thread setup appears atomic. */
3942 pthread_mutex_lock(&clone_lock);
3943
3944 memset(&info, 0, sizeof(info));
3945 pthread_mutex_init(&info.mutex, NULL);
3946 pthread_mutex_lock(&info.mutex);
3947 pthread_cond_init(&info.cond, NULL);
3948 info.env = new_env;
3949 if (nptl_flags & CLONE_CHILD_SETTID)
3950 info.child_tidptr = child_tidptr;
3951 if (nptl_flags & CLONE_PARENT_SETTID)
3952 info.parent_tidptr = parent_tidptr;
3953
3954 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003955 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
3956 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00003957 /* It is not safe to deliver signals until the child has finished
3958 initializing, so temporarily block all signals. */
3959 sigfillset(&sigmask);
3960 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
3961
3962 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00003963 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00003964
3965 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
3966 pthread_attr_destroy(&attr);
3967 if (ret == 0) {
3968 /* Wait for the child to initialize. */
3969 pthread_cond_wait(&info.cond, &info.mutex);
3970 ret = info.tid;
3971 if (flags & CLONE_PARENT_SETTID)
3972 put_user_u32(ret, parent_tidptr);
3973 } else {
3974 ret = -1;
3975 }
3976 pthread_mutex_unlock(&info.mutex);
3977 pthread_cond_destroy(&info.cond);
3978 pthread_mutex_destroy(&info.mutex);
3979 pthread_mutex_unlock(&clone_lock);
3980#else
3981 if (flags & CLONE_NPTL_FLAGS2)
3982 return -EINVAL;
3983 /* This is probably going to die very quickly, but do it anyway. */
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003984 new_stack = qemu_mallocz (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00003985#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02003986 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00003987#else
3988 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
3989#endif
pbrookd865bab2008-06-07 22:12:17 +00003990#endif
bellard1b6b0292003-03-22 17:31:38 +00003991 } else {
3992 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00003993 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00003994 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00003995 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00003996 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00003997 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00003998 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00003999 cpu_clone_regs(env, newsp);
4000 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004001#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004002 /* There is a race condition here. The parent process could
4003 theoretically read the TID in the child process before the child
4004 tid is set. This would require using either ptrace
4005 (not implemented) or having *_tidptr to point at a shared memory
4006 mapping. We can't repeat the spinlock hack used above because
4007 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004008 if (flags & CLONE_CHILD_SETTID)
4009 put_user_u32(gettid(), child_tidptr);
4010 if (flags & CLONE_PARENT_SETTID)
4011 put_user_u32(gettid(), parent_tidptr);
4012 ts = (TaskState *)env->opaque;
4013 if (flags & CLONE_SETTLS)
4014 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004015 if (flags & CLONE_CHILD_CLEARTID)
4016 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004017#endif
pbrookd865bab2008-06-07 22:12:17 +00004018 } else {
4019 fork_end(0);
4020 }
bellard1b6b0292003-03-22 17:31:38 +00004021 }
4022 return ret;
4023}
4024
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004025/* warning : doesn't handle linux specific flags... */
4026static int target_to_host_fcntl_cmd(int cmd)
4027{
4028 switch(cmd) {
4029 case TARGET_F_DUPFD:
4030 case TARGET_F_GETFD:
4031 case TARGET_F_SETFD:
4032 case TARGET_F_GETFL:
4033 case TARGET_F_SETFL:
4034 return cmd;
4035 case TARGET_F_GETLK:
4036 return F_GETLK;
4037 case TARGET_F_SETLK:
4038 return F_SETLK;
4039 case TARGET_F_SETLKW:
4040 return F_SETLKW;
4041 case TARGET_F_GETOWN:
4042 return F_GETOWN;
4043 case TARGET_F_SETOWN:
4044 return F_SETOWN;
4045 case TARGET_F_GETSIG:
4046 return F_GETSIG;
4047 case TARGET_F_SETSIG:
4048 return F_SETSIG;
4049#if TARGET_ABI_BITS == 32
4050 case TARGET_F_GETLK64:
4051 return F_GETLK64;
4052 case TARGET_F_SETLK64:
4053 return F_SETLK64;
4054 case TARGET_F_SETLKW64:
4055 return F_SETLKW64;
4056#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004057 case TARGET_F_SETLEASE:
4058 return F_SETLEASE;
4059 case TARGET_F_GETLEASE:
4060 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004061#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004062 case TARGET_F_DUPFD_CLOEXEC:
4063 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004064#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004065 case TARGET_F_NOTIFY:
4066 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004067 default:
4068 return -TARGET_EINVAL;
4069 }
4070 return -TARGET_EINVAL;
4071}
4072
blueswir1992f48a2007-10-14 16:27:31 +00004073static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004074{
4075 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004076 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004077 struct flock64 fl64;
4078 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004079 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004080 int host_cmd = target_to_host_fcntl_cmd(cmd);
4081
4082 if (host_cmd == -TARGET_EINVAL)
4083 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004084
bellard7775e9e2003-05-14 22:46:48 +00004085 switch(cmd) {
4086 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004087 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4088 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004089 fl.l_type = tswap16(target_fl->l_type);
4090 fl.l_whence = tswap16(target_fl->l_whence);
4091 fl.l_start = tswapl(target_fl->l_start);
4092 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004093 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004094 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004095 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004096 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004097 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4098 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004099 target_fl->l_type = tswap16(fl.l_type);
4100 target_fl->l_whence = tswap16(fl.l_whence);
4101 target_fl->l_start = tswapl(fl.l_start);
4102 target_fl->l_len = tswapl(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004103 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004104 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004105 }
4106 break;
ths3b46e622007-09-17 08:09:54 +00004107
bellard7775e9e2003-05-14 22:46:48 +00004108 case TARGET_F_SETLK:
4109 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004110 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4111 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004112 fl.l_type = tswap16(target_fl->l_type);
4113 fl.l_whence = tswap16(target_fl->l_whence);
4114 fl.l_start = tswapl(target_fl->l_start);
4115 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004116 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004117 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004118 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004119 break;
ths3b46e622007-09-17 08:09:54 +00004120
bellard7775e9e2003-05-14 22:46:48 +00004121 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004122 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4123 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004124 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4125 fl64.l_whence = tswap16(target_fl64->l_whence);
4126 fl64.l_start = tswapl(target_fl64->l_start);
4127 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004128 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004129 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004130 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004131 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004132 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4133 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004134 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4135 target_fl64->l_whence = tswap16(fl64.l_whence);
4136 target_fl64->l_start = tswapl(fl64.l_start);
4137 target_fl64->l_len = tswapl(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004138 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004139 unlock_user_struct(target_fl64, arg, 1);
4140 }
bellard9ee1fa22007-11-11 15:11:19 +00004141 break;
bellard7775e9e2003-05-14 22:46:48 +00004142 case TARGET_F_SETLK64:
4143 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004144 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4145 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004146 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4147 fl64.l_whence = tswap16(target_fl64->l_whence);
4148 fl64.l_start = tswapl(target_fl64->l_start);
4149 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004150 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004151 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004152 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004153 break;
4154
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004155 case TARGET_F_GETFL:
4156 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004157 if (ret >= 0) {
4158 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4159 }
bellardffa65c32004-01-04 23:57:22 +00004160 break;
4161
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004162 case TARGET_F_SETFL:
4163 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4164 break;
4165
4166 case TARGET_F_SETOWN:
4167 case TARGET_F_GETOWN:
4168 case TARGET_F_SETSIG:
4169 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004170 case TARGET_F_SETLEASE:
4171 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004172 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004173 break;
4174
bellard7775e9e2003-05-14 22:46:48 +00004175 default:
bellard9ee1fa22007-11-11 15:11:19 +00004176 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004177 break;
4178 }
4179 return ret;
4180}
4181
bellard67867302003-11-23 17:05:30 +00004182#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004183
bellard67867302003-11-23 17:05:30 +00004184static inline int high2lowuid(int uid)
4185{
4186 if (uid > 65535)
4187 return 65534;
4188 else
4189 return uid;
4190}
4191
4192static inline int high2lowgid(int gid)
4193{
4194 if (gid > 65535)
4195 return 65534;
4196 else
4197 return gid;
4198}
4199
4200static inline int low2highuid(int uid)
4201{
4202 if ((int16_t)uid == -1)
4203 return -1;
4204 else
4205 return uid;
4206}
4207
4208static inline int low2highgid(int gid)
4209{
4210 if ((int16_t)gid == -1)
4211 return -1;
4212 else
4213 return gid;
4214}
Riku Voipio0c866a72011-04-18 15:23:06 +03004215static inline int tswapid(int id)
4216{
4217 return tswap16(id);
4218}
4219#else /* !USE_UID16 */
4220static inline int high2lowuid(int uid)
4221{
4222 return uid;
4223}
4224static inline int high2lowgid(int gid)
4225{
4226 return gid;
4227}
4228static inline int low2highuid(int uid)
4229{
4230 return uid;
4231}
4232static inline int low2highgid(int gid)
4233{
4234 return gid;
4235}
4236static inline int tswapid(int id)
4237{
4238 return tswap32(id);
4239}
bellard67867302003-11-23 17:05:30 +00004240#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004241
bellard31e31b82003-02-18 22:55:36 +00004242void syscall_init(void)
4243{
bellard2ab83ea2003-06-15 19:56:46 +00004244 IOCTLEntry *ie;
4245 const argtype *arg_type;
4246 int size;
thsb92c47c2007-11-01 00:07:38 +00004247 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004248
Blue Swirl001faf32009-05-13 17:53:17 +00004249#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004250#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004251#include "syscall_types.h"
4252#undef STRUCT
4253#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004254
4255 /* we patch the ioctl size if necessary. We rely on the fact that
4256 no ioctl has all the bits at '1' in the size field */
4257 ie = ioctl_entries;
4258 while (ie->target_cmd != 0) {
4259 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4260 TARGET_IOC_SIZEMASK) {
4261 arg_type = ie->arg_type;
4262 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004263 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004264 ie->target_cmd);
4265 exit(1);
4266 }
4267 arg_type++;
4268 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004269 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004270 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4271 (size << TARGET_IOC_SIZESHIFT);
4272 }
thsb92c47c2007-11-01 00:07:38 +00004273
4274 /* Build target_to_host_errno_table[] table from
4275 * host_to_target_errno_table[]. */
4276 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4277 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4278
bellard2ab83ea2003-06-15 19:56:46 +00004279 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004280#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4281 (defined(__x86_64__) && defined(TARGET_X86_64))
4282 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4283 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4284 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004285 }
4286#endif
4287 ie++;
4288 }
bellard31e31b82003-02-18 22:55:36 +00004289}
bellardc573ff62004-01-04 15:51:36 +00004290
blueswir1992f48a2007-10-14 16:27:31 +00004291#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004292static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4293{
thsaf325d32008-06-10 15:29:15 +00004294#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004295 return ((uint64_t)word0 << 32) | word1;
4296#else
4297 return ((uint64_t)word1 << 32) | word0;
4298#endif
4299}
blueswir1992f48a2007-10-14 16:27:31 +00004300#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004301static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4302{
4303 return word0;
4304}
blueswir1992f48a2007-10-14 16:27:31 +00004305#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004306
4307#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004308static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4309 abi_long arg2,
4310 abi_long arg3,
4311 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004312{
4313#ifdef TARGET_ARM
4314 if (((CPUARMState *)cpu_env)->eabi)
4315 {
4316 arg2 = arg3;
4317 arg3 = arg4;
4318 }
4319#endif
4320 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4321}
4322#endif
4323
4324#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004325static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4326 abi_long arg2,
4327 abi_long arg3,
4328 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004329{
4330#ifdef TARGET_ARM
4331 if (((CPUARMState *)cpu_env)->eabi)
4332 {
4333 arg2 = arg3;
4334 arg3 = arg4;
4335 }
4336#endif
4337 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4338}
4339#endif
4340
bellard579a97f2007-11-11 14:26:47 +00004341static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4342 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004343{
4344 struct target_timespec *target_ts;
4345
bellard579a97f2007-11-11 14:26:47 +00004346 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4347 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004348 host_ts->tv_sec = tswapl(target_ts->tv_sec);
4349 host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
4350 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004351 return 0;
pbrook53a59602006-03-25 19:31:22 +00004352}
4353
bellard579a97f2007-11-11 14:26:47 +00004354static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4355 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004356{
4357 struct target_timespec *target_ts;
4358
bellard579a97f2007-11-11 14:26:47 +00004359 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4360 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004361 target_ts->tv_sec = tswapl(host_ts->tv_sec);
4362 target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
4363 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004364 return 0;
pbrook53a59602006-03-25 19:31:22 +00004365}
4366
aurel329d33b762009-04-08 23:07:05 +00004367#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004368static inline abi_long host_to_target_stat64(void *cpu_env,
4369 abi_ulong target_addr,
4370 struct stat *host_st)
4371{
4372#ifdef TARGET_ARM
4373 if (((CPUARMState *)cpu_env)->eabi) {
4374 struct target_eabi_stat64 *target_st;
4375
4376 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4377 return -TARGET_EFAULT;
4378 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4379 __put_user(host_st->st_dev, &target_st->st_dev);
4380 __put_user(host_st->st_ino, &target_st->st_ino);
4381#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4382 __put_user(host_st->st_ino, &target_st->__st_ino);
4383#endif
4384 __put_user(host_st->st_mode, &target_st->st_mode);
4385 __put_user(host_st->st_nlink, &target_st->st_nlink);
4386 __put_user(host_st->st_uid, &target_st->st_uid);
4387 __put_user(host_st->st_gid, &target_st->st_gid);
4388 __put_user(host_st->st_rdev, &target_st->st_rdev);
4389 __put_user(host_st->st_size, &target_st->st_size);
4390 __put_user(host_st->st_blksize, &target_st->st_blksize);
4391 __put_user(host_st->st_blocks, &target_st->st_blocks);
4392 __put_user(host_st->st_atime, &target_st->target_st_atime);
4393 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4394 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4395 unlock_user_struct(target_st, target_addr, 1);
4396 } else
4397#endif
4398 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004399#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004400 struct target_stat *target_st;
4401#else
balrog6a24a772008-09-20 02:23:36 +00004402 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004403#endif
balrog6a24a772008-09-20 02:23:36 +00004404
4405 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4406 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004407 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004408 __put_user(host_st->st_dev, &target_st->st_dev);
4409 __put_user(host_st->st_ino, &target_st->st_ino);
4410#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4411 __put_user(host_st->st_ino, &target_st->__st_ino);
4412#endif
4413 __put_user(host_st->st_mode, &target_st->st_mode);
4414 __put_user(host_st->st_nlink, &target_st->st_nlink);
4415 __put_user(host_st->st_uid, &target_st->st_uid);
4416 __put_user(host_st->st_gid, &target_st->st_gid);
4417 __put_user(host_st->st_rdev, &target_st->st_rdev);
4418 /* XXX: better use of kernel struct */
4419 __put_user(host_st->st_size, &target_st->st_size);
4420 __put_user(host_st->st_blksize, &target_st->st_blksize);
4421 __put_user(host_st->st_blocks, &target_st->st_blocks);
4422 __put_user(host_st->st_atime, &target_st->target_st_atime);
4423 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4424 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4425 unlock_user_struct(target_st, target_addr, 1);
4426 }
4427
4428 return 0;
4429}
4430#endif
4431
Juan Quintela2f7bb872009-07-27 16:13:24 +02004432#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004433/* ??? Using host futex calls even when target atomic operations
4434 are not really atomic probably breaks things. However implementing
4435 futexes locally would make futexes shared between multiple processes
4436 tricky. However they're probably useless because guest atomic
4437 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004438static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4439 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004440{
4441 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004442 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004443
4444 /* ??? We assume FUTEX_* constants are the same on both host
4445 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004446#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004447 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004448#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004449 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004450#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004451 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004452 case FUTEX_WAIT:
4453 if (timeout) {
4454 pts = &ts;
4455 target_to_host_timespec(pts, timeout);
4456 } else {
4457 pts = NULL;
4458 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004459 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004460 pts, NULL, 0));
4461 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004462 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004463 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004464 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004465 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004466 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004467 case FUTEX_WAKE_OP:
4468 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4469 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4470 But the prototype takes a `struct timespec *'; insert casts
4471 to satisfy the compiler. We do not need to tswap TIMEOUT
4472 since it's not compared to guest memory. */
4473 pts = (struct timespec *)(uintptr_t) timeout;
4474 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4475 g2h(uaddr2),
4476 (base_op == FUTEX_CMP_REQUEUE
4477 ? tswap32(val3)
4478 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004479 default:
4480 return -TARGET_ENOSYS;
4481 }
4482}
4483#endif
4484
pbrook1d9d8b52009-04-16 15:17:02 +00004485/* Map host to target signal numbers for the wait family of syscalls.
4486 Assume all other status bits are the same. */
4487static int host_to_target_waitstatus(int status)
4488{
4489 if (WIFSIGNALED(status)) {
4490 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4491 }
4492 if (WIFSTOPPED(status)) {
4493 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4494 | (status & 0xff);
4495 }
4496 return status;
4497}
4498
pbrooka745ec62008-05-06 15:36:17 +00004499int get_osversion(void)
4500{
4501 static int osversion;
4502 struct new_utsname buf;
4503 const char *s;
4504 int i, n, tmp;
4505 if (osversion)
4506 return osversion;
4507 if (qemu_uname_release && *qemu_uname_release) {
4508 s = qemu_uname_release;
4509 } else {
4510 if (sys_uname(&buf))
4511 return 0;
4512 s = buf.release;
4513 }
4514 tmp = 0;
4515 for (i = 0; i < 3; i++) {
4516 n = 0;
4517 while (*s >= '0' && *s <= '9') {
4518 n *= 10;
4519 n += *s - '0';
4520 s++;
4521 }
4522 tmp = (tmp << 8) + n;
4523 if (*s == '.')
4524 s++;
4525 }
4526 osversion = tmp;
4527 return osversion;
4528}
4529
ths0da46a62007-10-20 20:23:07 +00004530/* do_syscall() should always have a single exit point at the end so
4531 that actions, such as logging of syscall results, can be performed.
4532 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004533abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4534 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004535 abi_long arg5, abi_long arg6, abi_long arg7,
4536 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00004537{
blueswir1992f48a2007-10-14 16:27:31 +00004538 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004539 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004540 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004541 void *p;
ths3b46e622007-09-17 08:09:54 +00004542
bellard72f03902003-02-18 23:33:18 +00004543#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00004544 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00004545#endif
thsb92c47c2007-11-01 00:07:38 +00004546 if(do_strace)
4547 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
4548
bellard31e31b82003-02-18 22:55:36 +00004549 switch(num) {
4550 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02004551#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00004552 /* In old applications this may be used to implement _exit(2).
4553 However in threaded applictions it is used for thread termination,
4554 and _exit_group is used for application termination.
4555 Do thread termination if we have more then one thread. */
4556 /* FIXME: This probably breaks if a signal arrives. We should probably
4557 be disabling signals. */
4558 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004559 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00004560 CPUState **lastp;
4561 CPUState *p;
4562
4563 cpu_list_lock();
4564 lastp = &first_cpu;
4565 p = first_cpu;
4566 while (p && p != (CPUState *)cpu_env) {
4567 lastp = &p->next_cpu;
4568 p = p->next_cpu;
4569 }
4570 /* If we didn't find the CPU for this thread then something is
4571 horribly wrong. */
4572 if (!p)
4573 abort();
4574 /* Remove the CPU from the list. */
4575 *lastp = p->next_cpu;
4576 cpu_list_unlock();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004577 ts = ((CPUState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00004578 if (ts->child_tidptr) {
4579 put_user_u32(0, ts->child_tidptr);
4580 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
4581 NULL, NULL, 0);
4582 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004583 thread_env = NULL;
4584 qemu_free(cpu_env);
4585 qemu_free(ts);
pbrookc2764712009-03-07 15:24:59 +00004586 pthread_exit(NULL);
4587 }
4588#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02004589#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00004590 _mcleanup();
4591#endif
bellarde9009672005-04-26 20:42:36 +00004592 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00004593 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00004594 ret = 0; /* avoid warning */
4595 break;
4596 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00004597 if (arg3 == 0)
4598 ret = 0;
4599 else {
4600 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
4601 goto efault;
4602 ret = get_errno(read(arg1, p, arg3));
4603 unlock_user(p, arg2, ret);
4604 }
bellard31e31b82003-02-18 22:55:36 +00004605 break;
4606 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00004607 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
4608 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004609 ret = get_errno(write(arg1, p, arg3));
4610 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00004611 break;
4612 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00004613 if (!(p = lock_user_string(arg1)))
4614 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004615 ret = get_errno(open(path(p),
bellardffa65c32004-01-04 23:57:22 +00004616 target_to_host_bitmask(arg2, fcntl_flags_tbl),
4617 arg3));
pbrook53a59602006-03-25 19:31:22 +00004618 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004619 break;
ths82424832007-09-24 09:21:55 +00004620#if defined(TARGET_NR_openat) && defined(__NR_openat)
4621 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00004622 if (!(p = lock_user_string(arg2)))
4623 goto efault;
4624 ret = get_errno(sys_openat(arg1,
4625 path(p),
4626 target_to_host_bitmask(arg3, fcntl_flags_tbl),
4627 arg4));
4628 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00004629 break;
4630#endif
bellard31e31b82003-02-18 22:55:36 +00004631 case TARGET_NR_close:
4632 ret = get_errno(close(arg1));
4633 break;
4634 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00004635 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00004636 break;
4637 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00004638 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00004639 break;
thse5febef2007-04-01 18:31:35 +00004640#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00004641 case TARGET_NR_waitpid:
4642 {
pbrook53a59602006-03-25 19:31:22 +00004643 int status;
4644 ret = get_errno(waitpid(arg1, &status, arg3));
bellard2f619692007-11-16 10:46:05 +00004645 if (!is_error(ret) && arg2
pbrook1d9d8b52009-04-16 15:17:02 +00004646 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00004647 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004648 }
4649 break;
thse5febef2007-04-01 18:31:35 +00004650#endif
pbrookf0cbb612008-05-30 18:20:05 +00004651#ifdef TARGET_NR_waitid
4652 case TARGET_NR_waitid:
4653 {
4654 siginfo_t info;
4655 info.si_pid = 0;
4656 ret = get_errno(waitid(arg1, arg2, &info, arg4));
4657 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004658 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00004659 goto efault;
4660 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05004661 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00004662 }
4663 }
4664 break;
4665#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004666#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004667 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00004668 if (!(p = lock_user_string(arg1)))
4669 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004670 ret = get_errno(creat(p, arg2));
4671 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004672 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004673#endif
bellard31e31b82003-02-18 22:55:36 +00004674 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00004675 {
4676 void * p2;
4677 p = lock_user_string(arg1);
4678 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004679 if (!p || !p2)
4680 ret = -TARGET_EFAULT;
4681 else
4682 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004683 unlock_user(p2, arg2, 0);
4684 unlock_user(p, arg1, 0);
4685 }
bellard31e31b82003-02-18 22:55:36 +00004686 break;
ths64f0ce42007-09-24 09:25:06 +00004687#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
4688 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00004689 {
4690 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00004691 if (!arg2 || !arg4)
4692 goto efault;
ths64f0ce42007-09-24 09:25:06 +00004693 p = lock_user_string(arg2);
4694 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004695 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004696 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00004697 else
4698 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00004699 unlock_user(p, arg2, 0);
4700 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00004701 }
4702 break;
4703#endif
bellard31e31b82003-02-18 22:55:36 +00004704 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00004705 if (!(p = lock_user_string(arg1)))
4706 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004707 ret = get_errno(unlink(p));
4708 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004709 break;
ths8170f562007-09-24 09:24:11 +00004710#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
4711 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00004712 if (!(p = lock_user_string(arg2)))
4713 goto efault;
4714 ret = get_errno(sys_unlinkat(arg1, p, arg3));
4715 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00004716 break;
balrogb7d35e62007-12-12 00:40:24 +00004717#endif
bellard31e31b82003-02-18 22:55:36 +00004718 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00004719 {
4720 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00004721 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00004722 abi_ulong gp;
4723 abi_ulong guest_argp;
4724 abi_ulong guest_envp;
4725 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00004726 char **q;
4727
bellardf7341ff2003-03-30 21:00:25 +00004728 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00004729 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00004730 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004731 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004732 goto efault;
ths03aa1972007-12-02 06:28:08 +00004733 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004734 break;
bellard7854b052003-03-29 17:22:23 +00004735 argc++;
bellard2f619692007-11-16 10:46:05 +00004736 }
bellardf7341ff2003-03-30 21:00:25 +00004737 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00004738 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00004739 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004740 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004741 goto efault;
ths03aa1972007-12-02 06:28:08 +00004742 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004743 break;
bellard7854b052003-03-29 17:22:23 +00004744 envc++;
bellard2f619692007-11-16 10:46:05 +00004745 }
bellard7854b052003-03-29 17:22:23 +00004746
bellardf7341ff2003-03-30 21:00:25 +00004747 argp = alloca((argc + 1) * sizeof(void *));
4748 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00004749
pbrookda94d262008-05-30 18:24:00 +00004750 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004751 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004752 if (get_user_ual(addr, gp))
4753 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004754 if (!addr)
4755 break;
bellard2f619692007-11-16 10:46:05 +00004756 if (!(*q = lock_user_string(addr)))
4757 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004758 }
bellardf7341ff2003-03-30 21:00:25 +00004759 *q = NULL;
4760
pbrookda94d262008-05-30 18:24:00 +00004761 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004762 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004763 if (get_user_ual(addr, gp))
4764 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004765 if (!addr)
4766 break;
bellard2f619692007-11-16 10:46:05 +00004767 if (!(*q = lock_user_string(addr)))
4768 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004769 }
bellardf7341ff2003-03-30 21:00:25 +00004770 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00004771
bellard2f619692007-11-16 10:46:05 +00004772 if (!(p = lock_user_string(arg1)))
4773 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004774 ret = get_errno(execve(p, argp, envp));
4775 unlock_user(p, arg1, 0);
4776
bellard2f619692007-11-16 10:46:05 +00004777 goto execve_end;
4778
4779 execve_efault:
4780 ret = -TARGET_EFAULT;
4781
4782 execve_end:
pbrook53a59602006-03-25 19:31:22 +00004783 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004784 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004785 if (get_user_ual(addr, gp)
4786 || !addr)
4787 break;
pbrook53a59602006-03-25 19:31:22 +00004788 unlock_user(*q, addr, 0);
4789 }
4790 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004791 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004792 if (get_user_ual(addr, gp)
4793 || !addr)
4794 break;
pbrook53a59602006-03-25 19:31:22 +00004795 unlock_user(*q, addr, 0);
4796 }
bellard7854b052003-03-29 17:22:23 +00004797 }
bellard31e31b82003-02-18 22:55:36 +00004798 break;
4799 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00004800 if (!(p = lock_user_string(arg1)))
4801 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004802 ret = get_errno(chdir(p));
4803 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004804 break;
bellarda315a142005-01-30 22:59:18 +00004805#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00004806 case TARGET_NR_time:
4807 {
pbrook53a59602006-03-25 19:31:22 +00004808 time_t host_time;
4809 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00004810 if (!is_error(ret)
4811 && arg1
4812 && put_user_sal(host_time, arg1))
4813 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004814 }
4815 break;
bellarda315a142005-01-30 22:59:18 +00004816#endif
bellard31e31b82003-02-18 22:55:36 +00004817 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00004818 if (!(p = lock_user_string(arg1)))
4819 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004820 ret = get_errno(mknod(p, arg2, arg3));
4821 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004822 break;
ths75ac37a2007-09-24 09:23:05 +00004823#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
4824 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00004825 if (!(p = lock_user_string(arg2)))
4826 goto efault;
4827 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
4828 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00004829 break;
4830#endif
bellard31e31b82003-02-18 22:55:36 +00004831 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00004832 if (!(p = lock_user_string(arg1)))
4833 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004834 ret = get_errno(chmod(p, arg2));
4835 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004836 break;
bellardebc05482003-09-30 21:08:41 +00004837#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00004838 case TARGET_NR_break:
4839 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004840#endif
4841#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00004842 case TARGET_NR_oldstat:
4843 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004844#endif
bellard31e31b82003-02-18 22:55:36 +00004845 case TARGET_NR_lseek:
4846 ret = get_errno(lseek(arg1, arg2, arg3));
4847 break;
Richard Henderson92317332010-05-03 10:07:53 -07004848#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
4849 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00004850 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07004851 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00004852 ret = get_errno(getpid());
4853 break;
Richard Henderson92317332010-05-03 10:07:53 -07004854#endif
4855#ifdef TARGET_NR_getpid
4856 case TARGET_NR_getpid:
4857 ret = get_errno(getpid());
4858 break;
4859#endif
bellard31e31b82003-02-18 22:55:36 +00004860 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00004861 {
4862 /* need to look at the data field */
4863 void *p2, *p3;
4864 p = lock_user_string(arg1);
4865 p2 = lock_user_string(arg2);
4866 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00004867 if (!p || !p2 || !p3)
4868 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004869 else {
bellard579a97f2007-11-11 14:26:47 +00004870 /* FIXME - arg5 should be locked, but it isn't clear how to
4871 * do that since it's not guaranteed to be a NULL-terminated
4872 * string.
4873 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004874 if ( ! arg5 )
4875 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
4876 else
4877 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
4878 }
bellard579a97f2007-11-11 14:26:47 +00004879 unlock_user(p, arg1, 0);
4880 unlock_user(p2, arg2, 0);
4881 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00004882 break;
4883 }
thse5febef2007-04-01 18:31:35 +00004884#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00004885 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00004886 if (!(p = lock_user_string(arg1)))
4887 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004888 ret = get_errno(umount(p));
4889 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004890 break;
thse5febef2007-04-01 18:31:35 +00004891#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004892#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004893 case TARGET_NR_stime:
4894 {
pbrook53a59602006-03-25 19:31:22 +00004895 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00004896 if (get_user_sal(host_time, arg1))
4897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004898 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00004899 }
4900 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004901#endif
bellard31e31b82003-02-18 22:55:36 +00004902 case TARGET_NR_ptrace:
4903 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00004904#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004905 case TARGET_NR_alarm:
4906 ret = alarm(arg1);
4907 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004908#endif
bellardebc05482003-09-30 21:08:41 +00004909#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00004910 case TARGET_NR_oldfstat:
4911 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004912#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004913#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004914 case TARGET_NR_pause:
4915 ret = get_errno(pause());
4916 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004917#endif
thse5febef2007-04-01 18:31:35 +00004918#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00004919 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00004920 {
pbrook53a59602006-03-25 19:31:22 +00004921 struct utimbuf tbuf, *host_tbuf;
4922 struct target_utimbuf *target_tbuf;
4923 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00004924 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
4925 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004926 tbuf.actime = tswapl(target_tbuf->actime);
4927 tbuf.modtime = tswapl(target_tbuf->modtime);
4928 unlock_user_struct(target_tbuf, arg2, 0);
4929 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00004930 } else {
pbrook53a59602006-03-25 19:31:22 +00004931 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00004932 }
bellard579a97f2007-11-11 14:26:47 +00004933 if (!(p = lock_user_string(arg1)))
4934 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004935 ret = get_errno(utime(p, host_tbuf));
4936 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00004937 }
4938 break;
thse5febef2007-04-01 18:31:35 +00004939#endif
bellard978a66f2004-12-06 22:58:05 +00004940 case TARGET_NR_utimes:
4941 {
bellard978a66f2004-12-06 22:58:05 +00004942 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00004943 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00004944 if (copy_from_user_timeval(&tv[0], arg2)
4945 || copy_from_user_timeval(&tv[1],
4946 arg2 + sizeof(struct target_timeval)))
4947 goto efault;
bellard978a66f2004-12-06 22:58:05 +00004948 tvp = tv;
4949 } else {
4950 tvp = NULL;
4951 }
bellard579a97f2007-11-11 14:26:47 +00004952 if (!(p = lock_user_string(arg1)))
4953 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004954 ret = get_errno(utimes(p, tvp));
4955 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00004956 }
4957 break;
balrogac8a6552008-09-20 02:25:39 +00004958#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
4959 case TARGET_NR_futimesat:
4960 {
4961 struct timeval *tvp, tv[2];
4962 if (arg3) {
4963 if (copy_from_user_timeval(&tv[0], arg3)
4964 || copy_from_user_timeval(&tv[1],
4965 arg3 + sizeof(struct target_timeval)))
4966 goto efault;
4967 tvp = tv;
4968 } else {
4969 tvp = NULL;
4970 }
4971 if (!(p = lock_user_string(arg2)))
4972 goto efault;
4973 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
4974 unlock_user(p, arg2, 0);
4975 }
4976 break;
4977#endif
bellardebc05482003-09-30 21:08:41 +00004978#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00004979 case TARGET_NR_stty:
4980 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004981#endif
4982#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00004983 case TARGET_NR_gtty:
4984 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004985#endif
bellard31e31b82003-02-18 22:55:36 +00004986 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00004987 if (!(p = lock_user_string(arg1)))
4988 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02004989 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00004990 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004991 break;
ths92a34c12007-09-24 09:27:49 +00004992#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
4993 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00004994 if (!(p = lock_user_string(arg2)))
4995 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00004996 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00004997 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00004998 break;
4999#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005000#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005001 case TARGET_NR_nice:
5002 ret = get_errno(nice(arg1));
5003 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005004#endif
bellardebc05482003-09-30 21:08:41 +00005005#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005006 case TARGET_NR_ftime:
5007 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005008#endif
bellard31e31b82003-02-18 22:55:36 +00005009 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005010 sync();
5011 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005012 break;
5013 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005014 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005015 break;
5016 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005017 {
5018 void *p2;
5019 p = lock_user_string(arg1);
5020 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005021 if (!p || !p2)
5022 ret = -TARGET_EFAULT;
5023 else
5024 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005025 unlock_user(p2, arg2, 0);
5026 unlock_user(p, arg1, 0);
5027 }
bellard31e31b82003-02-18 22:55:36 +00005028 break;
ths722183f2007-09-24 09:24:37 +00005029#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5030 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005031 {
bellard579a97f2007-11-11 14:26:47 +00005032 void *p2;
ths722183f2007-09-24 09:24:37 +00005033 p = lock_user_string(arg2);
5034 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005035 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005036 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005037 else
5038 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005039 unlock_user(p2, arg4, 0);
5040 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005041 }
5042 break;
5043#endif
bellard31e31b82003-02-18 22:55:36 +00005044 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005045 if (!(p = lock_user_string(arg1)))
5046 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005047 ret = get_errno(mkdir(p, arg2));
5048 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005049 break;
ths4472ad02007-09-24 09:22:32 +00005050#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5051 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005052 if (!(p = lock_user_string(arg2)))
5053 goto efault;
5054 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5055 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005056 break;
5057#endif
bellard31e31b82003-02-18 22:55:36 +00005058 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005059 if (!(p = lock_user_string(arg1)))
5060 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005061 ret = get_errno(rmdir(p));
5062 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005063 break;
5064 case TARGET_NR_dup:
5065 ret = get_errno(dup(arg1));
5066 break;
5067 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005068 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005069 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005070#ifdef TARGET_NR_pipe2
5071 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005072 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005073 break;
5074#endif
bellard31e31b82003-02-18 22:55:36 +00005075 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005076 {
pbrook53a59602006-03-25 19:31:22 +00005077 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005078 struct tms tms;
5079 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005080 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005081 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5082 if (!tmsp)
5083 goto efault;
bellardc596ed12003-07-13 17:32:31 +00005084 tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
5085 tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
5086 tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
5087 tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005088 }
bellardc596ed12003-07-13 17:32:31 +00005089 if (!is_error(ret))
5090 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005091 }
5092 break;
bellardebc05482003-09-30 21:08:41 +00005093#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005094 case TARGET_NR_prof:
5095 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005096#endif
thse5febef2007-04-01 18:31:35 +00005097#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005098 case TARGET_NR_signal:
5099 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005100#endif
bellard31e31b82003-02-18 22:55:36 +00005101 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005102 if (arg1 == 0) {
5103 ret = get_errno(acct(NULL));
5104 } else {
5105 if (!(p = lock_user_string(arg1)))
5106 goto efault;
5107 ret = get_errno(acct(path(p)));
5108 unlock_user(p, arg1, 0);
5109 }
pbrook24836682006-04-16 14:14:53 +00005110 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005111#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005112 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005113 if (!(p = lock_user_string(arg1)))
5114 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005115 ret = get_errno(umount2(p, arg2));
5116 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005117 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005118#endif
bellardebc05482003-09-30 21:08:41 +00005119#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005120 case TARGET_NR_lock:
5121 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005122#endif
bellard31e31b82003-02-18 22:55:36 +00005123 case TARGET_NR_ioctl:
5124 ret = do_ioctl(arg1, arg2, arg3);
5125 break;
5126 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005127 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005128 break;
bellardebc05482003-09-30 21:08:41 +00005129#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005130 case TARGET_NR_mpx:
5131 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005132#endif
bellard31e31b82003-02-18 22:55:36 +00005133 case TARGET_NR_setpgid:
5134 ret = get_errno(setpgid(arg1, arg2));
5135 break;
bellardebc05482003-09-30 21:08:41 +00005136#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005137 case TARGET_NR_ulimit:
5138 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005139#endif
5140#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005141 case TARGET_NR_oldolduname:
5142 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005143#endif
bellard31e31b82003-02-18 22:55:36 +00005144 case TARGET_NR_umask:
5145 ret = get_errno(umask(arg1));
5146 break;
5147 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005148 if (!(p = lock_user_string(arg1)))
5149 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005150 ret = get_errno(chroot(p));
5151 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005152 break;
5153 case TARGET_NR_ustat:
5154 goto unimplemented;
5155 case TARGET_NR_dup2:
5156 ret = get_errno(dup2(arg1, arg2));
5157 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005158#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5159 case TARGET_NR_dup3:
5160 ret = get_errno(dup3(arg1, arg2, arg3));
5161 break;
5162#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005163#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005164 case TARGET_NR_getppid:
5165 ret = get_errno(getppid());
5166 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005167#endif
bellard31e31b82003-02-18 22:55:36 +00005168 case TARGET_NR_getpgrp:
5169 ret = get_errno(getpgrp());
5170 break;
5171 case TARGET_NR_setsid:
5172 ret = get_errno(setsid());
5173 break;
thse5febef2007-04-01 18:31:35 +00005174#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005175 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005176 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005177#if defined(TARGET_ALPHA)
5178 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005179 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005180 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005181 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5182 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005183 act._sa_handler = old_act->_sa_handler;
5184 target_siginitset(&act.sa_mask, old_act->sa_mask);
5185 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005186 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005187 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005188 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005189 }
5190 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005191 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005192 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5193 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005194 old_act->_sa_handler = oact._sa_handler;
5195 old_act->sa_mask = oact.sa_mask.sig[0];
5196 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005197 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005198 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005199#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005200 struct target_sigaction act, oact, *pact, *old_act;
5201
5202 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005203 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5204 goto efault;
bellard106ec872006-06-27 21:08:10 +00005205 act._sa_handler = old_act->_sa_handler;
5206 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5207 act.sa_flags = old_act->sa_flags;
5208 unlock_user_struct(old_act, arg2, 0);
5209 pact = &act;
5210 } else {
5211 pact = NULL;
5212 }
5213
5214 ret = get_errno(do_sigaction(arg1, pact, &oact));
5215
5216 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005217 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5218 goto efault;
bellard106ec872006-06-27 21:08:10 +00005219 old_act->_sa_handler = oact._sa_handler;
5220 old_act->sa_flags = oact.sa_flags;
5221 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5222 old_act->sa_mask.sig[1] = 0;
5223 old_act->sa_mask.sig[2] = 0;
5224 old_act->sa_mask.sig[3] = 0;
5225 unlock_user_struct(old_act, arg3, 1);
5226 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005227#else
5228 struct target_old_sigaction *old_act;
5229 struct target_sigaction act, oact, *pact;
5230 if (arg2) {
5231 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5232 goto efault;
5233 act._sa_handler = old_act->_sa_handler;
5234 target_siginitset(&act.sa_mask, old_act->sa_mask);
5235 act.sa_flags = old_act->sa_flags;
5236 act.sa_restorer = old_act->sa_restorer;
5237 unlock_user_struct(old_act, arg2, 0);
5238 pact = &act;
5239 } else {
5240 pact = NULL;
5241 }
5242 ret = get_errno(do_sigaction(arg1, pact, &oact));
5243 if (!is_error(ret) && arg3) {
5244 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5245 goto efault;
5246 old_act->_sa_handler = oact._sa_handler;
5247 old_act->sa_mask = oact.sa_mask.sig[0];
5248 old_act->sa_flags = oact.sa_flags;
5249 old_act->sa_restorer = oact.sa_restorer;
5250 unlock_user_struct(old_act, arg3, 1);
5251 }
ths388bb212007-05-13 13:58:00 +00005252#endif
bellard31e31b82003-02-18 22:55:36 +00005253 }
5254 break;
thse5febef2007-04-01 18:31:35 +00005255#endif
bellard66fb9762003-03-23 01:06:05 +00005256 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005257 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005258#if defined(TARGET_ALPHA)
5259 struct target_sigaction act, oact, *pact = 0;
5260 struct target_rt_sigaction *rt_act;
5261 /* ??? arg4 == sizeof(sigset_t). */
5262 if (arg2) {
5263 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5264 goto efault;
5265 act._sa_handler = rt_act->_sa_handler;
5266 act.sa_mask = rt_act->sa_mask;
5267 act.sa_flags = rt_act->sa_flags;
5268 act.sa_restorer = arg5;
5269 unlock_user_struct(rt_act, arg2, 0);
5270 pact = &act;
5271 }
5272 ret = get_errno(do_sigaction(arg1, pact, &oact));
5273 if (!is_error(ret) && arg3) {
5274 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5275 goto efault;
5276 rt_act->_sa_handler = oact._sa_handler;
5277 rt_act->sa_mask = oact.sa_mask;
5278 rt_act->sa_flags = oact.sa_flags;
5279 unlock_user_struct(rt_act, arg3, 1);
5280 }
5281#else
pbrook53a59602006-03-25 19:31:22 +00005282 struct target_sigaction *act;
5283 struct target_sigaction *oact;
5284
bellard579a97f2007-11-11 14:26:47 +00005285 if (arg2) {
5286 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5287 goto efault;
5288 } else
pbrook53a59602006-03-25 19:31:22 +00005289 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005290 if (arg3) {
5291 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5292 ret = -TARGET_EFAULT;
5293 goto rt_sigaction_fail;
5294 }
5295 } else
pbrook53a59602006-03-25 19:31:22 +00005296 oact = NULL;
5297 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005298 rt_sigaction_fail:
5299 if (act)
pbrook53a59602006-03-25 19:31:22 +00005300 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005301 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005302 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005303#endif
pbrook53a59602006-03-25 19:31:22 +00005304 }
bellard66fb9762003-03-23 01:06:05 +00005305 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005306#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005307 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005308 {
5309 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005310 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005311 sigprocmask(0, NULL, &cur_set);
5312 host_to_target_old_sigset(&target_set, &cur_set);
5313 ret = target_set;
5314 }
5315 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005316#endif
5317#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005318 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005319 {
5320 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005321 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005322 sigprocmask(0, NULL, &cur_set);
5323 target_to_host_old_sigset(&set, &target_set);
5324 sigorset(&set, &set, &cur_set);
5325 sigprocmask(SIG_SETMASK, &set, &oset);
5326 host_to_target_old_sigset(&target_set, &oset);
5327 ret = target_set;
5328 }
5329 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005330#endif
thse5febef2007-04-01 18:31:35 +00005331#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005332 case TARGET_NR_sigprocmask:
5333 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005334#if defined(TARGET_ALPHA)
5335 sigset_t set, oldset;
5336 abi_ulong mask;
5337 int how;
5338
5339 switch (arg1) {
5340 case TARGET_SIG_BLOCK:
5341 how = SIG_BLOCK;
5342 break;
5343 case TARGET_SIG_UNBLOCK:
5344 how = SIG_UNBLOCK;
5345 break;
5346 case TARGET_SIG_SETMASK:
5347 how = SIG_SETMASK;
5348 break;
5349 default:
5350 ret = -TARGET_EINVAL;
5351 goto fail;
5352 }
5353 mask = arg2;
5354 target_to_host_old_sigset(&set, &mask);
5355
5356 ret = get_errno(sigprocmask(how, &set, &oldset));
5357
5358 if (!is_error(ret)) {
5359 host_to_target_old_sigset(&mask, &oldset);
5360 ret = mask;
5361 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5362 }
5363#else
bellard66fb9762003-03-23 01:06:05 +00005364 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005365 int how;
ths3b46e622007-09-17 08:09:54 +00005366
pbrook53a59602006-03-25 19:31:22 +00005367 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005368 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005369 case TARGET_SIG_BLOCK:
5370 how = SIG_BLOCK;
5371 break;
5372 case TARGET_SIG_UNBLOCK:
5373 how = SIG_UNBLOCK;
5374 break;
5375 case TARGET_SIG_SETMASK:
5376 how = SIG_SETMASK;
5377 break;
5378 default:
ths0da46a62007-10-20 20:23:07 +00005379 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005380 goto fail;
5381 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005382 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005383 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005384 target_to_host_old_sigset(&set, p);
5385 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005386 set_ptr = &set;
5387 } else {
5388 how = 0;
5389 set_ptr = NULL;
5390 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005391 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005392 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005393 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005394 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005395 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005396 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005397 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005398#endif
bellard66fb9762003-03-23 01:06:05 +00005399 }
5400 break;
thse5febef2007-04-01 18:31:35 +00005401#endif
bellard66fb9762003-03-23 01:06:05 +00005402 case TARGET_NR_rt_sigprocmask:
5403 {
5404 int how = arg1;
5405 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005406
pbrook53a59602006-03-25 19:31:22 +00005407 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005408 switch(how) {
5409 case TARGET_SIG_BLOCK:
5410 how = SIG_BLOCK;
5411 break;
5412 case TARGET_SIG_UNBLOCK:
5413 how = SIG_UNBLOCK;
5414 break;
5415 case TARGET_SIG_SETMASK:
5416 how = SIG_SETMASK;
5417 break;
5418 default:
ths0da46a62007-10-20 20:23:07 +00005419 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005420 goto fail;
5421 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005422 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005423 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005424 target_to_host_sigset(&set, p);
5425 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005426 set_ptr = &set;
5427 } else {
5428 how = 0;
5429 set_ptr = NULL;
5430 }
5431 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005432 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005433 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005434 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005435 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005436 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005437 }
5438 }
5439 break;
thse5febef2007-04-01 18:31:35 +00005440#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005441 case TARGET_NR_sigpending:
5442 {
5443 sigset_t set;
5444 ret = get_errno(sigpending(&set));
5445 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005446 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005447 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005448 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005449 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005450 }
5451 }
5452 break;
thse5febef2007-04-01 18:31:35 +00005453#endif
bellard66fb9762003-03-23 01:06:05 +00005454 case TARGET_NR_rt_sigpending:
5455 {
5456 sigset_t set;
5457 ret = get_errno(sigpending(&set));
5458 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005459 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005460 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005461 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005462 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005463 }
5464 }
5465 break;
thse5febef2007-04-01 18:31:35 +00005466#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005467 case TARGET_NR_sigsuspend:
5468 {
5469 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005470#if defined(TARGET_ALPHA)
5471 abi_ulong mask = arg1;
5472 target_to_host_old_sigset(&set, &mask);
5473#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005474 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005475 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005476 target_to_host_old_sigset(&set, p);
5477 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005478#endif
bellard66fb9762003-03-23 01:06:05 +00005479 ret = get_errno(sigsuspend(&set));
5480 }
5481 break;
thse5febef2007-04-01 18:31:35 +00005482#endif
bellard66fb9762003-03-23 01:06:05 +00005483 case TARGET_NR_rt_sigsuspend:
5484 {
5485 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005486 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005487 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005488 target_to_host_sigset(&set, p);
5489 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005490 ret = get_errno(sigsuspend(&set));
5491 }
5492 break;
5493 case TARGET_NR_rt_sigtimedwait:
5494 {
bellard66fb9762003-03-23 01:06:05 +00005495 sigset_t set;
5496 struct timespec uts, *puts;
5497 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005498
Anthony Liguoric227f092009-10-01 16:12:16 -05005499 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005500 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005501 target_to_host_sigset(&set, p);
5502 unlock_user(p, arg1, 0);
5503 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005504 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005505 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005506 } else {
5507 puts = NULL;
5508 }
5509 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005510 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005511 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005512 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005513 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005514 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005515 }
5516 }
5517 break;
5518 case TARGET_NR_rt_sigqueueinfo:
5519 {
5520 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005521 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005522 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005523 target_to_host_siginfo(&uinfo, p);
5524 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005525 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5526 }
5527 break;
thse5febef2007-04-01 18:31:35 +00005528#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005529 case TARGET_NR_sigreturn:
5530 /* NOTE: ret is eax, so not transcoding must be done */
5531 ret = do_sigreturn(cpu_env);
5532 break;
thse5febef2007-04-01 18:31:35 +00005533#endif
bellard66fb9762003-03-23 01:06:05 +00005534 case TARGET_NR_rt_sigreturn:
5535 /* NOTE: ret is eax, so not transcoding must be done */
5536 ret = do_rt_sigreturn(cpu_env);
5537 break;
bellard31e31b82003-02-18 22:55:36 +00005538 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00005539 if (!(p = lock_user_string(arg1)))
5540 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005541 ret = get_errno(sethostname(p, arg2));
5542 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005543 break;
5544 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00005545 {
bellard9de5e442003-03-23 16:49:39 +00005546 int resource = arg1;
pbrook53a59602006-03-25 19:31:22 +00005547 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005548 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00005549 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
5550 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005551 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
5552 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005553 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00005554 ret = get_errno(setrlimit(resource, &rlim));
5555 }
5556 break;
bellard31e31b82003-02-18 22:55:36 +00005557 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00005558 {
bellard9de5e442003-03-23 16:49:39 +00005559 int resource = arg1;
pbrook53a59602006-03-25 19:31:22 +00005560 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005561 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00005562
bellard9de5e442003-03-23 16:49:39 +00005563 ret = get_errno(getrlimit(resource, &rlim));
5564 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005565 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
5566 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005567 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
5568 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005569 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00005570 }
5571 }
5572 break;
bellard31e31b82003-02-18 22:55:36 +00005573 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00005574 {
5575 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00005576 ret = get_errno(getrusage(arg1, &rusage));
5577 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005578 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00005579 }
5580 }
5581 break;
bellard31e31b82003-02-18 22:55:36 +00005582 case TARGET_NR_gettimeofday:
5583 {
bellard31e31b82003-02-18 22:55:36 +00005584 struct timeval tv;
5585 ret = get_errno(gettimeofday(&tv, NULL));
5586 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00005587 if (copy_to_user_timeval(arg1, &tv))
5588 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005589 }
5590 }
5591 break;
5592 case TARGET_NR_settimeofday:
5593 {
bellard31e31b82003-02-18 22:55:36 +00005594 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00005595 if (copy_from_user_timeval(&tv, arg1))
5596 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005597 ret = get_errno(settimeofday(&tv, NULL));
5598 }
5599 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005600#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00005601 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00005602 {
pbrook53a59602006-03-25 19:31:22 +00005603 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00005604 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00005605 long nsel;
5606
bellard579a97f2007-11-11 14:26:47 +00005607 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
5608 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005609 nsel = tswapl(sel->n);
5610 inp = tswapl(sel->inp);
5611 outp = tswapl(sel->outp);
5612 exp = tswapl(sel->exp);
5613 tvp = tswapl(sel->tvp);
5614 unlock_user_struct(sel, arg1, 0);
5615 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00005616 }
5617 break;
bellard048f6b42005-11-26 18:47:20 +00005618#endif
Riku Voipio9e423822010-05-07 12:28:05 +00005619#ifdef TARGET_NR_pselect6
5620 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04005621 {
5622 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
5623 fd_set rfds, wfds, efds;
5624 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
5625 struct timespec ts, *ts_ptr;
5626
5627 /*
5628 * The 6th arg is actually two args smashed together,
5629 * so we cannot use the C library.
5630 */
5631 sigset_t set;
5632 struct {
5633 sigset_t *set;
5634 size_t size;
5635 } sig, *sig_ptr;
5636
5637 abi_ulong arg_sigset, arg_sigsize, *arg7;
5638 target_sigset_t *target_sigset;
5639
5640 n = arg1;
5641 rfd_addr = arg2;
5642 wfd_addr = arg3;
5643 efd_addr = arg4;
5644 ts_addr = arg5;
5645
5646 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
5647 if (ret) {
5648 goto fail;
5649 }
5650 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
5651 if (ret) {
5652 goto fail;
5653 }
5654 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
5655 if (ret) {
5656 goto fail;
5657 }
5658
5659 /*
5660 * This takes a timespec, and not a timeval, so we cannot
5661 * use the do_select() helper ...
5662 */
5663 if (ts_addr) {
5664 if (target_to_host_timespec(&ts, ts_addr)) {
5665 goto efault;
5666 }
5667 ts_ptr = &ts;
5668 } else {
5669 ts_ptr = NULL;
5670 }
5671
5672 /* Extract the two packed args for the sigset */
5673 if (arg6) {
5674 sig_ptr = &sig;
5675 sig.size = _NSIG / 8;
5676
5677 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
5678 if (!arg7) {
5679 goto efault;
5680 }
5681 arg_sigset = tswapl(arg7[0]);
5682 arg_sigsize = tswapl(arg7[1]);
5683 unlock_user(arg7, arg6, 0);
5684
5685 if (arg_sigset) {
5686 sig.set = &set;
5687 target_sigset = lock_user(VERIFY_READ, arg_sigset,
5688 sizeof(*target_sigset), 1);
5689 if (!target_sigset) {
5690 goto efault;
5691 }
5692 target_to_host_sigset(&set, target_sigset);
5693 unlock_user(target_sigset, arg_sigset, 0);
5694 } else {
5695 sig.set = NULL;
5696 }
5697 } else {
5698 sig_ptr = NULL;
5699 }
5700
5701 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
5702 ts_ptr, sig_ptr));
5703
5704 if (!is_error(ret)) {
5705 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
5706 goto efault;
5707 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
5708 goto efault;
5709 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
5710 goto efault;
5711
5712 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
5713 goto efault;
5714 }
5715 }
5716 break;
Riku Voipio9e423822010-05-07 12:28:05 +00005717#endif
bellard31e31b82003-02-18 22:55:36 +00005718 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00005719 {
5720 void *p2;
5721 p = lock_user_string(arg1);
5722 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005723 if (!p || !p2)
5724 ret = -TARGET_EFAULT;
5725 else
5726 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005727 unlock_user(p2, arg2, 0);
5728 unlock_user(p, arg1, 0);
5729 }
bellard31e31b82003-02-18 22:55:36 +00005730 break;
thsf0b62432007-09-24 09:25:40 +00005731#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
5732 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00005733 {
bellard579a97f2007-11-11 14:26:47 +00005734 void *p2;
thsf0b62432007-09-24 09:25:40 +00005735 p = lock_user_string(arg1);
5736 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005737 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005738 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00005739 else
5740 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00005741 unlock_user(p2, arg3, 0);
5742 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00005743 }
5744 break;
5745#endif
bellardebc05482003-09-30 21:08:41 +00005746#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00005747 case TARGET_NR_oldlstat:
5748 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005749#endif
bellard31e31b82003-02-18 22:55:36 +00005750 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00005751 {
aurel32d088d662009-01-30 20:09:01 +00005752 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00005753 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00005754 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
5755 if (!p || !p2)
5756 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00005757 else {
5758 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
5759 char real[PATH_MAX];
5760 temp = realpath(exec_path,real);
5761 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
5762 snprintf((char *)p2, arg3, "%s", real);
5763 }
5764 else
5765 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00005766 }
pbrook53a59602006-03-25 19:31:22 +00005767 unlock_user(p2, arg2, ret);
5768 unlock_user(p, arg1, 0);
5769 }
bellard31e31b82003-02-18 22:55:36 +00005770 break;
ths5e0ccb12007-09-24 09:26:10 +00005771#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
5772 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00005773 {
bellard579a97f2007-11-11 14:26:47 +00005774 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00005775 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005776 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
5777 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005778 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00005779 else
5780 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00005781 unlock_user(p2, arg3, ret);
5782 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00005783 }
5784 break;
5785#endif
thse5febef2007-04-01 18:31:35 +00005786#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00005787 case TARGET_NR_uselib:
5788 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005789#endif
5790#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00005791 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00005792 if (!(p = lock_user_string(arg1)))
5793 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005794 ret = get_errno(swapon(p, arg2));
5795 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005796 break;
thse5febef2007-04-01 18:31:35 +00005797#endif
bellard31e31b82003-02-18 22:55:36 +00005798 case TARGET_NR_reboot:
5799 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005800#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00005801 case TARGET_NR_readdir:
5802 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005803#endif
5804#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00005805 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005806#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
5807 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
5808 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00005809 {
blueswir1992f48a2007-10-14 16:27:31 +00005810 abi_ulong *v;
5811 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00005812 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
5813 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005814 v1 = tswapl(v[0]);
5815 v2 = tswapl(v[1]);
5816 v3 = tswapl(v[2]);
5817 v4 = tswapl(v[3]);
5818 v5 = tswapl(v[4]);
5819 v6 = tswapl(v[5]);
5820 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00005821 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00005822 target_to_host_bitmask(v4, mmap_flags_tbl),
5823 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00005824 }
bellard31e31b82003-02-18 22:55:36 +00005825#else
ths5fafdf22007-09-16 21:08:06 +00005826 ret = get_errno(target_mmap(arg1, arg2, arg3,
5827 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00005828 arg5,
5829 arg6));
bellard31e31b82003-02-18 22:55:36 +00005830#endif
bellard6fb883e2003-07-09 17:12:39 +00005831 break;
thse5febef2007-04-01 18:31:35 +00005832#endif
bellarda315a142005-01-30 22:59:18 +00005833#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00005834 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00005835#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00005836#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00005837#endif
ths5fafdf22007-09-16 21:08:06 +00005838 ret = get_errno(target_mmap(arg1, arg2, arg3,
5839 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00005840 arg5,
bellardc573ff62004-01-04 15:51:36 +00005841 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00005842 break;
bellarda315a142005-01-30 22:59:18 +00005843#endif
bellard31e31b82003-02-18 22:55:36 +00005844 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00005845 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005846 break;
bellard9de5e442003-03-23 16:49:39 +00005847 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01005848 {
5849 TaskState *ts = ((CPUState *)cpu_env)->opaque;
5850 /* Special hack to detect libc making the stack executable. */
5851 if ((arg3 & PROT_GROWSDOWN)
5852 && arg1 >= ts->info->stack_limit
5853 && arg1 <= ts->info->start_stack) {
5854 arg3 &= ~PROT_GROWSDOWN;
5855 arg2 = arg2 + arg1 - ts->info->stack_limit;
5856 arg1 = ts->info->stack_limit;
5857 }
5858 }
bellard54936002003-05-13 00:25:15 +00005859 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005860 break;
thse5febef2007-04-01 18:31:35 +00005861#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00005862 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00005863 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00005864 break;
thse5febef2007-04-01 18:31:35 +00005865#endif
pbrook53a59602006-03-25 19:31:22 +00005866 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00005867#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00005868 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00005869 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005870 break;
thse5febef2007-04-01 18:31:35 +00005871#endif
5872#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00005873 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00005874 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005875 break;
thse5febef2007-04-01 18:31:35 +00005876#endif
5877#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00005878 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00005879 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005880 break;
thse5febef2007-04-01 18:31:35 +00005881#endif
5882#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00005883 case TARGET_NR_mlockall:
5884 ret = get_errno(mlockall(arg1));
5885 break;
thse5febef2007-04-01 18:31:35 +00005886#endif
5887#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00005888 case TARGET_NR_munlockall:
5889 ret = get_errno(munlockall());
5890 break;
thse5febef2007-04-01 18:31:35 +00005891#endif
bellard31e31b82003-02-18 22:55:36 +00005892 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00005893 if (!(p = lock_user_string(arg1)))
5894 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005895 ret = get_errno(truncate(p, arg2));
5896 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005897 break;
5898 case TARGET_NR_ftruncate:
5899 ret = get_errno(ftruncate(arg1, arg2));
5900 break;
5901 case TARGET_NR_fchmod:
5902 ret = get_errno(fchmod(arg1, arg2));
5903 break;
ths814d7972007-09-24 09:26:51 +00005904#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
5905 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00005906 if (!(p = lock_user_string(arg2)))
5907 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005908 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005909 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00005910 break;
5911#endif
bellard31e31b82003-02-18 22:55:36 +00005912 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00005913 /* libc does special remapping of the return value of
5914 * sys_getpriority() so it's just easiest to call
5915 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03005916 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005917 break;
5918 case TARGET_NR_setpriority:
5919 ret = get_errno(setpriority(arg1, arg2, arg3));
5920 break;
bellardebc05482003-09-30 21:08:41 +00005921#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00005922 case TARGET_NR_profil:
5923 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005924#endif
bellard31e31b82003-02-18 22:55:36 +00005925 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00005926 if (!(p = lock_user_string(arg1)))
5927 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005928 ret = get_errno(statfs(path(p), &stfs));
5929 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005930 convert_statfs:
5931 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005932 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00005933
bellard579a97f2007-11-11 14:26:47 +00005934 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
5935 goto efault;
5936 __put_user(stfs.f_type, &target_stfs->f_type);
5937 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
5938 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
5939 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
5940 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
5941 __put_user(stfs.f_files, &target_stfs->f_files);
5942 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
5943 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
5944 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
5945 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00005946 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00005947 }
5948 break;
5949 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00005950 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00005951 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00005952#ifdef TARGET_NR_statfs64
5953 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00005954 if (!(p = lock_user_string(arg1)))
5955 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005956 ret = get_errno(statfs(path(p), &stfs));
5957 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00005958 convert_statfs64:
5959 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005960 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00005961
bellard579a97f2007-11-11 14:26:47 +00005962 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
5963 goto efault;
5964 __put_user(stfs.f_type, &target_stfs->f_type);
5965 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
5966 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
5967 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
5968 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
5969 __put_user(stfs.f_files, &target_stfs->f_files);
5970 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
5971 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
5972 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
5973 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
5974 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00005975 }
5976 break;
5977 case TARGET_NR_fstatfs64:
5978 ret = get_errno(fstatfs(arg1, &stfs));
5979 goto convert_statfs64;
5980#endif
bellardebc05482003-09-30 21:08:41 +00005981#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00005982 case TARGET_NR_ioperm:
5983 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005984#endif
thse5febef2007-04-01 18:31:35 +00005985#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00005986 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00005987 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00005988 break;
thse5febef2007-04-01 18:31:35 +00005989#endif
bellard3532fa72006-06-24 15:06:03 +00005990#ifdef TARGET_NR_accept
5991 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00005992 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00005993 break;
5994#endif
5995#ifdef TARGET_NR_bind
5996 case TARGET_NR_bind:
5997 ret = do_bind(arg1, arg2, arg3);
5998 break;
5999#endif
6000#ifdef TARGET_NR_connect
6001 case TARGET_NR_connect:
6002 ret = do_connect(arg1, arg2, arg3);
6003 break;
6004#endif
6005#ifdef TARGET_NR_getpeername
6006 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006007 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006008 break;
6009#endif
6010#ifdef TARGET_NR_getsockname
6011 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006012 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006013 break;
6014#endif
6015#ifdef TARGET_NR_getsockopt
6016 case TARGET_NR_getsockopt:
6017 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6018 break;
6019#endif
6020#ifdef TARGET_NR_listen
6021 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006022 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006023 break;
6024#endif
6025#ifdef TARGET_NR_recv
6026 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006027 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006028 break;
6029#endif
6030#ifdef TARGET_NR_recvfrom
6031 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006032 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006033 break;
6034#endif
6035#ifdef TARGET_NR_recvmsg
6036 case TARGET_NR_recvmsg:
6037 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6038 break;
6039#endif
6040#ifdef TARGET_NR_send
6041 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006042 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006043 break;
6044#endif
6045#ifdef TARGET_NR_sendmsg
6046 case TARGET_NR_sendmsg:
6047 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6048 break;
6049#endif
6050#ifdef TARGET_NR_sendto
6051 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006052 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006053 break;
6054#endif
6055#ifdef TARGET_NR_shutdown
6056 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006057 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006058 break;
6059#endif
6060#ifdef TARGET_NR_socket
6061 case TARGET_NR_socket:
6062 ret = do_socket(arg1, arg2, arg3);
6063 break;
6064#endif
6065#ifdef TARGET_NR_socketpair
6066 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006067 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006068 break;
6069#endif
6070#ifdef TARGET_NR_setsockopt
6071 case TARGET_NR_setsockopt:
6072 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6073 break;
6074#endif
ths7494b0f2007-02-11 18:26:53 +00006075
bellard31e31b82003-02-18 22:55:36 +00006076 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006077 if (!(p = lock_user_string(arg2)))
6078 goto efault;
thse5574482007-02-11 20:03:13 +00006079 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6080 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006081 break;
6082
bellard31e31b82003-02-18 22:55:36 +00006083 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006084 {
bellard66fb9762003-03-23 01:06:05 +00006085 struct itimerval value, ovalue, *pvalue;
6086
pbrook53a59602006-03-25 19:31:22 +00006087 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006088 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006089 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6090 || copy_from_user_timeval(&pvalue->it_value,
6091 arg2 + sizeof(struct target_timeval)))
6092 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006093 } else {
6094 pvalue = NULL;
6095 }
6096 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006097 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006098 if (copy_to_user_timeval(arg3,
6099 &ovalue.it_interval)
6100 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6101 &ovalue.it_value))
6102 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006103 }
6104 }
6105 break;
bellard31e31b82003-02-18 22:55:36 +00006106 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006107 {
bellard66fb9762003-03-23 01:06:05 +00006108 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006109
bellard66fb9762003-03-23 01:06:05 +00006110 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006111 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006112 if (copy_to_user_timeval(arg2,
6113 &value.it_interval)
6114 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6115 &value.it_value))
6116 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006117 }
6118 }
6119 break;
bellard31e31b82003-02-18 22:55:36 +00006120 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006121 if (!(p = lock_user_string(arg1)))
6122 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006123 ret = get_errno(stat(path(p), &st));
6124 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006125 goto do_stat;
6126 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006127 if (!(p = lock_user_string(arg1)))
6128 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006129 ret = get_errno(lstat(path(p), &st));
6130 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006131 goto do_stat;
6132 case TARGET_NR_fstat:
6133 {
6134 ret = get_errno(fstat(arg1, &st));
6135 do_stat:
6136 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006137 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006138
bellard579a97f2007-11-11 14:26:47 +00006139 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6140 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006141 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006142 __put_user(st.st_dev, &target_st->st_dev);
6143 __put_user(st.st_ino, &target_st->st_ino);
6144 __put_user(st.st_mode, &target_st->st_mode);
6145 __put_user(st.st_uid, &target_st->st_uid);
6146 __put_user(st.st_gid, &target_st->st_gid);
6147 __put_user(st.st_nlink, &target_st->st_nlink);
6148 __put_user(st.st_rdev, &target_st->st_rdev);
6149 __put_user(st.st_size, &target_st->st_size);
6150 __put_user(st.st_blksize, &target_st->st_blksize);
6151 __put_user(st.st_blocks, &target_st->st_blocks);
6152 __put_user(st.st_atime, &target_st->target_st_atime);
6153 __put_user(st.st_mtime, &target_st->target_st_mtime);
6154 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006155 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006156 }
6157 }
6158 break;
bellardebc05482003-09-30 21:08:41 +00006159#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006160 case TARGET_NR_olduname:
6161 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006162#endif
6163#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006164 case TARGET_NR_iopl:
6165 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006166#endif
bellard31e31b82003-02-18 22:55:36 +00006167 case TARGET_NR_vhangup:
6168 ret = get_errno(vhangup());
6169 break;
bellardebc05482003-09-30 21:08:41 +00006170#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006171 case TARGET_NR_idle:
6172 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006173#endif
bellard42ad6ae2005-01-03 22:48:11 +00006174#ifdef TARGET_NR_syscall
6175 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006176 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6177 arg6, arg7, arg8, 0);
6178 break;
bellard42ad6ae2005-01-03 22:48:11 +00006179#endif
bellard31e31b82003-02-18 22:55:36 +00006180 case TARGET_NR_wait4:
6181 {
6182 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006183 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006184 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006185 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006186 if (target_rusage)
6187 rusage_ptr = &rusage;
6188 else
6189 rusage_ptr = NULL;
6190 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6191 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006192 if (status_ptr) {
pbrook1d9d8b52009-04-16 15:17:02 +00006193 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006194 if (put_user_s32(status, status_ptr))
6195 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006196 }
bellard2f619692007-11-16 10:46:05 +00006197 if (target_rusage)
6198 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006199 }
6200 }
6201 break;
thse5febef2007-04-01 18:31:35 +00006202#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006203 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006204 if (!(p = lock_user_string(arg1)))
6205 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006206 ret = get_errno(swapoff(p));
6207 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006208 break;
thse5febef2007-04-01 18:31:35 +00006209#endif
bellard31e31b82003-02-18 22:55:36 +00006210 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006211 {
pbrook53a59602006-03-25 19:31:22 +00006212 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006213 struct sysinfo value;
6214 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006215 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006216 {
bellard579a97f2007-11-11 14:26:47 +00006217 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6218 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006219 __put_user(value.uptime, &target_value->uptime);
6220 __put_user(value.loads[0], &target_value->loads[0]);
6221 __put_user(value.loads[1], &target_value->loads[1]);
6222 __put_user(value.loads[2], &target_value->loads[2]);
6223 __put_user(value.totalram, &target_value->totalram);
6224 __put_user(value.freeram, &target_value->freeram);
6225 __put_user(value.sharedram, &target_value->sharedram);
6226 __put_user(value.bufferram, &target_value->bufferram);
6227 __put_user(value.totalswap, &target_value->totalswap);
6228 __put_user(value.freeswap, &target_value->freeswap);
6229 __put_user(value.procs, &target_value->procs);
6230 __put_user(value.totalhigh, &target_value->totalhigh);
6231 __put_user(value.freehigh, &target_value->freehigh);
6232 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006233 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006234 }
6235 }
6236 break;
thse5febef2007-04-01 18:31:35 +00006237#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006238 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006239 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6240 break;
thse5febef2007-04-01 18:31:35 +00006241#endif
aurel32e5289082009-04-18 16:16:12 +00006242#ifdef TARGET_NR_semget
6243 case TARGET_NR_semget:
6244 ret = get_errno(semget(arg1, arg2, arg3));
6245 break;
6246#endif
6247#ifdef TARGET_NR_semop
6248 case TARGET_NR_semop:
6249 ret = get_errno(do_semop(arg1, arg2, arg3));
6250 break;
6251#endif
6252#ifdef TARGET_NR_semctl
6253 case TARGET_NR_semctl:
6254 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6255 break;
6256#endif
aurel32eeb438c2008-10-13 21:08:55 +00006257#ifdef TARGET_NR_msgctl
6258 case TARGET_NR_msgctl:
6259 ret = do_msgctl(arg1, arg2, arg3);
6260 break;
6261#endif
6262#ifdef TARGET_NR_msgget
6263 case TARGET_NR_msgget:
6264 ret = get_errno(msgget(arg1, arg2));
6265 break;
6266#endif
6267#ifdef TARGET_NR_msgrcv
6268 case TARGET_NR_msgrcv:
6269 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6270 break;
6271#endif
6272#ifdef TARGET_NR_msgsnd
6273 case TARGET_NR_msgsnd:
6274 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6275 break;
6276#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006277#ifdef TARGET_NR_shmget
6278 case TARGET_NR_shmget:
6279 ret = get_errno(shmget(arg1, arg2, arg3));
6280 break;
6281#endif
6282#ifdef TARGET_NR_shmctl
6283 case TARGET_NR_shmctl:
6284 ret = do_shmctl(arg1, arg2, arg3);
6285 break;
6286#endif
6287#ifdef TARGET_NR_shmat
6288 case TARGET_NR_shmat:
6289 ret = do_shmat(arg1, arg2, arg3);
6290 break;
6291#endif
6292#ifdef TARGET_NR_shmdt
6293 case TARGET_NR_shmdt:
6294 ret = do_shmdt(arg1);
6295 break;
6296#endif
bellard31e31b82003-02-18 22:55:36 +00006297 case TARGET_NR_fsync:
6298 ret = get_errno(fsync(arg1));
6299 break;
bellard31e31b82003-02-18 22:55:36 +00006300 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006301#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006302 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006303#elif defined(TARGET_CRIS)
6304 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006305#elif defined(TARGET_S390X)
6306 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006307#else
pbrookd865bab2008-06-07 22:12:17 +00006308 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006309#endif
bellard1b6b0292003-03-22 17:31:38 +00006310 break;
bellardec86b0f2003-04-11 00:15:04 +00006311#ifdef __NR_exit_group
6312 /* new thread calls */
6313 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006314#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006315 _mcleanup();
6316#endif
bellarde9009672005-04-26 20:42:36 +00006317 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006318 ret = get_errno(exit_group(arg1));
6319 break;
6320#endif
bellard31e31b82003-02-18 22:55:36 +00006321 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006322 if (!(p = lock_user_string(arg1)))
6323 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006324 ret = get_errno(setdomainname(p, arg2));
6325 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006326 break;
6327 case TARGET_NR_uname:
6328 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006329 {
6330 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006331
bellard579a97f2007-11-11 14:26:47 +00006332 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6333 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006334 ret = get_errno(sys_uname(buf));
6335 if (!is_error(ret)) {
6336 /* Overrite the native machine name with whatever is being
6337 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006338 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006339 /* Allow the user to override the reported release. */
6340 if (qemu_uname_release && *qemu_uname_release)
6341 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006342 }
pbrook53a59602006-03-25 19:31:22 +00006343 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006344 }
bellard31e31b82003-02-18 22:55:36 +00006345 break;
bellard6dbad632003-03-16 18:05:05 +00006346#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006347 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006348 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006349 break;
j_mayer84409dd2007-04-06 08:56:50 +00006350#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006351 case TARGET_NR_vm86old:
6352 goto unimplemented;
6353 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006354 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006355 break;
6356#endif
j_mayer84409dd2007-04-06 08:56:50 +00006357#endif
bellard31e31b82003-02-18 22:55:36 +00006358 case TARGET_NR_adjtimex:
6359 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006360#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006361 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006362#endif
bellard31e31b82003-02-18 22:55:36 +00006363 case TARGET_NR_init_module:
6364 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006365#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006366 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006367#endif
bellard31e31b82003-02-18 22:55:36 +00006368 goto unimplemented;
6369 case TARGET_NR_quotactl:
6370 goto unimplemented;
6371 case TARGET_NR_getpgid:
6372 ret = get_errno(getpgid(arg1));
6373 break;
6374 case TARGET_NR_fchdir:
6375 ret = get_errno(fchdir(arg1));
6376 break;
j_mayer84409dd2007-04-06 08:56:50 +00006377#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006378 case TARGET_NR_bdflush:
6379 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006380#endif
thse5febef2007-04-01 18:31:35 +00006381#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006382 case TARGET_NR_sysfs:
6383 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006384#endif
bellard31e31b82003-02-18 22:55:36 +00006385 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006386 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006387 break;
thse5febef2007-04-01 18:31:35 +00006388#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006389 case TARGET_NR_afs_syscall:
6390 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006391#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006392#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006393 case TARGET_NR__llseek:
6394 {
6395 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006396#if !defined(__NR_llseek)
6397 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6398 if (res == -1) {
6399 ret = get_errno(res);
6400 } else {
6401 ret = 0;
6402 }
6403#else
bellard31e31b82003-02-18 22:55:36 +00006404 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006405#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006406 if ((ret == 0) && put_user_s64(res, arg4)) {
6407 goto efault;
6408 }
bellard31e31b82003-02-18 22:55:36 +00006409 }
6410 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006411#endif
bellard31e31b82003-02-18 22:55:36 +00006412 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006413#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006414 {
pbrook53a59602006-03-25 19:31:22 +00006415 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006416 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006417 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006418
6419 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006420 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006421 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006422 goto fail;
6423 }
ths3b46e622007-09-17 08:09:54 +00006424
bellard4add45b2003-06-05 01:52:59 +00006425 ret = get_errno(sys_getdents(arg1, dirp, count));
6426 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006427 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006428 struct target_dirent *tde;
6429 int len = ret;
6430 int reclen, treclen;
6431 int count1, tnamelen;
6432
6433 count1 = 0;
6434 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006435 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6436 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006437 tde = target_dirp;
6438 while (len > 0) {
6439 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006440 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006441 tde->d_reclen = tswap16(treclen);
6442 tde->d_ino = tswapl(de->d_ino);
6443 tde->d_off = tswapl(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006444 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006445 if (tnamelen > 256)
6446 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006447 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006448 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006449 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006450 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006451 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006452 count1 += treclen;
6453 }
6454 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006455 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006456 }
6457 free(dirp);
6458 }
6459#else
bellard31e31b82003-02-18 22:55:36 +00006460 {
aurel326556a832008-10-13 21:08:17 +00006461 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006462 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006463
bellard579a97f2007-11-11 14:26:47 +00006464 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6465 goto efault;
bellard72f03902003-02-18 23:33:18 +00006466 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006467 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006468 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006469 int len = ret;
6470 int reclen;
6471 de = dirp;
6472 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006473 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006474 if (reclen > len)
6475 break;
bellard8083a3e2003-03-24 23:12:16 +00006476 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006477 tswapls(&de->d_ino);
6478 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006479 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006480 len -= reclen;
6481 }
6482 }
pbrook53a59602006-03-25 19:31:22 +00006483 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006484 }
bellard4add45b2003-06-05 01:52:59 +00006485#endif
bellard31e31b82003-02-18 22:55:36 +00006486 break;
ths3ae43202007-09-16 21:39:48 +00006487#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006488 case TARGET_NR_getdents64:
6489 {
aurel326556a832008-10-13 21:08:17 +00006490 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006491 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006492 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6493 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006494 ret = get_errno(sys_getdents64(arg1, dirp, count));
6495 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006496 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006497 int len = ret;
6498 int reclen;
6499 de = dirp;
6500 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006501 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006502 if (reclen > len)
6503 break;
bellard8083a3e2003-03-24 23:12:16 +00006504 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006505 tswap64s((uint64_t *)&de->d_ino);
6506 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006507 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006508 len -= reclen;
6509 }
6510 }
pbrook53a59602006-03-25 19:31:22 +00006511 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006512 }
6513 break;
bellarda541f292004-04-12 20:39:29 +00006514#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006515#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
6516#ifdef TARGET_S390X
6517 case TARGET_NR_select:
6518#else
bellard31e31b82003-02-18 22:55:36 +00006519 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006520#endif
pbrook53a59602006-03-25 19:31:22 +00006521 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00006522 break;
thse5febef2007-04-01 18:31:35 +00006523#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05006524#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
6525# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00006526 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05006527# endif
6528# ifdef TARGET_NR_ppoll
6529 case TARGET_NR_ppoll:
6530# endif
bellard9de5e442003-03-23 16:49:39 +00006531 {
pbrook53a59602006-03-25 19:31:22 +00006532 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00006533 unsigned int nfds = arg2;
6534 int timeout = arg3;
6535 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00006536 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00006537
bellard579a97f2007-11-11 14:26:47 +00006538 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
6539 if (!target_pfd)
6540 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05006541
bellard9de5e442003-03-23 16:49:39 +00006542 pfd = alloca(sizeof(struct pollfd) * nfds);
6543 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006544 pfd[i].fd = tswap32(target_pfd[i].fd);
6545 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00006546 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05006547
6548# ifdef TARGET_NR_ppoll
6549 if (num == TARGET_NR_ppoll) {
6550 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
6551 target_sigset_t *target_set;
6552 sigset_t _set, *set = &_set;
6553
6554 if (arg3) {
6555 if (target_to_host_timespec(timeout_ts, arg3)) {
6556 unlock_user(target_pfd, arg1, 0);
6557 goto efault;
6558 }
6559 } else {
6560 timeout_ts = NULL;
6561 }
6562
6563 if (arg4) {
6564 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
6565 if (!target_set) {
6566 unlock_user(target_pfd, arg1, 0);
6567 goto efault;
6568 }
6569 target_to_host_sigset(set, target_set);
6570 } else {
6571 set = NULL;
6572 }
6573
6574 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
6575
6576 if (!is_error(ret) && arg3) {
6577 host_to_target_timespec(arg3, timeout_ts);
6578 }
6579 if (arg4) {
6580 unlock_user(target_set, arg4, 0);
6581 }
6582 } else
6583# endif
6584 ret = get_errno(poll(pfd, nfds, timeout));
6585
bellard9de5e442003-03-23 16:49:39 +00006586 if (!is_error(ret)) {
6587 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006588 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00006589 }
6590 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00006591 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00006592 }
6593 break;
thse5febef2007-04-01 18:31:35 +00006594#endif
bellard31e31b82003-02-18 22:55:36 +00006595 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00006596 /* NOTE: the flock constant seems to be the same for every
6597 Linux platform */
6598 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006599 break;
6600 case TARGET_NR_readv:
6601 {
6602 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006603 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006604
6605 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006606 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
6607 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006608 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006609 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00006610 }
6611 break;
6612 case TARGET_NR_writev:
6613 {
6614 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006615 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006616
6617 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006618 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
6619 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006620 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006621 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00006622 }
6623 break;
6624 case TARGET_NR_getsid:
6625 ret = get_errno(getsid(arg1));
6626 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006627#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00006628 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00006629 ret = get_errno(fdatasync(arg1));
6630 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006631#endif
bellard31e31b82003-02-18 22:55:36 +00006632 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00006633 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00006634 return value. */
ths0da46a62007-10-20 20:23:07 +00006635 ret = -TARGET_ENOTDIR;
6636 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05006637 case TARGET_NR_sched_getaffinity:
6638 {
6639 unsigned int mask_size;
6640 unsigned long *mask;
6641
6642 /*
6643 * sched_getaffinity needs multiples of ulong, so need to take
6644 * care of mismatches between target ulong and host ulong sizes.
6645 */
6646 if (arg2 & (sizeof(abi_ulong) - 1)) {
6647 ret = -TARGET_EINVAL;
6648 break;
6649 }
6650 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6651
6652 mask = alloca(mask_size);
6653 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
6654
6655 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09006656 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05006657 goto efault;
6658 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05006659 }
6660 }
6661 break;
6662 case TARGET_NR_sched_setaffinity:
6663 {
6664 unsigned int mask_size;
6665 unsigned long *mask;
6666
6667 /*
6668 * sched_setaffinity needs multiples of ulong, so need to take
6669 * care of mismatches between target ulong and host ulong sizes.
6670 */
6671 if (arg2 & (sizeof(abi_ulong) - 1)) {
6672 ret = -TARGET_EINVAL;
6673 break;
6674 }
6675 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6676
6677 mask = alloca(mask_size);
6678 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
6679 goto efault;
6680 }
6681 memcpy(mask, p, arg2);
6682 unlock_user_struct(p, arg2, 0);
6683
6684 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
6685 }
6686 break;
bellard31e31b82003-02-18 22:55:36 +00006687 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00006688 {
pbrook53a59602006-03-25 19:31:22 +00006689 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006690 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00006691
bellard579a97f2007-11-11 14:26:47 +00006692 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
6693 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006694 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006695 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00006696 ret = get_errno(sched_setparam(arg1, &schp));
6697 }
6698 break;
bellard31e31b82003-02-18 22:55:36 +00006699 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00006700 {
pbrook53a59602006-03-25 19:31:22 +00006701 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006702 struct sched_param schp;
6703 ret = get_errno(sched_getparam(arg1, &schp));
6704 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006705 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
6706 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006707 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006708 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00006709 }
6710 }
6711 break;
bellard31e31b82003-02-18 22:55:36 +00006712 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00006713 {
pbrook53a59602006-03-25 19:31:22 +00006714 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006715 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00006716 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
6717 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006718 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006719 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00006720 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
6721 }
6722 break;
bellard31e31b82003-02-18 22:55:36 +00006723 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00006724 ret = get_errno(sched_getscheduler(arg1));
6725 break;
bellard31e31b82003-02-18 22:55:36 +00006726 case TARGET_NR_sched_yield:
6727 ret = get_errno(sched_yield());
6728 break;
6729 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00006730 ret = get_errno(sched_get_priority_max(arg1));
6731 break;
bellard31e31b82003-02-18 22:55:36 +00006732 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00006733 ret = get_errno(sched_get_priority_min(arg1));
6734 break;
bellard31e31b82003-02-18 22:55:36 +00006735 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00006736 {
bellard5cd43932003-03-29 16:54:36 +00006737 struct timespec ts;
6738 ret = get_errno(sched_rr_get_interval(arg1, &ts));
6739 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006740 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00006741 }
6742 }
6743 break;
bellard31e31b82003-02-18 22:55:36 +00006744 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00006745 {
bellard1b6b0292003-03-22 17:31:38 +00006746 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00006747 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00006748 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00006749 if (is_error(ret) && arg2) {
6750 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00006751 }
6752 }
6753 break;
thse5febef2007-04-01 18:31:35 +00006754#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00006755 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00006756 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006757#endif
6758#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00006759 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00006760 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006761#endif
bellard31e31b82003-02-18 22:55:36 +00006762 case TARGET_NR_prctl:
thse5574482007-02-11 20:03:13 +00006763 switch (arg1)
6764 {
6765 case PR_GET_PDEATHSIG:
6766 {
6767 int deathsig;
6768 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
bellard2f619692007-11-16 10:46:05 +00006769 if (!is_error(ret) && arg2
6770 && put_user_ual(deathsig, arg2))
6771 goto efault;
thse5574482007-02-11 20:03:13 +00006772 }
6773 break;
6774 default:
6775 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
6776 break;
6777 }
ths39b9aae2007-02-11 18:36:44 +00006778 break;
bellardd2fd1af2007-11-14 18:08:56 +00006779#ifdef TARGET_NR_arch_prctl
6780 case TARGET_NR_arch_prctl:
6781#if defined(TARGET_I386) && !defined(TARGET_ABI32)
6782 ret = do_arch_prctl(cpu_env, arg1, arg2);
6783 break;
6784#else
6785 goto unimplemented;
6786#endif
6787#endif
bellard67867302003-11-23 17:05:30 +00006788#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00006789 case TARGET_NR_pread:
balroga4ae00b2008-09-20 03:14:14 +00006790#ifdef TARGET_ARM
6791 if (((CPUARMState *)cpu_env)->eabi)
6792 arg4 = arg5;
6793#endif
bellard579a97f2007-11-11 14:26:47 +00006794 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6795 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006796 ret = get_errno(pread(arg1, p, arg3, arg4));
6797 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00006798 break;
bellard31e31b82003-02-18 22:55:36 +00006799 case TARGET_NR_pwrite:
balroga4ae00b2008-09-20 03:14:14 +00006800#ifdef TARGET_ARM
6801 if (((CPUARMState *)cpu_env)->eabi)
6802 arg4 = arg5;
6803#endif
bellard579a97f2007-11-11 14:26:47 +00006804 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6805 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006806 ret = get_errno(pwrite(arg1, p, arg3, arg4));
6807 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00006808 break;
bellard67867302003-11-23 17:05:30 +00006809#endif
aurel32f2c7ba12008-03-28 22:32:06 +00006810#ifdef TARGET_NR_pread64
6811 case TARGET_NR_pread64:
6812 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6813 goto efault;
6814 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
6815 unlock_user(p, arg2, ret);
6816 break;
6817 case TARGET_NR_pwrite64:
6818 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6819 goto efault;
6820 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
6821 unlock_user(p, arg2, 0);
6822 break;
6823#endif
bellard31e31b82003-02-18 22:55:36 +00006824 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00006825 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
6826 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006827 ret = get_errno(sys_getcwd1(p, arg2));
6828 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00006829 break;
6830 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00006831 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006832 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00006833 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006834 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00006835#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02006836 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006837 defined(TARGET_M68K) || defined(TARGET_S390X)
bellard579a97f2007-11-11 14:26:47 +00006838 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00006839 break;
6840#else
bellard5cd43932003-03-29 16:54:36 +00006841 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00006842#endif
bellard31e31b82003-02-18 22:55:36 +00006843 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00006844 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006845#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00006846 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00006847 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006848#endif
6849#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00006850 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00006851 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006852#endif
bellard048f6b42005-11-26 18:47:20 +00006853#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00006854 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00006855 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
6856 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006857 break;
bellard048f6b42005-11-26 18:47:20 +00006858#endif
bellardebc05482003-09-30 21:08:41 +00006859#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00006860 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00006861 {
6862 struct rlimit rlim;
6863 ret = get_errno(getrlimit(arg1, &rlim));
6864 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006865 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00006866 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6867 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006868 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6869 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006870 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00006871 }
6872 break;
6873 }
bellardebc05482003-09-30 21:08:41 +00006874#endif
bellarda315a142005-01-30 22:59:18 +00006875#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00006876 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00006877 if (!(p = lock_user_string(arg1)))
6878 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006879 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
6880 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00006881 break;
bellarda315a142005-01-30 22:59:18 +00006882#endif
6883#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00006884 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00006885 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00006886 break;
bellarda315a142005-01-30 22:59:18 +00006887#endif
6888#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00006889 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00006890 if (!(p = lock_user_string(arg1)))
6891 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006892 ret = get_errno(stat(path(p), &st));
6893 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006894 if (!is_error(ret))
6895 ret = host_to_target_stat64(cpu_env, arg2, &st);
6896 break;
bellarda315a142005-01-30 22:59:18 +00006897#endif
6898#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00006899 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00006900 if (!(p = lock_user_string(arg1)))
6901 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006902 ret = get_errno(lstat(path(p), &st));
6903 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006904 if (!is_error(ret))
6905 ret = host_to_target_stat64(cpu_env, arg2, &st);
6906 break;
bellarda315a142005-01-30 22:59:18 +00006907#endif
6908#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00006909 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00006910 ret = get_errno(fstat(arg1, &st));
6911 if (!is_error(ret))
6912 ret = host_to_target_stat64(cpu_env, arg2, &st);
6913 break;
bellardec86b0f2003-04-11 00:15:04 +00006914#endif
aurel329d33b762009-04-08 23:07:05 +00006915#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
6916 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
6917#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006918 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00006919#endif
6920#ifdef TARGET_NR_newfstatat
6921 case TARGET_NR_newfstatat:
6922#endif
balrog6a24a772008-09-20 02:23:36 +00006923 if (!(p = lock_user_string(arg2)))
6924 goto efault;
aurel329d33b762009-04-08 23:07:05 +00006925#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006926 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00006927#else
6928 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
6929#endif
balrog6a24a772008-09-20 02:23:36 +00006930 if (!is_error(ret))
6931 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00006932 break;
bellarda315a142005-01-30 22:59:18 +00006933#endif
bellard67867302003-11-23 17:05:30 +00006934 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00006935 if (!(p = lock_user_string(arg1)))
6936 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006937 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
6938 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00006939 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006940#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00006941 case TARGET_NR_getuid:
6942 ret = get_errno(high2lowuid(getuid()));
6943 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006944#endif
6945#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00006946 case TARGET_NR_getgid:
6947 ret = get_errno(high2lowgid(getgid()));
6948 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006949#endif
6950#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00006951 case TARGET_NR_geteuid:
6952 ret = get_errno(high2lowuid(geteuid()));
6953 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006954#endif
6955#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00006956 case TARGET_NR_getegid:
6957 ret = get_errno(high2lowgid(getegid()));
6958 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03006959#endif
bellard67867302003-11-23 17:05:30 +00006960 case TARGET_NR_setreuid:
6961 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
6962 break;
6963 case TARGET_NR_setregid:
6964 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
6965 break;
6966 case TARGET_NR_getgroups:
6967 {
6968 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03006969 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00006970 gid_t *grouplist;
6971 int i;
6972
6973 grouplist = alloca(gidsetsize * sizeof(gid_t));
6974 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00006975 if (gidsetsize == 0)
6976 break;
bellard67867302003-11-23 17:05:30 +00006977 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006978 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
6979 if (!target_grouplist)
6980 goto efault;
balroga2155fc2008-09-20 02:12:08 +00006981 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03006982 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00006983 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00006984 }
6985 }
6986 break;
6987 case TARGET_NR_setgroups:
6988 {
6989 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03006990 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00006991 gid_t *grouplist;
6992 int i;
6993
6994 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00006995 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
6996 if (!target_grouplist) {
6997 ret = -TARGET_EFAULT;
6998 goto fail;
6999 }
bellard67867302003-11-23 17:05:30 +00007000 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007001 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007002 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007003 ret = get_errno(setgroups(gidsetsize, grouplist));
7004 }
7005 break;
7006 case TARGET_NR_fchown:
7007 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7008 break;
thsccfa72b2007-09-24 09:23:34 +00007009#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7010 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007011 if (!(p = lock_user_string(arg2)))
7012 goto efault;
7013 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7014 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007015 break;
7016#endif
bellard67867302003-11-23 17:05:30 +00007017#ifdef TARGET_NR_setresuid
7018 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007019 ret = get_errno(setresuid(low2highuid(arg1),
7020 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007021 low2highuid(arg3)));
7022 break;
7023#endif
7024#ifdef TARGET_NR_getresuid
7025 case TARGET_NR_getresuid:
7026 {
pbrook53a59602006-03-25 19:31:22 +00007027 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007028 ret = get_errno(getresuid(&ruid, &euid, &suid));
7029 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007030 if (put_user_u16(high2lowuid(ruid), arg1)
7031 || put_user_u16(high2lowuid(euid), arg2)
7032 || put_user_u16(high2lowuid(suid), arg3))
7033 goto efault;
bellard67867302003-11-23 17:05:30 +00007034 }
7035 }
7036 break;
7037#endif
7038#ifdef TARGET_NR_getresgid
7039 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007040 ret = get_errno(setresgid(low2highgid(arg1),
7041 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007042 low2highgid(arg3)));
7043 break;
7044#endif
7045#ifdef TARGET_NR_getresgid
7046 case TARGET_NR_getresgid:
7047 {
pbrook53a59602006-03-25 19:31:22 +00007048 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007049 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7050 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007051 if (put_user_u16(high2lowgid(rgid), arg1)
7052 || put_user_u16(high2lowgid(egid), arg2)
7053 || put_user_u16(high2lowgid(sgid), arg3))
7054 goto efault;
bellard67867302003-11-23 17:05:30 +00007055 }
7056 }
7057 break;
7058#endif
7059 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007060 if (!(p = lock_user_string(arg1)))
7061 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007062 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7063 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007064 break;
7065 case TARGET_NR_setuid:
7066 ret = get_errno(setuid(low2highuid(arg1)));
7067 break;
7068 case TARGET_NR_setgid:
7069 ret = get_errno(setgid(low2highgid(arg1)));
7070 break;
7071 case TARGET_NR_setfsuid:
7072 ret = get_errno(setfsuid(arg1));
7073 break;
7074 case TARGET_NR_setfsgid:
7075 ret = get_errno(setfsgid(arg1));
7076 break;
bellard67867302003-11-23 17:05:30 +00007077
bellarda315a142005-01-30 22:59:18 +00007078#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007079 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007080 if (!(p = lock_user_string(arg1)))
7081 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007082 ret = get_errno(lchown(p, arg2, arg3));
7083 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007084 break;
bellarda315a142005-01-30 22:59:18 +00007085#endif
7086#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007087 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007088 ret = get_errno(getuid());
7089 break;
bellarda315a142005-01-30 22:59:18 +00007090#endif
aurel3264b4d282008-11-14 17:20:15 +00007091
7092#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7093 /* Alpha specific */
7094 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007095 {
7096 uid_t euid;
7097 euid=geteuid();
7098 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7099 }
aurel3264b4d282008-11-14 17:20:15 +00007100 ret = get_errno(getuid());
7101 break;
7102#endif
7103#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7104 /* Alpha specific */
7105 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007106 {
7107 uid_t egid;
7108 egid=getegid();
7109 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7110 }
aurel3264b4d282008-11-14 17:20:15 +00007111 ret = get_errno(getgid());
7112 break;
7113#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007114#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7115 /* Alpha specific */
7116 case TARGET_NR_osf_getsysinfo:
7117 ret = -TARGET_EOPNOTSUPP;
7118 switch (arg1) {
7119 case TARGET_GSI_IEEE_FP_CONTROL:
7120 {
7121 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7122
7123 /* Copied from linux ieee_fpcr_to_swcr. */
7124 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7125 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7126 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7127 | SWCR_TRAP_ENABLE_DZE
7128 | SWCR_TRAP_ENABLE_OVF);
7129 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7130 | SWCR_TRAP_ENABLE_INE);
7131 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7132 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7133
7134 if (put_user_u64 (swcr, arg2))
7135 goto efault;
7136 ret = 0;
7137 }
7138 break;
7139
7140 /* case GSI_IEEE_STATE_AT_SIGNAL:
7141 -- Not implemented in linux kernel.
7142 case GSI_UACPROC:
7143 -- Retrieves current unaligned access state; not much used.
7144 case GSI_PROC_TYPE:
7145 -- Retrieves implver information; surely not used.
7146 case GSI_GET_HWRPB:
7147 -- Grabs a copy of the HWRPB; surely not used.
7148 */
7149 }
7150 break;
7151#endif
7152#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7153 /* Alpha specific */
7154 case TARGET_NR_osf_setsysinfo:
7155 ret = -TARGET_EOPNOTSUPP;
7156 switch (arg1) {
7157 case TARGET_SSI_IEEE_FP_CONTROL:
7158 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7159 {
7160 uint64_t swcr, fpcr, orig_fpcr;
7161
7162 if (get_user_u64 (swcr, arg2))
7163 goto efault;
7164 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7165 fpcr = orig_fpcr & FPCR_DYN_MASK;
7166
7167 /* Copied from linux ieee_swcr_to_fpcr. */
7168 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7169 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7170 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7171 | SWCR_TRAP_ENABLE_DZE
7172 | SWCR_TRAP_ENABLE_OVF)) << 48;
7173 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7174 | SWCR_TRAP_ENABLE_INE)) << 57;
7175 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7176 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7177
7178 cpu_alpha_store_fpcr (cpu_env, fpcr);
7179 ret = 0;
7180
7181 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7182 /* Old exceptions are not signaled. */
7183 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7184
7185 /* If any exceptions set by this call, and are unmasked,
7186 send a signal. */
7187 /* ??? FIXME */
7188 }
7189 }
7190 break;
7191
7192 /* case SSI_NVPAIRS:
7193 -- Used with SSIN_UACPROC to enable unaligned accesses.
7194 case SSI_IEEE_STATE_AT_SIGNAL:
7195 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7196 -- Not implemented in linux kernel
7197 */
7198 }
7199 break;
7200#endif
7201#ifdef TARGET_NR_osf_sigprocmask
7202 /* Alpha specific. */
7203 case TARGET_NR_osf_sigprocmask:
7204 {
7205 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007206 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007207 sigset_t set, oldset;
7208
7209 switch(arg1) {
7210 case TARGET_SIG_BLOCK:
7211 how = SIG_BLOCK;
7212 break;
7213 case TARGET_SIG_UNBLOCK:
7214 how = SIG_UNBLOCK;
7215 break;
7216 case TARGET_SIG_SETMASK:
7217 how = SIG_SETMASK;
7218 break;
7219 default:
7220 ret = -TARGET_EINVAL;
7221 goto fail;
7222 }
7223 mask = arg2;
7224 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007225 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007226 host_to_target_old_sigset(&mask, &oldset);
7227 ret = mask;
7228 }
7229 break;
7230#endif
aurel3264b4d282008-11-14 17:20:15 +00007231
bellarda315a142005-01-30 22:59:18 +00007232#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007233 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007234 ret = get_errno(getgid());
7235 break;
bellarda315a142005-01-30 22:59:18 +00007236#endif
7237#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007238 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007239 ret = get_errno(geteuid());
7240 break;
bellarda315a142005-01-30 22:59:18 +00007241#endif
7242#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007243 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007244 ret = get_errno(getegid());
7245 break;
bellarda315a142005-01-30 22:59:18 +00007246#endif
7247#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007248 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007249 ret = get_errno(setreuid(arg1, arg2));
7250 break;
bellarda315a142005-01-30 22:59:18 +00007251#endif
7252#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007253 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007254 ret = get_errno(setregid(arg1, arg2));
7255 break;
bellarda315a142005-01-30 22:59:18 +00007256#endif
7257#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007258 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007259 {
7260 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007261 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007262 gid_t *grouplist;
7263 int i;
7264
7265 grouplist = alloca(gidsetsize * sizeof(gid_t));
7266 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007267 if (gidsetsize == 0)
7268 break;
bellard99c475a2005-01-31 20:45:13 +00007269 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007270 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7271 if (!target_grouplist) {
7272 ret = -TARGET_EFAULT;
7273 goto fail;
7274 }
balroga2155fc2008-09-20 02:12:08 +00007275 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007276 target_grouplist[i] = tswap32(grouplist[i]);
7277 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007278 }
7279 }
7280 break;
bellarda315a142005-01-30 22:59:18 +00007281#endif
7282#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007283 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007284 {
7285 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007286 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007287 gid_t *grouplist;
7288 int i;
ths3b46e622007-09-17 08:09:54 +00007289
bellard99c475a2005-01-31 20:45:13 +00007290 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007291 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7292 if (!target_grouplist) {
7293 ret = -TARGET_EFAULT;
7294 goto fail;
7295 }
bellard99c475a2005-01-31 20:45:13 +00007296 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007297 grouplist[i] = tswap32(target_grouplist[i]);
7298 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007299 ret = get_errno(setgroups(gidsetsize, grouplist));
7300 }
7301 break;
bellarda315a142005-01-30 22:59:18 +00007302#endif
7303#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007304 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007305 ret = get_errno(fchown(arg1, arg2, arg3));
7306 break;
bellarda315a142005-01-30 22:59:18 +00007307#endif
7308#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007309 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007310 ret = get_errno(setresuid(arg1, arg2, arg3));
7311 break;
bellarda315a142005-01-30 22:59:18 +00007312#endif
7313#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007314 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007315 {
pbrook53a59602006-03-25 19:31:22 +00007316 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007317 ret = get_errno(getresuid(&ruid, &euid, &suid));
7318 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007319 if (put_user_u32(ruid, arg1)
7320 || put_user_u32(euid, arg2)
7321 || put_user_u32(suid, arg3))
7322 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007323 }
7324 }
7325 break;
bellarda315a142005-01-30 22:59:18 +00007326#endif
7327#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007328 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007329 ret = get_errno(setresgid(arg1, arg2, arg3));
7330 break;
bellarda315a142005-01-30 22:59:18 +00007331#endif
7332#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007333 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007334 {
pbrook53a59602006-03-25 19:31:22 +00007335 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007336 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7337 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007338 if (put_user_u32(rgid, arg1)
7339 || put_user_u32(egid, arg2)
7340 || put_user_u32(sgid, arg3))
7341 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007342 }
7343 }
7344 break;
bellarda315a142005-01-30 22:59:18 +00007345#endif
7346#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007347 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007348 if (!(p = lock_user_string(arg1)))
7349 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007350 ret = get_errno(chown(p, arg2, arg3));
7351 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007352 break;
bellarda315a142005-01-30 22:59:18 +00007353#endif
7354#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007355 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007356 ret = get_errno(setuid(arg1));
7357 break;
bellarda315a142005-01-30 22:59:18 +00007358#endif
7359#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007360 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007361 ret = get_errno(setgid(arg1));
7362 break;
bellarda315a142005-01-30 22:59:18 +00007363#endif
7364#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007365 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007366 ret = get_errno(setfsuid(arg1));
7367 break;
bellarda315a142005-01-30 22:59:18 +00007368#endif
7369#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007370 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007371 ret = get_errno(setfsgid(arg1));
7372 break;
bellarda315a142005-01-30 22:59:18 +00007373#endif
bellard67867302003-11-23 17:05:30 +00007374
bellard31e31b82003-02-18 22:55:36 +00007375 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007376 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007377#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007378 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007379 {
7380 void *a;
7381 ret = -TARGET_EFAULT;
7382 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7383 goto efault;
7384 if (!(p = lock_user_string(arg3)))
7385 goto mincore_fail;
7386 ret = get_errno(mincore(a, arg2, p));
7387 unlock_user(p, arg3, ret);
7388 mincore_fail:
7389 unlock_user(a, arg1, 0);
7390 }
7391 break;
bellardffa65c32004-01-04 23:57:22 +00007392#endif
aurel32408321b2008-10-01 21:46:32 +00007393#ifdef TARGET_NR_arm_fadvise64_64
7394 case TARGET_NR_arm_fadvise64_64:
7395 {
7396 /*
7397 * arm_fadvise64_64 looks like fadvise64_64 but
7398 * with different argument order
7399 */
7400 abi_long temp;
7401 temp = arg3;
7402 arg3 = arg4;
7403 arg4 = temp;
7404 }
7405#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007406#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007407#ifdef TARGET_NR_fadvise64_64
7408 case TARGET_NR_fadvise64_64:
7409#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007410#ifdef TARGET_NR_fadvise64
7411 case TARGET_NR_fadvise64:
7412#endif
7413#ifdef TARGET_S390X
7414 switch (arg4) {
7415 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7416 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7417 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7418 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7419 default: break;
7420 }
7421#endif
7422 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007423 break;
7424#endif
bellardffa65c32004-01-04 23:57:22 +00007425#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007426 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007427 /* A straight passthrough may not be safe because qemu sometimes
7428 turns private flie-backed mappings into anonymous mappings.
7429 This will break MADV_DONTNEED.
7430 This is a hint, so ignoring and returning success is ok. */
7431 ret = get_errno(0);
7432 break;
bellardffa65c32004-01-04 23:57:22 +00007433#endif
blueswir1992f48a2007-10-14 16:27:31 +00007434#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007435 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007436 {
thsb1e341e2007-03-20 21:50:52 +00007437 int cmd;
bellard77e46722003-04-29 20:39:06 +00007438 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007439 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007440#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007441 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007442#endif
bellard77e46722003-04-29 20:39:06 +00007443
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007444 cmd = target_to_host_fcntl_cmd(arg2);
7445 if (cmd == -TARGET_EINVAL)
7446 return cmd;
thsb1e341e2007-03-20 21:50:52 +00007447
bellard60cd49d2003-03-16 22:53:56 +00007448 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007449 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007450#ifdef TARGET_ARM
7451 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007452 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7453 goto efault;
ths58134272007-03-31 18:59:32 +00007454 fl.l_type = tswap16(target_efl->l_type);
7455 fl.l_whence = tswap16(target_efl->l_whence);
7456 fl.l_start = tswap64(target_efl->l_start);
7457 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007458 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007459 unlock_user_struct(target_efl, arg3, 0);
7460 } else
7461#endif
7462 {
bellard9ee1fa22007-11-11 15:11:19 +00007463 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7464 goto efault;
ths58134272007-03-31 18:59:32 +00007465 fl.l_type = tswap16(target_fl->l_type);
7466 fl.l_whence = tswap16(target_fl->l_whence);
7467 fl.l_start = tswap64(target_fl->l_start);
7468 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007469 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007470 unlock_user_struct(target_fl, arg3, 0);
7471 }
thsb1e341e2007-03-20 21:50:52 +00007472 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007473 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007474#ifdef TARGET_ARM
7475 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007476 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7477 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007478 target_efl->l_type = tswap16(fl.l_type);
7479 target_efl->l_whence = tswap16(fl.l_whence);
7480 target_efl->l_start = tswap64(fl.l_start);
7481 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007482 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007483 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007484 } else
7485#endif
7486 {
bellard9ee1fa22007-11-11 15:11:19 +00007487 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7488 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007489 target_fl->l_type = tswap16(fl.l_type);
7490 target_fl->l_whence = tswap16(fl.l_whence);
7491 target_fl->l_start = tswap64(fl.l_start);
7492 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007493 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007494 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007495 }
bellard77e46722003-04-29 20:39:06 +00007496 }
7497 break;
7498
thsb1e341e2007-03-20 21:50:52 +00007499 case TARGET_F_SETLK64:
7500 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00007501#ifdef TARGET_ARM
7502 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007503 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7504 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007505 fl.l_type = tswap16(target_efl->l_type);
7506 fl.l_whence = tswap16(target_efl->l_whence);
7507 fl.l_start = tswap64(target_efl->l_start);
7508 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007509 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007510 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007511 } else
7512#endif
7513 {
bellard9ee1fa22007-11-11 15:11:19 +00007514 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7515 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007516 fl.l_type = tswap16(target_fl->l_type);
7517 fl.l_whence = tswap16(target_fl->l_whence);
7518 fl.l_start = tswap64(target_fl->l_start);
7519 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007520 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007521 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007522 }
thsb1e341e2007-03-20 21:50:52 +00007523 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007524 break;
bellard60cd49d2003-03-16 22:53:56 +00007525 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007526 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00007527 break;
7528 }
bellard77e46722003-04-29 20:39:06 +00007529 break;
7530 }
bellard60cd49d2003-03-16 22:53:56 +00007531#endif
ths7d600c82006-12-08 01:32:58 +00007532#ifdef TARGET_NR_cacheflush
7533 case TARGET_NR_cacheflush:
7534 /* self-modifying code is handled automatically, so nothing needed */
7535 ret = 0;
7536 break;
7537#endif
bellardebc05482003-09-30 21:08:41 +00007538#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00007539 case TARGET_NR_security:
7540 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007541#endif
bellardc573ff62004-01-04 15:51:36 +00007542#ifdef TARGET_NR_getpagesize
7543 case TARGET_NR_getpagesize:
7544 ret = TARGET_PAGE_SIZE;
7545 break;
7546#endif
bellard31e31b82003-02-18 22:55:36 +00007547 case TARGET_NR_gettid:
7548 ret = get_errno(gettid());
7549 break;
thse5febef2007-04-01 18:31:35 +00007550#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00007551 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00007552#if TARGET_ABI_BITS == 32
7553#ifdef TARGET_ARM
7554 if (((CPUARMState *)cpu_env)->eabi)
7555 {
7556 arg2 = arg3;
7557 arg3 = arg4;
7558 arg4 = arg5;
7559 }
7560#endif
7561 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
7562#else
7563 ret = get_errno(readahead(arg1, arg2, arg3));
7564#endif
7565 break;
thse5febef2007-04-01 18:31:35 +00007566#endif
bellardebc05482003-09-30 21:08:41 +00007567#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00007568 case TARGET_NR_setxattr:
7569 case TARGET_NR_lsetxattr:
7570 case TARGET_NR_fsetxattr:
7571 case TARGET_NR_getxattr:
7572 case TARGET_NR_lgetxattr:
7573 case TARGET_NR_fgetxattr:
7574 case TARGET_NR_listxattr:
7575 case TARGET_NR_llistxattr:
7576 case TARGET_NR_flistxattr:
7577 case TARGET_NR_removexattr:
7578 case TARGET_NR_lremovexattr:
7579 case TARGET_NR_fremovexattr:
Arnaud Patard6f932f92009-04-21 21:04:18 +03007580 ret = -TARGET_EOPNOTSUPP;
7581 break;
bellardebc05482003-09-30 21:08:41 +00007582#endif
7583#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00007584 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007585#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00007586 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
7587 ret = 0;
7588 break;
edgar_iglef967792009-01-07 14:19:38 +00007589#elif defined(TARGET_CRIS)
7590 if (arg1 & 0xff)
7591 ret = -TARGET_EINVAL;
7592 else {
7593 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
7594 ret = 0;
7595 }
7596 break;
bellard8d18e892007-11-14 15:18:40 +00007597#elif defined(TARGET_I386) && defined(TARGET_ABI32)
7598 ret = do_set_thread_area(cpu_env, arg1);
7599 break;
ths6f5b89a2007-03-02 20:48:00 +00007600#else
7601 goto unimplemented_nowarn;
7602#endif
7603#endif
7604#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00007605 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007606#if defined(TARGET_I386) && defined(TARGET_ABI32)
7607 ret = do_get_thread_area(cpu_env, arg1);
7608#else
bellard5cd43932003-03-29 16:54:36 +00007609 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00007610#endif
bellard8d18e892007-11-14 15:18:40 +00007611#endif
bellard48dc41e2006-06-21 18:15:50 +00007612#ifdef TARGET_NR_getdomainname
7613 case TARGET_NR_getdomainname:
7614 goto unimplemented_nowarn;
7615#endif
ths6f5b89a2007-03-02 20:48:00 +00007616
thsb5906f92007-03-19 13:32:45 +00007617#ifdef TARGET_NR_clock_gettime
7618 case TARGET_NR_clock_gettime:
7619 {
7620 struct timespec ts;
7621 ret = get_errno(clock_gettime(arg1, &ts));
7622 if (!is_error(ret)) {
7623 host_to_target_timespec(arg2, &ts);
7624 }
7625 break;
7626 }
7627#endif
7628#ifdef TARGET_NR_clock_getres
7629 case TARGET_NR_clock_getres:
7630 {
7631 struct timespec ts;
7632 ret = get_errno(clock_getres(arg1, &ts));
7633 if (!is_error(ret)) {
7634 host_to_target_timespec(arg2, &ts);
7635 }
7636 break;
7637 }
7638#endif
pbrook63d76512008-05-29 13:43:29 +00007639#ifdef TARGET_NR_clock_nanosleep
7640 case TARGET_NR_clock_nanosleep:
7641 {
7642 struct timespec ts;
7643 target_to_host_timespec(&ts, arg3);
7644 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
7645 if (arg4)
7646 host_to_target_timespec(arg4, &ts);
7647 break;
7648 }
7649#endif
thsb5906f92007-03-19 13:32:45 +00007650
ths6f5b89a2007-03-02 20:48:00 +00007651#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
7652 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00007653 ret = get_errno(set_tid_address((int *)g2h(arg1)));
7654 break;
ths6f5b89a2007-03-02 20:48:00 +00007655#endif
7656
ths3ae43202007-09-16 21:39:48 +00007657#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00007658 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00007659 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00007660 break;
7661#endif
7662
ths3ae43202007-09-16 21:39:48 +00007663#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00007664 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00007665 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
7666 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00007667 break;
7668#endif
7669
ths4f2b1fe2007-06-21 21:57:12 +00007670#ifdef TARGET_NR_set_robust_list
7671 case TARGET_NR_set_robust_list:
7672 goto unimplemented_nowarn;
7673#endif
7674
ths9007f0e2007-09-25 17:50:37 +00007675#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
7676 case TARGET_NR_utimensat:
7677 {
Riku Voipioebc996f2009-04-21 15:01:51 +03007678 struct timespec *tsp, ts[2];
7679 if (!arg3) {
7680 tsp = NULL;
7681 } else {
7682 target_to_host_timespec(ts, arg3);
7683 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
7684 tsp = ts;
7685 }
ths9007f0e2007-09-25 17:50:37 +00007686 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03007687 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00007688 else {
bellard579a97f2007-11-11 14:26:47 +00007689 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00007690 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00007691 goto fail;
7692 }
Riku Voipioebc996f2009-04-21 15:01:51 +03007693 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00007694 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00007695 }
7696 }
7697 break;
7698#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02007699#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00007700 case TARGET_NR_futex:
7701 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
7702 break;
7703#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007704#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00007705 case TARGET_NR_inotify_init:
7706 ret = get_errno(sys_inotify_init());
7707 break;
7708#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007709#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00007710#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
7711 case TARGET_NR_inotify_init1:
7712 ret = get_errno(sys_inotify_init1(arg1));
7713 break;
7714#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007715#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007716#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00007717 case TARGET_NR_inotify_add_watch:
7718 p = lock_user_string(arg2);
7719 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
7720 unlock_user(p, arg2, 0);
7721 break;
7722#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007723#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00007724 case TARGET_NR_inotify_rm_watch:
7725 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
7726 break;
7727#endif
ths9007f0e2007-09-25 17:50:37 +00007728
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07007729#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00007730 case TARGET_NR_mq_open:
7731 {
7732 struct mq_attr posix_mq_attr;
7733
7734 p = lock_user_string(arg1 - 1);
7735 if (arg4 != 0)
7736 copy_from_user_mq_attr (&posix_mq_attr, arg4);
7737 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
7738 unlock_user (p, arg1, 0);
7739 }
7740 break;
7741
7742 case TARGET_NR_mq_unlink:
7743 p = lock_user_string(arg1 - 1);
7744 ret = get_errno(mq_unlink(p));
7745 unlock_user (p, arg1, 0);
7746 break;
7747
7748 case TARGET_NR_mq_timedsend:
7749 {
7750 struct timespec ts;
7751
7752 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7753 if (arg5 != 0) {
7754 target_to_host_timespec(&ts, arg5);
7755 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
7756 host_to_target_timespec(arg5, &ts);
7757 }
7758 else
7759 ret = get_errno(mq_send(arg1, p, arg3, arg4));
7760 unlock_user (p, arg2, arg3);
7761 }
7762 break;
7763
7764 case TARGET_NR_mq_timedreceive:
7765 {
7766 struct timespec ts;
7767 unsigned int prio;
7768
7769 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7770 if (arg5 != 0) {
7771 target_to_host_timespec(&ts, arg5);
7772 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
7773 host_to_target_timespec(arg5, &ts);
7774 }
7775 else
7776 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
7777 unlock_user (p, arg2, arg3);
7778 if (arg4 != 0)
7779 put_user_u32(prio, arg4);
7780 }
7781 break;
7782
7783 /* Not implemented for now... */
7784/* case TARGET_NR_mq_notify: */
7785/* break; */
7786
7787 case TARGET_NR_mq_getsetattr:
7788 {
7789 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
7790 ret = 0;
7791 if (arg3 != 0) {
7792 ret = mq_getattr(arg1, &posix_mq_attr_out);
7793 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
7794 }
7795 if (arg2 != 0) {
7796 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
7797 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
7798 }
7799
7800 }
7801 break;
7802#endif
7803
vibisreenivasan3ce34df2009-05-16 18:32:41 +05307804#ifdef CONFIG_SPLICE
7805#ifdef TARGET_NR_tee
7806 case TARGET_NR_tee:
7807 {
7808 ret = get_errno(tee(arg1,arg2,arg3,arg4));
7809 }
7810 break;
7811#endif
7812#ifdef TARGET_NR_splice
7813 case TARGET_NR_splice:
7814 {
7815 loff_t loff_in, loff_out;
7816 loff_t *ploff_in = NULL, *ploff_out = NULL;
7817 if(arg2) {
7818 get_user_u64(loff_in, arg2);
7819 ploff_in = &loff_in;
7820 }
7821 if(arg4) {
7822 get_user_u64(loff_out, arg2);
7823 ploff_out = &loff_out;
7824 }
7825 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
7826 }
7827 break;
7828#endif
7829#ifdef TARGET_NR_vmsplice
7830 case TARGET_NR_vmsplice:
7831 {
7832 int count = arg3;
7833 struct iovec *vec;
7834
7835 vec = alloca(count * sizeof(struct iovec));
7836 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7837 goto efault;
7838 ret = get_errno(vmsplice(arg1, vec, count, arg4));
7839 unlock_iovec(vec, arg2, count, 0);
7840 }
7841 break;
7842#endif
7843#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03007844#ifdef CONFIG_EVENTFD
7845#if defined(TARGET_NR_eventfd)
7846 case TARGET_NR_eventfd:
7847 ret = get_errno(eventfd(arg1, 0));
7848 break;
7849#endif
7850#if defined(TARGET_NR_eventfd2)
7851 case TARGET_NR_eventfd2:
7852 ret = get_errno(eventfd(arg1, arg2));
7853 break;
7854#endif
7855#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03007856#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
7857 case TARGET_NR_fallocate:
7858 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
7859 break;
7860#endif
Peter Maydellc727f472011-01-06 11:05:10 +00007861#if defined(CONFIG_SYNC_FILE_RANGE)
7862#if defined(TARGET_NR_sync_file_range)
7863 case TARGET_NR_sync_file_range:
7864#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03007865#if defined(TARGET_MIPS)
7866 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7867 target_offset64(arg5, arg6), arg7));
7868#else
Peter Maydellc727f472011-01-06 11:05:10 +00007869 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
7870 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03007871#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00007872#else
7873 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
7874#endif
7875 break;
7876#endif
7877#if defined(TARGET_NR_sync_file_range2)
7878 case TARGET_NR_sync_file_range2:
7879 /* This is like sync_file_range but the arguments are reordered */
7880#if TARGET_ABI_BITS == 32
7881 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7882 target_offset64(arg5, arg6), arg2));
7883#else
7884 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
7885#endif
7886 break;
7887#endif
7888#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00007889#if defined(CONFIG_EPOLL)
7890#if defined(TARGET_NR_epoll_create)
7891 case TARGET_NR_epoll_create:
7892 ret = get_errno(epoll_create(arg1));
7893 break;
7894#endif
7895#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
7896 case TARGET_NR_epoll_create1:
7897 ret = get_errno(epoll_create1(arg1));
7898 break;
7899#endif
7900#if defined(TARGET_NR_epoll_ctl)
7901 case TARGET_NR_epoll_ctl:
7902 {
7903 struct epoll_event ep;
7904 struct epoll_event *epp = 0;
7905 if (arg4) {
7906 struct target_epoll_event *target_ep;
7907 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
7908 goto efault;
7909 }
7910 ep.events = tswap32(target_ep->events);
7911 /* The epoll_data_t union is just opaque data to the kernel,
7912 * so we transfer all 64 bits across and need not worry what
7913 * actual data type it is.
7914 */
7915 ep.data.u64 = tswap64(target_ep->data.u64);
7916 unlock_user_struct(target_ep, arg4, 0);
7917 epp = &ep;
7918 }
7919 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
7920 break;
7921 }
7922#endif
7923
7924#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
7925#define IMPLEMENT_EPOLL_PWAIT
7926#endif
7927#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
7928#if defined(TARGET_NR_epoll_wait)
7929 case TARGET_NR_epoll_wait:
7930#endif
7931#if defined(IMPLEMENT_EPOLL_PWAIT)
7932 case TARGET_NR_epoll_pwait:
7933#endif
7934 {
7935 struct target_epoll_event *target_ep;
7936 struct epoll_event *ep;
7937 int epfd = arg1;
7938 int maxevents = arg3;
7939 int timeout = arg4;
7940
7941 target_ep = lock_user(VERIFY_WRITE, arg2,
7942 maxevents * sizeof(struct target_epoll_event), 1);
7943 if (!target_ep) {
7944 goto efault;
7945 }
7946
7947 ep = alloca(maxevents * sizeof(struct epoll_event));
7948
7949 switch (num) {
7950#if defined(IMPLEMENT_EPOLL_PWAIT)
7951 case TARGET_NR_epoll_pwait:
7952 {
7953 target_sigset_t *target_set;
7954 sigset_t _set, *set = &_set;
7955
7956 if (arg5) {
7957 target_set = lock_user(VERIFY_READ, arg5,
7958 sizeof(target_sigset_t), 1);
7959 if (!target_set) {
7960 unlock_user(target_ep, arg2, 0);
7961 goto efault;
7962 }
7963 target_to_host_sigset(set, target_set);
7964 unlock_user(target_set, arg5, 0);
7965 } else {
7966 set = NULL;
7967 }
7968
7969 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
7970 break;
7971 }
7972#endif
7973#if defined(TARGET_NR_epoll_wait)
7974 case TARGET_NR_epoll_wait:
7975 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
7976 break;
7977#endif
7978 default:
7979 ret = -TARGET_ENOSYS;
7980 }
7981 if (!is_error(ret)) {
7982 int i;
7983 for (i = 0; i < ret; i++) {
7984 target_ep[i].events = tswap32(ep[i].events);
7985 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
7986 }
7987 }
7988 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
7989 break;
7990 }
7991#endif
7992#endif
bellard31e31b82003-02-18 22:55:36 +00007993 default:
7994 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00007995 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00007996#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 +00007997 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00007998#endif
ths0da46a62007-10-20 20:23:07 +00007999 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008000 break;
8001 }
bellard579a97f2007-11-11 14:26:47 +00008002fail:
bellardc573ff62004-01-04 15:51:36 +00008003#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008004 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008005#endif
thsb92c47c2007-11-01 00:07:38 +00008006 if(do_strace)
8007 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008008 return ret;
bellard579a97f2007-11-11 14:26:47 +00008009efault:
8010 ret = -TARGET_EFAULT;
8011 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008012}