blob: 1dd7aad43c63268b837eba82729aac654dd631c3 [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
Peter Maydell163a05a2011-06-27 17:44:52 +0100562#if defined(TARGET_NR_prlimit64)
563#ifndef __NR_prlimit64
564# define __NR_prlimit64 -1
565#endif
566#define __NR_sys_prlimit64 __NR_prlimit64
567/* The glibc rlimit structure may not be that used by the underlying syscall */
568struct host_rlimit64 {
569 uint64_t rlim_cur;
570 uint64_t rlim_max;
571};
572_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
573 const struct host_rlimit64 *, new_limit,
574 struct host_rlimit64 *, old_limit)
575#endif
576
bellard66fb9762003-03-23 01:06:05 +0000577extern int personality(int);
bellard9de5e442003-03-23 16:49:39 +0000578extern int flock(int, int);
579extern int setfsuid(int);
580extern int setfsgid(int);
bellard19b84f32003-05-08 15:41:49 +0000581extern int setgroups(int, gid_t *);
bellard31e31b82003-02-18 22:55:36 +0000582
Riku Voipio48e515d2011-07-12 15:40:51 +0300583/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
584#ifdef TARGET_ARM
585static inline int regpairs_aligned(void *cpu_env) {
586 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
587}
588#elif defined(TARGET_MIPS)
589static inline int regpairs_aligned(void *cpu_env) { return 1; }
590#else
591static inline int regpairs_aligned(void *cpu_env) { return 0; }
592#endif
593
thsb92c47c2007-11-01 00:07:38 +0000594#define ERRNO_TABLE_SIZE 1200
595
596/* target_to_host_errno_table[] is initialized from
597 * host_to_target_errno_table[] in syscall_init(). */
598static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
599};
600
ths637947f2007-06-01 12:09:19 +0000601/*
thsfe8f0962007-07-12 10:59:21 +0000602 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000603 * minus the errnos that are not actually generic to all archs.
604 */
thsb92c47c2007-11-01 00:07:38 +0000605static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000606 [EIDRM] = TARGET_EIDRM,
607 [ECHRNG] = TARGET_ECHRNG,
608 [EL2NSYNC] = TARGET_EL2NSYNC,
609 [EL3HLT] = TARGET_EL3HLT,
610 [EL3RST] = TARGET_EL3RST,
611 [ELNRNG] = TARGET_ELNRNG,
612 [EUNATCH] = TARGET_EUNATCH,
613 [ENOCSI] = TARGET_ENOCSI,
614 [EL2HLT] = TARGET_EL2HLT,
615 [EDEADLK] = TARGET_EDEADLK,
616 [ENOLCK] = TARGET_ENOLCK,
617 [EBADE] = TARGET_EBADE,
618 [EBADR] = TARGET_EBADR,
619 [EXFULL] = TARGET_EXFULL,
620 [ENOANO] = TARGET_ENOANO,
621 [EBADRQC] = TARGET_EBADRQC,
622 [EBADSLT] = TARGET_EBADSLT,
623 [EBFONT] = TARGET_EBFONT,
624 [ENOSTR] = TARGET_ENOSTR,
625 [ENODATA] = TARGET_ENODATA,
626 [ETIME] = TARGET_ETIME,
627 [ENOSR] = TARGET_ENOSR,
628 [ENONET] = TARGET_ENONET,
629 [ENOPKG] = TARGET_ENOPKG,
630 [EREMOTE] = TARGET_EREMOTE,
631 [ENOLINK] = TARGET_ENOLINK,
632 [EADV] = TARGET_EADV,
633 [ESRMNT] = TARGET_ESRMNT,
634 [ECOMM] = TARGET_ECOMM,
635 [EPROTO] = TARGET_EPROTO,
636 [EDOTDOT] = TARGET_EDOTDOT,
637 [EMULTIHOP] = TARGET_EMULTIHOP,
638 [EBADMSG] = TARGET_EBADMSG,
639 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
640 [EOVERFLOW] = TARGET_EOVERFLOW,
641 [ENOTUNIQ] = TARGET_ENOTUNIQ,
642 [EBADFD] = TARGET_EBADFD,
643 [EREMCHG] = TARGET_EREMCHG,
644 [ELIBACC] = TARGET_ELIBACC,
645 [ELIBBAD] = TARGET_ELIBBAD,
646 [ELIBSCN] = TARGET_ELIBSCN,
647 [ELIBMAX] = TARGET_ELIBMAX,
648 [ELIBEXEC] = TARGET_ELIBEXEC,
649 [EILSEQ] = TARGET_EILSEQ,
650 [ENOSYS] = TARGET_ENOSYS,
651 [ELOOP] = TARGET_ELOOP,
652 [ERESTART] = TARGET_ERESTART,
653 [ESTRPIPE] = TARGET_ESTRPIPE,
654 [ENOTEMPTY] = TARGET_ENOTEMPTY,
655 [EUSERS] = TARGET_EUSERS,
656 [ENOTSOCK] = TARGET_ENOTSOCK,
657 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
658 [EMSGSIZE] = TARGET_EMSGSIZE,
659 [EPROTOTYPE] = TARGET_EPROTOTYPE,
660 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
661 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
662 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
663 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
664 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
665 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
666 [EADDRINUSE] = TARGET_EADDRINUSE,
667 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
668 [ENETDOWN] = TARGET_ENETDOWN,
669 [ENETUNREACH] = TARGET_ENETUNREACH,
670 [ENETRESET] = TARGET_ENETRESET,
671 [ECONNABORTED] = TARGET_ECONNABORTED,
672 [ECONNRESET] = TARGET_ECONNRESET,
673 [ENOBUFS] = TARGET_ENOBUFS,
674 [EISCONN] = TARGET_EISCONN,
675 [ENOTCONN] = TARGET_ENOTCONN,
676 [EUCLEAN] = TARGET_EUCLEAN,
677 [ENOTNAM] = TARGET_ENOTNAM,
678 [ENAVAIL] = TARGET_ENAVAIL,
679 [EISNAM] = TARGET_EISNAM,
680 [EREMOTEIO] = TARGET_EREMOTEIO,
681 [ESHUTDOWN] = TARGET_ESHUTDOWN,
682 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
683 [ETIMEDOUT] = TARGET_ETIMEDOUT,
684 [ECONNREFUSED] = TARGET_ECONNREFUSED,
685 [EHOSTDOWN] = TARGET_EHOSTDOWN,
686 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
687 [EALREADY] = TARGET_EALREADY,
688 [EINPROGRESS] = TARGET_EINPROGRESS,
689 [ESTALE] = TARGET_ESTALE,
690 [ECANCELED] = TARGET_ECANCELED,
691 [ENOMEDIUM] = TARGET_ENOMEDIUM,
692 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000693#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000694 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000695#endif
696#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000697 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000698#endif
699#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000700 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000701#endif
702#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000703 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000704#endif
705#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000706 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000707#endif
708#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000709 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000710#endif
thsb92c47c2007-11-01 00:07:38 +0000711};
ths637947f2007-06-01 12:09:19 +0000712
713static inline int host_to_target_errno(int err)
714{
715 if(host_to_target_errno_table[err])
716 return host_to_target_errno_table[err];
717 return err;
718}
719
thsb92c47c2007-11-01 00:07:38 +0000720static inline int target_to_host_errno(int err)
721{
722 if (target_to_host_errno_table[err])
723 return target_to_host_errno_table[err];
724 return err;
725}
726
blueswir1992f48a2007-10-14 16:27:31 +0000727static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000728{
729 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000730 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000731 else
732 return ret;
733}
734
blueswir1992f48a2007-10-14 16:27:31 +0000735static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000736{
blueswir1992f48a2007-10-14 16:27:31 +0000737 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000738}
739
thsb92c47c2007-11-01 00:07:38 +0000740char *target_strerror(int err)
741{
742 return strerror(target_to_host_errno(err));
743}
744
blueswir1992f48a2007-10-14 16:27:31 +0000745static abi_ulong target_brk;
746static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000747static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000748
blueswir1992f48a2007-10-14 16:27:31 +0000749void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000750{
blueswir14c1de732007-07-07 20:45:44 +0000751 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000752 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000753}
754
vincent4d1de872011-06-14 21:56:33 +0000755//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
756#define DEBUGF_BRK(message, args...)
757
ths0da46a62007-10-20 20:23:07 +0000758/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000759abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000760{
blueswir1992f48a2007-10-14 16:27:31 +0000761 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000762 int new_alloc_size;
763
vincent4d1de872011-06-14 21:56:33 +0000764 DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000765
vincent4d1de872011-06-14 21:56:33 +0000766 if (!new_brk) {
767 DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
768 return target_brk;
769 }
770 if (new_brk < target_original_brk) {
771 DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
772 return target_brk;
773 }
bellard31e31b82003-02-18 22:55:36 +0000774
vincent4d1de872011-06-14 21:56:33 +0000775 /* If the new brk is less than the highest page reserved to the
776 * target heap allocation, set it and we're almost done... */
777 if (new_brk <= brk_page) {
778 /* Heap contents are initialized to zero, as for anonymous
779 * mapped pages. */
780 if (new_brk > target_brk) {
781 memset(g2h(target_brk), 0, new_brk - target_brk);
782 }
bellard31e31b82003-02-18 22:55:36 +0000783 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000784 DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000785 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000786 }
787
Peter Maydell00faf082011-04-18 16:34:24 +0100788 /* We need to allocate more memory after the brk... Note that
789 * we don't use MAP_FIXED because that will map over the top of
790 * any existing mapping (like the one with the host libc or qemu
791 * itself); instead we treat "mapped but at wrong address" as
792 * a failure and unmap again.
793 */
vincent4d1de872011-06-14 21:56:33 +0000794 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000795 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000796 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100797 MAP_ANON|MAP_PRIVATE, 0, 0));
798
799 if (mapped_addr == brk_page) {
800 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000801 brk_page = HOST_PAGE_ALIGN(target_brk);
802 DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100803 return target_brk;
804 } else if (mapped_addr != -1) {
805 /* Mapped but at wrong address, meaning there wasn't actually
806 * enough space for this brk.
807 */
808 target_munmap(mapped_addr, new_alloc_size);
809 mapped_addr = -1;
vincent4d1de872011-06-14 21:56:33 +0000810 DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
811 }
812 else {
813 DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100814 }
balrog7ab240a2008-04-26 12:17:34 +0000815
Richard Henderson7dd46c02010-05-03 10:07:49 -0700816#if defined(TARGET_ALPHA)
817 /* We (partially) emulate OSF/1 on Alpha, which requires we
818 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100819 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700820#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100821 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000822 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000823}
824
ths26edcf42007-12-09 02:25:24 +0000825static inline abi_long copy_from_user_fdset(fd_set *fds,
826 abi_ulong target_fds_addr,
827 int n)
bellard31e31b82003-02-18 22:55:36 +0000828{
ths26edcf42007-12-09 02:25:24 +0000829 int i, nw, j, k;
830 abi_ulong b, *target_fds;
831
832 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
833 if (!(target_fds = lock_user(VERIFY_READ,
834 target_fds_addr,
835 sizeof(abi_ulong) * nw,
836 1)))
837 return -TARGET_EFAULT;
838
839 FD_ZERO(fds);
840 k = 0;
841 for (i = 0; i < nw; i++) {
842 /* grab the abi_ulong */
843 __get_user(b, &target_fds[i]);
844 for (j = 0; j < TARGET_ABI_BITS; j++) {
845 /* check the bit inside the abi_ulong */
846 if ((b >> j) & 1)
847 FD_SET(k, fds);
848 k++;
bellard31e31b82003-02-18 22:55:36 +0000849 }
bellard31e31b82003-02-18 22:55:36 +0000850 }
ths26edcf42007-12-09 02:25:24 +0000851
852 unlock_user(target_fds, target_fds_addr, 0);
853
854 return 0;
bellard31e31b82003-02-18 22:55:36 +0000855}
856
Mike Frysinger055e0902011-06-03 17:01:49 -0400857static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
858 abi_ulong target_fds_addr,
859 int n)
860{
861 if (target_fds_addr) {
862 if (copy_from_user_fdset(fds, target_fds_addr, n))
863 return -TARGET_EFAULT;
864 *fds_ptr = fds;
865 } else {
866 *fds_ptr = NULL;
867 }
868 return 0;
869}
870
ths26edcf42007-12-09 02:25:24 +0000871static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
872 const fd_set *fds,
873 int n)
bellard31e31b82003-02-18 22:55:36 +0000874{
bellard31e31b82003-02-18 22:55:36 +0000875 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000876 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000877 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000878
ths26edcf42007-12-09 02:25:24 +0000879 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
880 if (!(target_fds = lock_user(VERIFY_WRITE,
881 target_fds_addr,
882 sizeof(abi_ulong) * nw,
883 0)))
884 return -TARGET_EFAULT;
885
886 k = 0;
887 for (i = 0; i < nw; i++) {
888 v = 0;
889 for (j = 0; j < TARGET_ABI_BITS; j++) {
890 v |= ((FD_ISSET(k, fds) != 0) << j);
891 k++;
bellard31e31b82003-02-18 22:55:36 +0000892 }
ths26edcf42007-12-09 02:25:24 +0000893 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000894 }
ths26edcf42007-12-09 02:25:24 +0000895
896 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
897
898 return 0;
bellard31e31b82003-02-18 22:55:36 +0000899}
900
bellardc596ed12003-07-13 17:32:31 +0000901#if defined(__alpha__)
902#define HOST_HZ 1024
903#else
904#define HOST_HZ 100
905#endif
906
blueswir1992f48a2007-10-14 16:27:31 +0000907static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000908{
909#if HOST_HZ == TARGET_HZ
910 return ticks;
911#else
912 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
913#endif
914}
915
bellard579a97f2007-11-11 14:26:47 +0000916static inline abi_long host_to_target_rusage(abi_ulong target_addr,
917 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000918{
pbrook53a59602006-03-25 19:31:22 +0000919 struct target_rusage *target_rusage;
920
bellard579a97f2007-11-11 14:26:47 +0000921 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
922 return -TARGET_EFAULT;
bellardb4091862003-05-16 15:39:34 +0000923 target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
924 target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
925 target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
926 target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
927 target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
928 target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
929 target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
930 target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
931 target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
932 target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
933 target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
934 target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
935 target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
936 target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
937 target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
938 target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
939 target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
940 target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000941 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000942
943 return 0;
bellardb4091862003-05-16 15:39:34 +0000944}
945
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900946static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
947{
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300948 target_ulong target_rlim_swap;
949 rlim_t result;
950
951 target_rlim_swap = tswapl(target_rlim);
952 if (target_rlim_swap == TARGET_RLIM_INFINITY || target_rlim_swap != (rlim_t)target_rlim_swap)
953 result = RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900954 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300955 result = target_rlim_swap;
956
957 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900958}
959
960static inline target_ulong host_to_target_rlim(rlim_t rlim)
961{
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300962 target_ulong target_rlim_swap;
963 target_ulong result;
964
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900965 if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300966 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900967 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300968 target_rlim_swap = rlim;
969 result = tswapl(target_rlim_swap);
970
971 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900972}
973
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300974static inline int target_to_host_resource(int code)
975{
976 switch (code) {
977 case TARGET_RLIMIT_AS:
978 return RLIMIT_AS;
979 case TARGET_RLIMIT_CORE:
980 return RLIMIT_CORE;
981 case TARGET_RLIMIT_CPU:
982 return RLIMIT_CPU;
983 case TARGET_RLIMIT_DATA:
984 return RLIMIT_DATA;
985 case TARGET_RLIMIT_FSIZE:
986 return RLIMIT_FSIZE;
987 case TARGET_RLIMIT_LOCKS:
988 return RLIMIT_LOCKS;
989 case TARGET_RLIMIT_MEMLOCK:
990 return RLIMIT_MEMLOCK;
991 case TARGET_RLIMIT_MSGQUEUE:
992 return RLIMIT_MSGQUEUE;
993 case TARGET_RLIMIT_NICE:
994 return RLIMIT_NICE;
995 case TARGET_RLIMIT_NOFILE:
996 return RLIMIT_NOFILE;
997 case TARGET_RLIMIT_NPROC:
998 return RLIMIT_NPROC;
999 case TARGET_RLIMIT_RSS:
1000 return RLIMIT_RSS;
1001 case TARGET_RLIMIT_RTPRIO:
1002 return RLIMIT_RTPRIO;
1003 case TARGET_RLIMIT_SIGPENDING:
1004 return RLIMIT_SIGPENDING;
1005 case TARGET_RLIMIT_STACK:
1006 return RLIMIT_STACK;
1007 default:
1008 return code;
1009 }
1010}
1011
ths788f5ec2007-12-09 02:37:05 +00001012static inline abi_long copy_from_user_timeval(struct timeval *tv,
1013 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001014{
pbrook53a59602006-03-25 19:31:22 +00001015 struct target_timeval *target_tv;
1016
ths788f5ec2007-12-09 02:37:05 +00001017 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001018 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001019
1020 __get_user(tv->tv_sec, &target_tv->tv_sec);
1021 __get_user(tv->tv_usec, &target_tv->tv_usec);
1022
1023 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001024
1025 return 0;
bellard31e31b82003-02-18 22:55:36 +00001026}
1027
ths788f5ec2007-12-09 02:37:05 +00001028static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1029 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001030{
pbrook53a59602006-03-25 19:31:22 +00001031 struct target_timeval *target_tv;
1032
ths788f5ec2007-12-09 02:37:05 +00001033 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001034 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001035
1036 __put_user(tv->tv_sec, &target_tv->tv_sec);
1037 __put_user(tv->tv_usec, &target_tv->tv_usec);
1038
1039 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001040
1041 return 0;
bellard31e31b82003-02-18 22:55:36 +00001042}
1043
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001044#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1045#include <mqueue.h>
1046
aurel3224e10032009-04-15 16:11:43 +00001047static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1048 abi_ulong target_mq_attr_addr)
1049{
1050 struct target_mq_attr *target_mq_attr;
1051
1052 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1053 target_mq_attr_addr, 1))
1054 return -TARGET_EFAULT;
1055
1056 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1057 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1058 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1059 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1060
1061 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1062
1063 return 0;
1064}
1065
1066static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1067 const struct mq_attr *attr)
1068{
1069 struct target_mq_attr *target_mq_attr;
1070
1071 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1072 target_mq_attr_addr, 0))
1073 return -TARGET_EFAULT;
1074
1075 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1076 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1077 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1078 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1079
1080 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1081
1082 return 0;
1083}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001084#endif
bellard31e31b82003-02-18 22:55:36 +00001085
Mike Frysinger055e0902011-06-03 17:01:49 -04001086#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001087/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001088static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001089 abi_ulong rfd_addr, abi_ulong wfd_addr,
1090 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001091{
1092 fd_set rfds, wfds, efds;
1093 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1094 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001095 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001096
Mike Frysinger055e0902011-06-03 17:01:49 -04001097 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1098 if (ret) {
1099 return ret;
pbrook53a59602006-03-25 19:31:22 +00001100 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001101 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1102 if (ret) {
1103 return ret;
pbrook53a59602006-03-25 19:31:22 +00001104 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001105 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1106 if (ret) {
1107 return ret;
pbrook53a59602006-03-25 19:31:22 +00001108 }
ths3b46e622007-09-17 08:09:54 +00001109
ths26edcf42007-12-09 02:25:24 +00001110 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001111 if (copy_from_user_timeval(&tv, target_tv_addr))
1112 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001113 tv_ptr = &tv;
1114 } else {
1115 tv_ptr = NULL;
1116 }
ths26edcf42007-12-09 02:25:24 +00001117
bellard31e31b82003-02-18 22:55:36 +00001118 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001119
ths26edcf42007-12-09 02:25:24 +00001120 if (!is_error(ret)) {
1121 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1122 return -TARGET_EFAULT;
1123 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1124 return -TARGET_EFAULT;
1125 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1126 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001127
ths788f5ec2007-12-09 02:37:05 +00001128 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1129 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001130 }
bellard579a97f2007-11-11 14:26:47 +00001131
bellard31e31b82003-02-18 22:55:36 +00001132 return ret;
1133}
Mike Frysinger055e0902011-06-03 17:01:49 -04001134#endif
bellard31e31b82003-02-18 22:55:36 +00001135
Riku Voipio099d6b02009-05-05 12:10:04 +03001136static abi_long do_pipe2(int host_pipe[], int flags)
1137{
1138#ifdef CONFIG_PIPE2
1139 return pipe2(host_pipe, flags);
1140#else
1141 return -ENOSYS;
1142#endif
1143}
1144
Richard Hendersonfb41a662010-05-03 10:07:52 -07001145static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1146 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001147{
1148 int host_pipe[2];
1149 abi_long ret;
1150 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1151
1152 if (is_error(ret))
1153 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001154
1155 /* Several targets have special calling conventions for the original
1156 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1157 if (!is_pipe2) {
1158#if defined(TARGET_ALPHA)
1159 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1160 return host_pipe[0];
1161#elif defined(TARGET_MIPS)
1162 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1163 return host_pipe[0];
1164#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001165 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001166 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001167#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001168 }
1169
Riku Voipio099d6b02009-05-05 12:10:04 +03001170 if (put_user_s32(host_pipe[0], pipedes)
1171 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1172 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001173 return get_errno(ret);
1174}
1175
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001176static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1177 abi_ulong target_addr,
1178 socklen_t len)
1179{
1180 struct target_ip_mreqn *target_smreqn;
1181
1182 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1183 if (!target_smreqn)
1184 return -TARGET_EFAULT;
1185 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1186 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1187 if (len == sizeof(struct target_ip_mreqn))
1188 mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
1189 unlock_user(target_smreqn, target_addr, 0);
1190
1191 return 0;
1192}
1193
bellard579a97f2007-11-11 14:26:47 +00001194static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1195 abi_ulong target_addr,
1196 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001197{
aurel32607175e2009-04-15 16:11:59 +00001198 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1199 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001200 struct target_sockaddr *target_saddr;
1201
bellard579a97f2007-11-11 14:26:47 +00001202 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1203 if (!target_saddr)
1204 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001205
1206 sa_family = tswap16(target_saddr->sa_family);
1207
1208 /* Oops. The caller might send a incomplete sun_path; sun_path
1209 * must be terminated by \0 (see the manual page), but
1210 * unfortunately it is quite common to specify sockaddr_un
1211 * length as "strlen(x->sun_path)" while it should be
1212 * "strlen(...) + 1". We'll fix that here if needed.
1213 * Linux kernel has a similar feature.
1214 */
1215
1216 if (sa_family == AF_UNIX) {
1217 if (len < unix_maxlen && len > 0) {
1218 char *cp = (char*)target_saddr;
1219
1220 if ( cp[len-1] && !cp[len] )
1221 len++;
1222 }
1223 if (len > unix_maxlen)
1224 len = unix_maxlen;
1225 }
1226
pbrook53a59602006-03-25 19:31:22 +00001227 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001228 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001229 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001230
1231 return 0;
bellard7854b052003-03-29 17:22:23 +00001232}
1233
bellard579a97f2007-11-11 14:26:47 +00001234static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1235 struct sockaddr *addr,
1236 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001237{
pbrook53a59602006-03-25 19:31:22 +00001238 struct target_sockaddr *target_saddr;
1239
bellard579a97f2007-11-11 14:26:47 +00001240 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1241 if (!target_saddr)
1242 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001243 memcpy(target_saddr, addr, len);
1244 target_saddr->sa_family = tswap16(addr->sa_family);
1245 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001246
1247 return 0;
bellard7854b052003-03-29 17:22:23 +00001248}
1249
pbrook53a59602006-03-25 19:31:22 +00001250/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001251static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1252 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001253{
1254 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001255 abi_long msg_controllen;
1256 abi_ulong target_cmsg_addr;
1257 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001258 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001259
1260 msg_controllen = tswapl(target_msgh->msg_controllen);
1261 if (msg_controllen < sizeof (struct target_cmsghdr))
1262 goto the_end;
1263 target_cmsg_addr = tswapl(target_msgh->msg_control);
1264 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1265 if (!target_cmsg)
1266 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001267
1268 while (cmsg && target_cmsg) {
1269 void *data = CMSG_DATA(cmsg);
1270 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1271
ths5fafdf22007-09-16 21:08:06 +00001272 int len = tswapl(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001273 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1274
1275 space += CMSG_SPACE(len);
1276 if (space > msgh->msg_controllen) {
1277 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001278 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001279 break;
1280 }
1281
1282 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1283 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1284 cmsg->cmsg_len = CMSG_LEN(len);
1285
bellard3532fa72006-06-24 15:06:03 +00001286 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001287 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1288 memcpy(data, target_data, len);
1289 } else {
1290 int *fd = (int *)data;
1291 int *target_fd = (int *)target_data;
1292 int i, numfds = len / sizeof(int);
1293
1294 for (i = 0; i < numfds; i++)
1295 fd[i] = tswap32(target_fd[i]);
1296 }
1297
1298 cmsg = CMSG_NXTHDR(msgh, cmsg);
1299 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1300 }
bellard5a4a8982007-11-11 17:39:18 +00001301 unlock_user(target_cmsg, target_cmsg_addr, 0);
1302 the_end:
bellard7854b052003-03-29 17:22:23 +00001303 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001304 return 0;
bellard7854b052003-03-29 17:22:23 +00001305}
1306
pbrook53a59602006-03-25 19:31:22 +00001307/* ??? Should this also swap msgh->name? */
bellard5a4a8982007-11-11 17:39:18 +00001308static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1309 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001310{
1311 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001312 abi_long msg_controllen;
1313 abi_ulong target_cmsg_addr;
1314 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001315 socklen_t space = 0;
1316
bellard5a4a8982007-11-11 17:39:18 +00001317 msg_controllen = tswapl(target_msgh->msg_controllen);
1318 if (msg_controllen < sizeof (struct target_cmsghdr))
1319 goto the_end;
1320 target_cmsg_addr = tswapl(target_msgh->msg_control);
1321 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1322 if (!target_cmsg)
1323 return -TARGET_EFAULT;
1324
bellard7854b052003-03-29 17:22:23 +00001325 while (cmsg && target_cmsg) {
1326 void *data = CMSG_DATA(cmsg);
1327 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1328
1329 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1330
1331 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001332 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001333 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001334 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001335 break;
1336 }
1337
1338 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1339 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
1340 target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
1341
bellard3532fa72006-06-24 15:06:03 +00001342 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001343 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1344 memcpy(target_data, data, len);
1345 } else {
1346 int *fd = (int *)data;
1347 int *target_fd = (int *)target_data;
1348 int i, numfds = len / sizeof(int);
1349
1350 for (i = 0; i < numfds; i++)
1351 target_fd[i] = tswap32(fd[i]);
1352 }
1353
1354 cmsg = CMSG_NXTHDR(msgh, cmsg);
1355 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1356 }
bellard5a4a8982007-11-11 17:39:18 +00001357 unlock_user(target_cmsg, target_cmsg_addr, space);
1358 the_end:
1359 target_msgh->msg_controllen = tswapl(space);
1360 return 0;
bellard7854b052003-03-29 17:22:23 +00001361}
1362
ths0da46a62007-10-20 20:23:07 +00001363/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001364static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001365 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001366{
blueswir1992f48a2007-10-14 16:27:31 +00001367 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001368 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001369 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001370 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001371
bellard8853f862004-02-22 14:57:26 +00001372 switch(level) {
1373 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001374 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001375 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001376 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001377
bellard2f619692007-11-16 10:46:05 +00001378 if (get_user_u32(val, optval_addr))
1379 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001380 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1381 break;
1382 case SOL_IP:
1383 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001384 case IP_TOS:
1385 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001386 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001387 case IP_ROUTER_ALERT:
1388 case IP_RECVOPTS:
1389 case IP_RETOPTS:
1390 case IP_PKTINFO:
1391 case IP_MTU_DISCOVER:
1392 case IP_RECVERR:
1393 case IP_RECVTOS:
1394#ifdef IP_FREEBIND
1395 case IP_FREEBIND:
1396#endif
1397 case IP_MULTICAST_TTL:
1398 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001399 val = 0;
1400 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001401 if (get_user_u32(val, optval_addr))
1402 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001403 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001404 if (get_user_u8(val, optval_addr))
1405 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001406 }
1407 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1408 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001409 case IP_ADD_MEMBERSHIP:
1410 case IP_DROP_MEMBERSHIP:
1411 if (optlen < sizeof (struct target_ip_mreq) ||
1412 optlen > sizeof (struct target_ip_mreqn))
1413 return -TARGET_EINVAL;
1414
1415 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1416 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1417 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1418 break;
1419
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001420 case IP_BLOCK_SOURCE:
1421 case IP_UNBLOCK_SOURCE:
1422 case IP_ADD_SOURCE_MEMBERSHIP:
1423 case IP_DROP_SOURCE_MEMBERSHIP:
1424 if (optlen != sizeof (struct target_ip_mreq_source))
1425 return -TARGET_EINVAL;
1426
1427 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1428 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1429 unlock_user (ip_mreq_source, optval_addr, 0);
1430 break;
1431
bellard8853f862004-02-22 14:57:26 +00001432 default:
1433 goto unimplemented;
1434 }
1435 break;
bellard3532fa72006-06-24 15:06:03 +00001436 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001437 switch (optname) {
1438 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001439 case TARGET_SO_DEBUG:
1440 optname = SO_DEBUG;
1441 break;
1442 case TARGET_SO_REUSEADDR:
1443 optname = SO_REUSEADDR;
1444 break;
1445 case TARGET_SO_TYPE:
1446 optname = SO_TYPE;
1447 break;
1448 case TARGET_SO_ERROR:
1449 optname = SO_ERROR;
1450 break;
1451 case TARGET_SO_DONTROUTE:
1452 optname = SO_DONTROUTE;
1453 break;
1454 case TARGET_SO_BROADCAST:
1455 optname = SO_BROADCAST;
1456 break;
1457 case TARGET_SO_SNDBUF:
1458 optname = SO_SNDBUF;
1459 break;
1460 case TARGET_SO_RCVBUF:
1461 optname = SO_RCVBUF;
1462 break;
1463 case TARGET_SO_KEEPALIVE:
1464 optname = SO_KEEPALIVE;
1465 break;
1466 case TARGET_SO_OOBINLINE:
1467 optname = SO_OOBINLINE;
1468 break;
1469 case TARGET_SO_NO_CHECK:
1470 optname = SO_NO_CHECK;
1471 break;
1472 case TARGET_SO_PRIORITY:
1473 optname = SO_PRIORITY;
1474 break;
bellard5e83e8e2005-03-01 22:32:06 +00001475#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001476 case TARGET_SO_BSDCOMPAT:
1477 optname = SO_BSDCOMPAT;
1478 break;
bellard5e83e8e2005-03-01 22:32:06 +00001479#endif
bellard3532fa72006-06-24 15:06:03 +00001480 case TARGET_SO_PASSCRED:
1481 optname = SO_PASSCRED;
1482 break;
1483 case TARGET_SO_TIMESTAMP:
1484 optname = SO_TIMESTAMP;
1485 break;
1486 case TARGET_SO_RCVLOWAT:
1487 optname = SO_RCVLOWAT;
1488 break;
1489 case TARGET_SO_RCVTIMEO:
1490 optname = SO_RCVTIMEO;
1491 break;
1492 case TARGET_SO_SNDTIMEO:
1493 optname = SO_SNDTIMEO;
1494 break;
bellard8853f862004-02-22 14:57:26 +00001495 break;
1496 default:
1497 goto unimplemented;
1498 }
bellard3532fa72006-06-24 15:06:03 +00001499 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001500 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001501
bellard2f619692007-11-16 10:46:05 +00001502 if (get_user_u32(val, optval_addr))
1503 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001504 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001505 break;
bellard7854b052003-03-29 17:22:23 +00001506 default:
bellard8853f862004-02-22 14:57:26 +00001507 unimplemented:
1508 gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001509 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001510 }
bellard8853f862004-02-22 14:57:26 +00001511 return ret;
bellard7854b052003-03-29 17:22:23 +00001512}
1513
ths0da46a62007-10-20 20:23:07 +00001514/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001515static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001516 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001517{
blueswir1992f48a2007-10-14 16:27:31 +00001518 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001519 int len, val;
1520 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001521
1522 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001523 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001524 level = SOL_SOCKET;
1525 switch (optname) {
1526 /* These don't just return a single integer */
1527 case TARGET_SO_LINGER:
1528 case TARGET_SO_RCVTIMEO:
1529 case TARGET_SO_SNDTIMEO:
1530 case TARGET_SO_PEERCRED:
1531 case TARGET_SO_PEERNAME:
1532 goto unimplemented;
1533 /* Options with 'int' argument. */
1534 case TARGET_SO_DEBUG:
1535 optname = SO_DEBUG;
1536 goto int_case;
1537 case TARGET_SO_REUSEADDR:
1538 optname = SO_REUSEADDR;
1539 goto int_case;
1540 case TARGET_SO_TYPE:
1541 optname = SO_TYPE;
1542 goto int_case;
1543 case TARGET_SO_ERROR:
1544 optname = SO_ERROR;
1545 goto int_case;
1546 case TARGET_SO_DONTROUTE:
1547 optname = SO_DONTROUTE;
1548 goto int_case;
1549 case TARGET_SO_BROADCAST:
1550 optname = SO_BROADCAST;
1551 goto int_case;
1552 case TARGET_SO_SNDBUF:
1553 optname = SO_SNDBUF;
1554 goto int_case;
1555 case TARGET_SO_RCVBUF:
1556 optname = SO_RCVBUF;
1557 goto int_case;
1558 case TARGET_SO_KEEPALIVE:
1559 optname = SO_KEEPALIVE;
1560 goto int_case;
1561 case TARGET_SO_OOBINLINE:
1562 optname = SO_OOBINLINE;
1563 goto int_case;
1564 case TARGET_SO_NO_CHECK:
1565 optname = SO_NO_CHECK;
1566 goto int_case;
1567 case TARGET_SO_PRIORITY:
1568 optname = SO_PRIORITY;
1569 goto int_case;
1570#ifdef SO_BSDCOMPAT
1571 case TARGET_SO_BSDCOMPAT:
1572 optname = SO_BSDCOMPAT;
1573 goto int_case;
1574#endif
1575 case TARGET_SO_PASSCRED:
1576 optname = SO_PASSCRED;
1577 goto int_case;
1578 case TARGET_SO_TIMESTAMP:
1579 optname = SO_TIMESTAMP;
1580 goto int_case;
1581 case TARGET_SO_RCVLOWAT:
1582 optname = SO_RCVLOWAT;
1583 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001584 default:
bellard2efbe912005-07-23 15:10:20 +00001585 goto int_case;
1586 }
1587 break;
1588 case SOL_TCP:
1589 /* TCP options all take an 'int' value. */
1590 int_case:
bellard2f619692007-11-16 10:46:05 +00001591 if (get_user_u32(len, optlen))
1592 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001593 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001594 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001595 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001596 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1597 if (ret < 0)
1598 return ret;
bellard2efbe912005-07-23 15:10:20 +00001599 if (len > lv)
1600 len = lv;
bellard2f619692007-11-16 10:46:05 +00001601 if (len == 4) {
1602 if (put_user_u32(val, optval_addr))
1603 return -TARGET_EFAULT;
1604 } else {
1605 if (put_user_u8(val, optval_addr))
1606 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001607 }
bellard2f619692007-11-16 10:46:05 +00001608 if (put_user_u32(len, optlen))
1609 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001610 break;
1611 case SOL_IP:
1612 switch(optname) {
1613 case IP_TOS:
1614 case IP_TTL:
1615 case IP_HDRINCL:
1616 case IP_ROUTER_ALERT:
1617 case IP_RECVOPTS:
1618 case IP_RETOPTS:
1619 case IP_PKTINFO:
1620 case IP_MTU_DISCOVER:
1621 case IP_RECVERR:
1622 case IP_RECVTOS:
1623#ifdef IP_FREEBIND
1624 case IP_FREEBIND:
1625#endif
1626 case IP_MULTICAST_TTL:
1627 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001628 if (get_user_u32(len, optlen))
1629 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001630 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001631 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001632 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001633 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1634 if (ret < 0)
1635 return ret;
bellard2efbe912005-07-23 15:10:20 +00001636 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001637 len = 1;
bellard2f619692007-11-16 10:46:05 +00001638 if (put_user_u32(len, optlen)
1639 || put_user_u8(val, optval_addr))
1640 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001641 } else {
bellard2efbe912005-07-23 15:10:20 +00001642 if (len > sizeof(int))
1643 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001644 if (put_user_u32(len, optlen)
1645 || put_user_u32(val, optval_addr))
1646 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001647 }
bellard8853f862004-02-22 14:57:26 +00001648 break;
bellard2efbe912005-07-23 15:10:20 +00001649 default:
thsc02f4992007-12-18 02:39:59 +00001650 ret = -TARGET_ENOPROTOOPT;
1651 break;
bellard8853f862004-02-22 14:57:26 +00001652 }
1653 break;
1654 default:
1655 unimplemented:
1656 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1657 level, optname);
thsc02f4992007-12-18 02:39:59 +00001658 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001659 break;
1660 }
1661 return ret;
bellard7854b052003-03-29 17:22:23 +00001662}
1663
bellard579a97f2007-11-11 14:26:47 +00001664/* FIXME
1665 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
1666 * other lock functions have a return code of 0 for failure.
1667 */
1668static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
1669 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001670{
1671 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001672 abi_ulong base;
balrogd732dcb2008-10-28 10:21:03 +00001673 int i;
pbrook53a59602006-03-25 19:31:22 +00001674
bellard579a97f2007-11-11 14:26:47 +00001675 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1676 if (!target_vec)
1677 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001678 for(i = 0;i < count; i++) {
1679 base = tswapl(target_vec[i].iov_base);
1680 vec[i].iov_len = tswapl(target_vec[i].iov_len);
bellard41df8412008-02-04 22:26:57 +00001681 if (vec[i].iov_len != 0) {
1682 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
balrogd732dcb2008-10-28 10:21:03 +00001683 /* Don't check lock_user return value. We must call writev even
1684 if a element has invalid base address. */
bellard41df8412008-02-04 22:26:57 +00001685 } else {
1686 /* zero length pointer is ignored */
1687 vec[i].iov_base = NULL;
1688 }
pbrook53a59602006-03-25 19:31:22 +00001689 }
1690 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001691 return 0;
pbrook53a59602006-03-25 19:31:22 +00001692}
1693
bellard579a97f2007-11-11 14:26:47 +00001694static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1695 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001696{
1697 struct target_iovec *target_vec;
blueswir1992f48a2007-10-14 16:27:31 +00001698 abi_ulong base;
pbrook53a59602006-03-25 19:31:22 +00001699 int i;
1700
bellard579a97f2007-11-11 14:26:47 +00001701 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
1702 if (!target_vec)
1703 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001704 for(i = 0;i < count; i++) {
balrogd732dcb2008-10-28 10:21:03 +00001705 if (target_vec[i].iov_base) {
1706 base = tswapl(target_vec[i].iov_base);
1707 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1708 }
pbrook53a59602006-03-25 19:31:22 +00001709 }
1710 unlock_user (target_vec, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001711
1712 return 0;
pbrook53a59602006-03-25 19:31:22 +00001713}
1714
ths0da46a62007-10-20 20:23:07 +00001715/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001716static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001717{
1718#if defined(TARGET_MIPS)
1719 switch(type) {
1720 case TARGET_SOCK_DGRAM:
1721 type = SOCK_DGRAM;
1722 break;
1723 case TARGET_SOCK_STREAM:
1724 type = SOCK_STREAM;
1725 break;
1726 case TARGET_SOCK_RAW:
1727 type = SOCK_RAW;
1728 break;
1729 case TARGET_SOCK_RDM:
1730 type = SOCK_RDM;
1731 break;
1732 case TARGET_SOCK_SEQPACKET:
1733 type = SOCK_SEQPACKET;
1734 break;
1735 case TARGET_SOCK_PACKET:
1736 type = SOCK_PACKET;
1737 break;
1738 }
1739#endif
balrog12bc92a2007-10-30 21:06:14 +00001740 if (domain == PF_NETLINK)
1741 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001742 return get_errno(socket(domain, type, protocol));
1743}
1744
ths0da46a62007-10-20 20:23:07 +00001745/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001746static abi_long do_bind(int sockfd, abi_ulong target_addr,
1747 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001748{
aurel328f7aeaf2009-01-30 19:47:57 +00001749 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001750 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001751
Blue Swirl38724252010-09-18 05:53:14 +00001752 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001753 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001754 }
aurel328f7aeaf2009-01-30 19:47:57 +00001755
aurel32607175e2009-04-15 16:11:59 +00001756 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001757
Arnaud Patard917507b2009-06-19 10:44:45 +03001758 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1759 if (ret)
1760 return ret;
1761
bellard3532fa72006-06-24 15:06:03 +00001762 return get_errno(bind(sockfd, addr, addrlen));
1763}
1764
ths0da46a62007-10-20 20:23:07 +00001765/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001766static abi_long do_connect(int sockfd, abi_ulong target_addr,
1767 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001768{
aurel328f7aeaf2009-01-30 19:47:57 +00001769 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001770 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001771
Blue Swirl38724252010-09-18 05:53:14 +00001772 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001773 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001774 }
aurel328f7aeaf2009-01-30 19:47:57 +00001775
1776 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001777
Arnaud Patard917507b2009-06-19 10:44:45 +03001778 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1779 if (ret)
1780 return ret;
1781
bellard3532fa72006-06-24 15:06:03 +00001782 return get_errno(connect(sockfd, addr, addrlen));
1783}
1784
ths0da46a62007-10-20 20:23:07 +00001785/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001786static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1787 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001788{
balrog6de645c2008-10-28 10:26:29 +00001789 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001790 struct target_msghdr *msgp;
1791 struct msghdr msg;
1792 int count;
1793 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001794 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001795
bellard579a97f2007-11-11 14:26:47 +00001796 /* FIXME */
1797 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1798 msgp,
1799 target_msg,
1800 send ? 1 : 0))
1801 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001802 if (msgp->msg_name) {
1803 msg.msg_namelen = tswap32(msgp->msg_namelen);
1804 msg.msg_name = alloca(msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001805 ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001806 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001807 if (ret) {
1808 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
1809 return ret;
1810 }
bellard3532fa72006-06-24 15:06:03 +00001811 } else {
1812 msg.msg_name = NULL;
1813 msg.msg_namelen = 0;
1814 }
1815 msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
1816 msg.msg_control = alloca(msg.msg_controllen);
1817 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001818
bellard3532fa72006-06-24 15:06:03 +00001819 count = tswapl(msgp->msg_iovlen);
1820 vec = alloca(count * sizeof(struct iovec));
1821 target_vec = tswapl(msgp->msg_iov);
bellard579a97f2007-11-11 14:26:47 +00001822 lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
bellard3532fa72006-06-24 15:06:03 +00001823 msg.msg_iovlen = count;
1824 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001825
bellard3532fa72006-06-24 15:06:03 +00001826 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001827 ret = target_to_host_cmsg(&msg, msgp);
1828 if (ret == 0)
1829 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001830 } else {
1831 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001832 if (!is_error(ret)) {
1833 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001834 ret = host_to_target_cmsg(msgp, &msg);
balrog6de645c2008-10-28 10:26:29 +00001835 if (!is_error(ret))
1836 ret = len;
1837 }
bellard3532fa72006-06-24 15:06:03 +00001838 }
1839 unlock_iovec(vec, target_vec, count, !send);
bellard579a97f2007-11-11 14:26:47 +00001840 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001841 return ret;
1842}
1843
ths0da46a62007-10-20 20:23:07 +00001844/* do_accept() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001845static abi_long do_accept(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001846 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001847{
bellard2f619692007-11-16 10:46:05 +00001848 socklen_t addrlen;
1849 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001850 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001851
Arnaud Patard917507b2009-06-19 10:44:45 +03001852 if (target_addr == 0)
1853 return get_errno(accept(fd, NULL, NULL));
1854
1855 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00001856 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03001857 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00001858
Blue Swirl38724252010-09-18 05:53:14 +00001859 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001860 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001861 }
aurel328f7aeaf2009-01-30 19:47:57 +00001862
Arnaud Patard917507b2009-06-19 10:44:45 +03001863 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1864 return -TARGET_EINVAL;
1865
bellard2f619692007-11-16 10:46:05 +00001866 addr = alloca(addrlen);
1867
pbrook1be9e1d2006-11-19 15:26:04 +00001868 ret = get_errno(accept(fd, addr, &addrlen));
1869 if (!is_error(ret)) {
1870 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001871 if (put_user_u32(addrlen, target_addrlen_addr))
1872 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001873 }
1874 return ret;
1875}
1876
ths0da46a62007-10-20 20:23:07 +00001877/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001878static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001879 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001880{
bellard2f619692007-11-16 10:46:05 +00001881 socklen_t addrlen;
1882 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001883 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001884
bellard2f619692007-11-16 10:46:05 +00001885 if (get_user_u32(addrlen, target_addrlen_addr))
1886 return -TARGET_EFAULT;
1887
Blue Swirl38724252010-09-18 05:53:14 +00001888 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001889 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001890 }
aurel328f7aeaf2009-01-30 19:47:57 +00001891
Arnaud Patard917507b2009-06-19 10:44:45 +03001892 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1893 return -TARGET_EFAULT;
1894
bellard2f619692007-11-16 10:46:05 +00001895 addr = alloca(addrlen);
1896
pbrook1be9e1d2006-11-19 15:26:04 +00001897 ret = get_errno(getpeername(fd, addr, &addrlen));
1898 if (!is_error(ret)) {
1899 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001900 if (put_user_u32(addrlen, target_addrlen_addr))
1901 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001902 }
1903 return ret;
1904}
1905
ths0da46a62007-10-20 20:23:07 +00001906/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001907static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00001908 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001909{
bellard2f619692007-11-16 10:46:05 +00001910 socklen_t addrlen;
1911 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00001912 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001913
bellard2f619692007-11-16 10:46:05 +00001914 if (get_user_u32(addrlen, target_addrlen_addr))
1915 return -TARGET_EFAULT;
1916
Blue Swirl38724252010-09-18 05:53:14 +00001917 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001918 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001919 }
aurel328f7aeaf2009-01-30 19:47:57 +00001920
Arnaud Patard917507b2009-06-19 10:44:45 +03001921 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
1922 return -TARGET_EFAULT;
1923
bellard2f619692007-11-16 10:46:05 +00001924 addr = alloca(addrlen);
1925
pbrook1be9e1d2006-11-19 15:26:04 +00001926 ret = get_errno(getsockname(fd, addr, &addrlen));
1927 if (!is_error(ret)) {
1928 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00001929 if (put_user_u32(addrlen, target_addrlen_addr))
1930 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001931 }
1932 return ret;
1933}
1934
ths0da46a62007-10-20 20:23:07 +00001935/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001936static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00001937 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00001938{
1939 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00001940 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001941
1942 ret = get_errno(socketpair(domain, type, protocol, tab));
1943 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00001944 if (put_user_s32(tab[0], target_tab_addr)
1945 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
1946 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001947 }
1948 return ret;
1949}
1950
ths0da46a62007-10-20 20:23:07 +00001951/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001952static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
1953 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001954{
1955 void *addr;
1956 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001957 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001958
Blue Swirl38724252010-09-18 05:53:14 +00001959 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001960 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001961 }
aurel328f7aeaf2009-01-30 19:47:57 +00001962
bellard579a97f2007-11-11 14:26:47 +00001963 host_msg = lock_user(VERIFY_READ, msg, len, 1);
1964 if (!host_msg)
1965 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001966 if (target_addr) {
1967 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001968 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1969 if (ret) {
1970 unlock_user(host_msg, msg, 0);
1971 return ret;
1972 }
pbrook1be9e1d2006-11-19 15:26:04 +00001973 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
1974 } else {
1975 ret = get_errno(send(fd, host_msg, len, flags));
1976 }
1977 unlock_user(host_msg, msg, 0);
1978 return ret;
1979}
1980
ths0da46a62007-10-20 20:23:07 +00001981/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001982static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
1983 abi_ulong target_addr,
1984 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00001985{
1986 socklen_t addrlen;
1987 void *addr;
1988 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00001989 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00001990
bellard579a97f2007-11-11 14:26:47 +00001991 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
1992 if (!host_msg)
1993 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00001994 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00001995 if (get_user_u32(addrlen, target_addrlen)) {
1996 ret = -TARGET_EFAULT;
1997 goto fail;
1998 }
Blue Swirl38724252010-09-18 05:53:14 +00001999 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002000 ret = -TARGET_EINVAL;
2001 goto fail;
2002 }
pbrook1be9e1d2006-11-19 15:26:04 +00002003 addr = alloca(addrlen);
2004 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2005 } else {
2006 addr = NULL; /* To keep compiler quiet. */
2007 ret = get_errno(recv(fd, host_msg, len, flags));
2008 }
2009 if (!is_error(ret)) {
2010 if (target_addr) {
2011 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002012 if (put_user_u32(addrlen, target_addrlen)) {
2013 ret = -TARGET_EFAULT;
2014 goto fail;
2015 }
pbrook1be9e1d2006-11-19 15:26:04 +00002016 }
2017 unlock_user(host_msg, msg, len);
2018 } else {
bellard2f619692007-11-16 10:46:05 +00002019fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002020 unlock_user(host_msg, msg, 0);
2021 }
2022 return ret;
2023}
2024
j_mayer32407102007-09-26 23:01:49 +00002025#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002026/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002027static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002028{
blueswir1992f48a2007-10-14 16:27:31 +00002029 abi_long ret;
2030 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002031
2032 switch(num) {
2033 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002034 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002035 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002036
Ulrich Hecht98818182009-07-03 17:09:28 +02002037 if (get_user_ual(domain, vptr)
2038 || get_user_ual(type, vptr + n)
2039 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002040 return -TARGET_EFAULT;
2041
bellard3532fa72006-06-24 15:06:03 +00002042 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002043 }
bellard31e31b82003-02-18 22:55:36 +00002044 break;
2045 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002046 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002047 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002048 abi_ulong target_addr;
2049 socklen_t addrlen;
2050
Ulrich Hecht98818182009-07-03 17:09:28 +02002051 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002052 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002053 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002054 return -TARGET_EFAULT;
2055
bellard3532fa72006-06-24 15:06:03 +00002056 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002057 }
bellard31e31b82003-02-18 22:55:36 +00002058 break;
2059 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002060 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002061 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002062 abi_ulong target_addr;
2063 socklen_t addrlen;
2064
Ulrich Hecht98818182009-07-03 17:09:28 +02002065 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002066 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002067 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002068 return -TARGET_EFAULT;
2069
bellard3532fa72006-06-24 15:06:03 +00002070 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002071 }
bellard31e31b82003-02-18 22:55:36 +00002072 break;
2073 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002074 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002075 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002076
Ulrich Hecht98818182009-07-03 17:09:28 +02002077 if (get_user_ual(sockfd, vptr)
2078 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002079 return -TARGET_EFAULT;
2080
bellard7854b052003-03-29 17:22:23 +00002081 ret = get_errno(listen(sockfd, backlog));
2082 }
bellard31e31b82003-02-18 22:55:36 +00002083 break;
2084 case SOCKOP_accept:
2085 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002086 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002087 abi_ulong target_addr, target_addrlen;
2088
Ulrich Hecht98818182009-07-03 17:09:28 +02002089 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002090 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002091 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002092 return -TARGET_EFAULT;
2093
pbrook1be9e1d2006-11-19 15:26:04 +00002094 ret = do_accept(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002095 }
2096 break;
2097 case SOCKOP_getsockname:
2098 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002099 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002100 abi_ulong target_addr, target_addrlen;
2101
Ulrich Hecht98818182009-07-03 17:09:28 +02002102 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002103 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002104 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002105 return -TARGET_EFAULT;
2106
pbrook1be9e1d2006-11-19 15:26:04 +00002107 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002108 }
2109 break;
2110 case SOCKOP_getpeername:
2111 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002112 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002113 abi_ulong target_addr, target_addrlen;
2114
Ulrich Hecht98818182009-07-03 17:09:28 +02002115 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002116 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002117 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002118 return -TARGET_EFAULT;
2119
pbrook1be9e1d2006-11-19 15:26:04 +00002120 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002121 }
2122 break;
2123 case SOCKOP_socketpair:
2124 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002125 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002126 abi_ulong tab;
2127
Ulrich Hecht98818182009-07-03 17:09:28 +02002128 if (get_user_ual(domain, vptr)
2129 || get_user_ual(type, vptr + n)
2130 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002131 || get_user_ual(tab, vptr + 3 * n))
2132 return -TARGET_EFAULT;
2133
pbrook1be9e1d2006-11-19 15:26:04 +00002134 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002135 }
2136 break;
2137 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002138 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002139 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002140 abi_ulong msg;
2141 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002142 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002143
Ulrich Hecht98818182009-07-03 17:09:28 +02002144 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002145 || get_user_ual(msg, vptr + n)
2146 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002147 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002148 return -TARGET_EFAULT;
2149
pbrook1be9e1d2006-11-19 15:26:04 +00002150 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002151 }
bellard31e31b82003-02-18 22:55:36 +00002152 break;
2153 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002154 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002155 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002156 abi_ulong msg;
2157 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002158 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002159
Ulrich Hecht98818182009-07-03 17:09:28 +02002160 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002161 || get_user_ual(msg, vptr + n)
2162 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002163 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002164 return -TARGET_EFAULT;
2165
pbrook1be9e1d2006-11-19 15:26:04 +00002166 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002167 }
bellard31e31b82003-02-18 22:55:36 +00002168 break;
2169 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002170 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002171 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002172 abi_ulong msg;
2173 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002174 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002175 abi_ulong addr;
2176 socklen_t addrlen;
2177
Ulrich Hecht98818182009-07-03 17:09:28 +02002178 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002179 || get_user_ual(msg, vptr + n)
2180 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002181 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002182 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002183 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002184 return -TARGET_EFAULT;
2185
pbrook1be9e1d2006-11-19 15:26:04 +00002186 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002187 }
bellard31e31b82003-02-18 22:55:36 +00002188 break;
2189 case SOCKOP_recvfrom:
2190 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002191 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002192 abi_ulong msg;
2193 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002194 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002195 abi_ulong addr;
2196 socklen_t addrlen;
2197
Ulrich Hecht98818182009-07-03 17:09:28 +02002198 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002199 || get_user_ual(msg, vptr + n)
2200 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002201 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002202 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002203 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002204 return -TARGET_EFAULT;
2205
pbrook1be9e1d2006-11-19 15:26:04 +00002206 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002207 }
2208 break;
2209 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002210 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002211 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002212
Ulrich Hecht98818182009-07-03 17:09:28 +02002213 if (get_user_ual(sockfd, vptr)
2214 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002215 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002216
2217 ret = get_errno(shutdown(sockfd, how));
2218 }
bellard31e31b82003-02-18 22:55:36 +00002219 break;
2220 case SOCKOP_sendmsg:
2221 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002222 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002223 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002224 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002225 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002226
Ulrich Hecht98818182009-07-03 17:09:28 +02002227 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002228 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002229 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002230 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002231
ths5fafdf22007-09-16 21:08:06 +00002232 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002233 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002234 }
2235 break;
bellard31e31b82003-02-18 22:55:36 +00002236 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002237 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002238 abi_ulong sockfd;
2239 abi_ulong level;
2240 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002241 abi_ulong optval;
2242 socklen_t optlen;
2243
Ulrich Hecht98818182009-07-03 17:09:28 +02002244 if (get_user_ual(sockfd, vptr)
2245 || get_user_ual(level, vptr + n)
2246 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002247 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002248 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002249 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002250
2251 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2252 }
2253 break;
bellard31e31b82003-02-18 22:55:36 +00002254 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002255 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002256 abi_ulong sockfd;
2257 abi_ulong level;
2258 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002259 abi_ulong optval;
2260 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002261
Ulrich Hecht98818182009-07-03 17:09:28 +02002262 if (get_user_ual(sockfd, vptr)
2263 || get_user_ual(level, vptr + n)
2264 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002265 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002266 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002267 return -TARGET_EFAULT;
2268
2269 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002270 }
2271 break;
bellard31e31b82003-02-18 22:55:36 +00002272 default:
2273 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002274 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002275 break;
2276 }
2277 return ret;
2278}
j_mayer32407102007-09-26 23:01:49 +00002279#endif
bellard31e31b82003-02-18 22:55:36 +00002280
bellard8853f862004-02-22 14:57:26 +00002281#define N_SHM_REGIONS 32
2282
2283static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002284 abi_ulong start;
2285 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002286} shm_regions[N_SHM_REGIONS];
2287
ths3eb6b042007-06-03 14:26:27 +00002288struct target_ipc_perm
2289{
blueswir1992f48a2007-10-14 16:27:31 +00002290 abi_long __key;
2291 abi_ulong uid;
2292 abi_ulong gid;
2293 abi_ulong cuid;
2294 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002295 unsigned short int mode;
2296 unsigned short int __pad1;
2297 unsigned short int __seq;
2298 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002299 abi_ulong __unused1;
2300 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002301};
2302
2303struct target_semid_ds
2304{
2305 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002306 abi_ulong sem_otime;
2307 abi_ulong __unused1;
2308 abi_ulong sem_ctime;
2309 abi_ulong __unused2;
2310 abi_ulong sem_nsems;
2311 abi_ulong __unused3;
2312 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002313};
2314
bellard579a97f2007-11-11 14:26:47 +00002315static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2316 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002317{
2318 struct target_ipc_perm *target_ip;
2319 struct target_semid_ds *target_sd;
2320
bellard579a97f2007-11-11 14:26:47 +00002321 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2322 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002323 target_ip = &(target_sd->sem_perm);
ths3eb6b042007-06-03 14:26:27 +00002324 host_ip->__key = tswapl(target_ip->__key);
2325 host_ip->uid = tswapl(target_ip->uid);
2326 host_ip->gid = tswapl(target_ip->gid);
2327 host_ip->cuid = tswapl(target_ip->cuid);
2328 host_ip->cgid = tswapl(target_ip->cgid);
2329 host_ip->mode = tswapl(target_ip->mode);
2330 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002331 return 0;
ths3eb6b042007-06-03 14:26:27 +00002332}
2333
bellard579a97f2007-11-11 14:26:47 +00002334static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2335 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002336{
2337 struct target_ipc_perm *target_ip;
2338 struct target_semid_ds *target_sd;
2339
bellard579a97f2007-11-11 14:26:47 +00002340 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2341 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002342 target_ip = &(target_sd->sem_perm);
2343 target_ip->__key = tswapl(host_ip->__key);
2344 target_ip->uid = tswapl(host_ip->uid);
2345 target_ip->gid = tswapl(host_ip->gid);
2346 target_ip->cuid = tswapl(host_ip->cuid);
2347 target_ip->cgid = tswapl(host_ip->cgid);
2348 target_ip->mode = tswapl(host_ip->mode);
2349 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002350 return 0;
ths3eb6b042007-06-03 14:26:27 +00002351}
2352
bellard579a97f2007-11-11 14:26:47 +00002353static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2354 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002355{
2356 struct target_semid_ds *target_sd;
2357
bellard579a97f2007-11-11 14:26:47 +00002358 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2359 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002360 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2361 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002362 host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
2363 host_sd->sem_otime = tswapl(target_sd->sem_otime);
2364 host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
2365 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002366 return 0;
ths3eb6b042007-06-03 14:26:27 +00002367}
2368
bellard579a97f2007-11-11 14:26:47 +00002369static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2370 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002371{
2372 struct target_semid_ds *target_sd;
2373
bellard579a97f2007-11-11 14:26:47 +00002374 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2375 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002376 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
2377 return -TARGET_EFAULT;;
ths3eb6b042007-06-03 14:26:27 +00002378 target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
2379 target_sd->sem_otime = tswapl(host_sd->sem_otime);
2380 target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
2381 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002382 return 0;
ths3eb6b042007-06-03 14:26:27 +00002383}
2384
aurel32e5289082009-04-18 16:16:12 +00002385struct target_seminfo {
2386 int semmap;
2387 int semmni;
2388 int semmns;
2389 int semmnu;
2390 int semmsl;
2391 int semopm;
2392 int semume;
2393 int semusz;
2394 int semvmx;
2395 int semaem;
2396};
2397
2398static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2399 struct seminfo *host_seminfo)
2400{
2401 struct target_seminfo *target_seminfo;
2402 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2403 return -TARGET_EFAULT;
2404 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2405 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2406 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2407 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2408 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2409 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2410 __put_user(host_seminfo->semume, &target_seminfo->semume);
2411 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2412 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2413 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2414 unlock_user_struct(target_seminfo, target_addr, 1);
2415 return 0;
2416}
2417
thsfa294812007-02-02 22:05:00 +00002418union semun {
2419 int val;
ths3eb6b042007-06-03 14:26:27 +00002420 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002421 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002422 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002423};
2424
ths3eb6b042007-06-03 14:26:27 +00002425union target_semun {
2426 int val;
aurel32e5289082009-04-18 16:16:12 +00002427 abi_ulong buf;
2428 abi_ulong array;
2429 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002430};
2431
aurel32e5289082009-04-18 16:16:12 +00002432static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2433 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002434{
aurel32e5289082009-04-18 16:16:12 +00002435 int nsems;
2436 unsigned short *array;
2437 union semun semun;
2438 struct semid_ds semid_ds;
2439 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002440
aurel32e5289082009-04-18 16:16:12 +00002441 semun.buf = &semid_ds;
2442
2443 ret = semctl(semid, 0, IPC_STAT, semun);
2444 if (ret == -1)
2445 return get_errno(ret);
2446
2447 nsems = semid_ds.sem_nsems;
2448
2449 *host_array = malloc(nsems*sizeof(unsigned short));
2450 array = lock_user(VERIFY_READ, target_addr,
2451 nsems*sizeof(unsigned short), 1);
2452 if (!array)
2453 return -TARGET_EFAULT;
2454
2455 for(i=0; i<nsems; i++) {
2456 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002457 }
aurel32e5289082009-04-18 16:16:12 +00002458 unlock_user(array, target_addr, 0);
2459
bellard579a97f2007-11-11 14:26:47 +00002460 return 0;
ths3eb6b042007-06-03 14:26:27 +00002461}
2462
aurel32e5289082009-04-18 16:16:12 +00002463static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2464 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002465{
aurel32e5289082009-04-18 16:16:12 +00002466 int nsems;
2467 unsigned short *array;
2468 union semun semun;
2469 struct semid_ds semid_ds;
2470 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002471
aurel32e5289082009-04-18 16:16:12 +00002472 semun.buf = &semid_ds;
2473
2474 ret = semctl(semid, 0, IPC_STAT, semun);
2475 if (ret == -1)
2476 return get_errno(ret);
2477
2478 nsems = semid_ds.sem_nsems;
2479
2480 array = lock_user(VERIFY_WRITE, target_addr,
2481 nsems*sizeof(unsigned short), 0);
2482 if (!array)
2483 return -TARGET_EFAULT;
2484
2485 for(i=0; i<nsems; i++) {
2486 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002487 }
aurel32e5289082009-04-18 16:16:12 +00002488 free(*host_array);
2489 unlock_user(array, target_addr, 1);
2490
bellard579a97f2007-11-11 14:26:47 +00002491 return 0;
ths3eb6b042007-06-03 14:26:27 +00002492}
2493
aurel32e5289082009-04-18 16:16:12 +00002494static inline abi_long do_semctl(int semid, int semnum, int cmd,
2495 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002496{
2497 union semun arg;
2498 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302499 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002500 struct seminfo seminfo;
2501 abi_long ret = -TARGET_EINVAL;
2502 abi_long err;
2503 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002504
2505 switch( cmd ) {
2506 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002507 case SETVAL:
aurel32e5289082009-04-18 16:16:12 +00002508 arg.val = tswapl(target_su.val);
2509 ret = get_errno(semctl(semid, semnum, cmd, arg));
2510 target_su.val = tswapl(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002511 break;
2512 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002513 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002514 err = target_to_host_semarray(semid, &array, target_su.array);
2515 if (err)
2516 return err;
2517 arg.array = array;
2518 ret = get_errno(semctl(semid, semnum, cmd, arg));
2519 err = host_to_target_semarray(semid, target_su.array, &array);
2520 if (err)
2521 return err;
ths3eb6b042007-06-03 14:26:27 +00002522 break;
2523 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002524 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002525 case SEM_STAT:
2526 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2527 if (err)
2528 return err;
2529 arg.buf = &dsarg;
2530 ret = get_errno(semctl(semid, semnum, cmd, arg));
2531 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2532 if (err)
2533 return err;
ths3eb6b042007-06-03 14:26:27 +00002534 break;
aurel32e5289082009-04-18 16:16:12 +00002535 case IPC_INFO:
2536 case SEM_INFO:
2537 arg.__buf = &seminfo;
2538 ret = get_errno(semctl(semid, semnum, cmd, arg));
2539 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2540 if (err)
2541 return err;
2542 break;
2543 case IPC_RMID:
2544 case GETPID:
2545 case GETNCNT:
2546 case GETZCNT:
2547 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2548 break;
ths3eb6b042007-06-03 14:26:27 +00002549 }
2550
2551 return ret;
2552}
2553
aurel32e5289082009-04-18 16:16:12 +00002554struct target_sembuf {
2555 unsigned short sem_num;
2556 short sem_op;
2557 short sem_flg;
2558};
2559
2560static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2561 abi_ulong target_addr,
2562 unsigned nsops)
2563{
2564 struct target_sembuf *target_sembuf;
2565 int i;
2566
2567 target_sembuf = lock_user(VERIFY_READ, target_addr,
2568 nsops*sizeof(struct target_sembuf), 1);
2569 if (!target_sembuf)
2570 return -TARGET_EFAULT;
2571
2572 for(i=0; i<nsops; i++) {
2573 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2574 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2575 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2576 }
2577
2578 unlock_user(target_sembuf, target_addr, 0);
2579
2580 return 0;
2581}
2582
2583static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2584{
2585 struct sembuf sops[nsops];
2586
2587 if (target_to_host_sembuf(sops, ptr, nsops))
2588 return -TARGET_EFAULT;
2589
2590 return semop(semid, sops, nsops);
2591}
2592
ths1bc012f2007-06-03 14:27:49 +00002593struct target_msqid_ds
2594{
aurel321c54ff92008-10-13 21:08:44 +00002595 struct target_ipc_perm msg_perm;
2596 abi_ulong msg_stime;
2597#if TARGET_ABI_BITS == 32
2598 abi_ulong __unused1;
2599#endif
2600 abi_ulong msg_rtime;
2601#if TARGET_ABI_BITS == 32
2602 abi_ulong __unused2;
2603#endif
2604 abi_ulong msg_ctime;
2605#if TARGET_ABI_BITS == 32
2606 abi_ulong __unused3;
2607#endif
2608 abi_ulong __msg_cbytes;
2609 abi_ulong msg_qnum;
2610 abi_ulong msg_qbytes;
2611 abi_ulong msg_lspid;
2612 abi_ulong msg_lrpid;
2613 abi_ulong __unused4;
2614 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002615};
2616
bellard579a97f2007-11-11 14:26:47 +00002617static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2618 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002619{
2620 struct target_msqid_ds *target_md;
2621
bellard579a97f2007-11-11 14:26:47 +00002622 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2623 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002624 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2625 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002626 host_md->msg_stime = tswapl(target_md->msg_stime);
2627 host_md->msg_rtime = tswapl(target_md->msg_rtime);
2628 host_md->msg_ctime = tswapl(target_md->msg_ctime);
2629 host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
2630 host_md->msg_qnum = tswapl(target_md->msg_qnum);
2631 host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
2632 host_md->msg_lspid = tswapl(target_md->msg_lspid);
2633 host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
2634 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002635 return 0;
ths1bc012f2007-06-03 14:27:49 +00002636}
2637
bellard579a97f2007-11-11 14:26:47 +00002638static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2639 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002640{
2641 struct target_msqid_ds *target_md;
2642
bellard579a97f2007-11-11 14:26:47 +00002643 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2644 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002645 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2646 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002647 target_md->msg_stime = tswapl(host_md->msg_stime);
2648 target_md->msg_rtime = tswapl(host_md->msg_rtime);
2649 target_md->msg_ctime = tswapl(host_md->msg_ctime);
2650 target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
2651 target_md->msg_qnum = tswapl(host_md->msg_qnum);
2652 target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
2653 target_md->msg_lspid = tswapl(host_md->msg_lspid);
2654 target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
2655 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002656 return 0;
ths1bc012f2007-06-03 14:27:49 +00002657}
2658
aurel321c54ff92008-10-13 21:08:44 +00002659struct target_msginfo {
2660 int msgpool;
2661 int msgmap;
2662 int msgmax;
2663 int msgmnb;
2664 int msgmni;
2665 int msgssz;
2666 int msgtql;
2667 unsigned short int msgseg;
2668};
2669
2670static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2671 struct msginfo *host_msginfo)
2672{
2673 struct target_msginfo *target_msginfo;
2674 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2675 return -TARGET_EFAULT;
2676 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2677 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2678 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2679 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2680 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2681 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2682 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2683 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2684 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002685 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002686}
2687
2688static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002689{
2690 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002691 struct msginfo msginfo;
2692 abi_long ret = -TARGET_EINVAL;
2693
2694 cmd &= 0xff;
2695
2696 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002697 case IPC_STAT:
2698 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002699 case MSG_STAT:
2700 if (target_to_host_msqid_ds(&dsarg,ptr))
2701 return -TARGET_EFAULT;
2702 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2703 if (host_to_target_msqid_ds(ptr,&dsarg))
2704 return -TARGET_EFAULT;
2705 break;
2706 case IPC_RMID:
2707 ret = get_errno(msgctl(msgid, cmd, NULL));
2708 break;
2709 case IPC_INFO:
2710 case MSG_INFO:
2711 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2712 if (host_to_target_msginfo(ptr, &msginfo))
2713 return -TARGET_EFAULT;
2714 break;
ths1bc012f2007-06-03 14:27:49 +00002715 }
aurel321c54ff92008-10-13 21:08:44 +00002716
ths1bc012f2007-06-03 14:27:49 +00002717 return ret;
2718}
2719
2720struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002721 abi_long mtype;
2722 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002723};
2724
blueswir1992f48a2007-10-14 16:27:31 +00002725static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2726 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002727{
2728 struct target_msgbuf *target_mb;
2729 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002730 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002731
bellard579a97f2007-11-11 14:26:47 +00002732 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2733 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002734 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002735 host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
2736 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002737 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2738 free(host_mb);
2739 unlock_user_struct(target_mb, msgp, 0);
2740
2741 return ret;
2742}
2743
blueswir1992f48a2007-10-14 16:27:31 +00002744static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002745 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002746 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002747{
2748 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002749 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002750 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002751 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002752
bellard579a97f2007-11-11 14:26:47 +00002753 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2754 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002755
ths1bc012f2007-06-03 14:27:49 +00002756 host_mb = malloc(msgsz+sizeof(long));
aurel321c54ff92008-10-13 21:08:44 +00002757 ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
2758
bellard579a97f2007-11-11 14:26:47 +00002759 if (ret > 0) {
2760 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2761 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2762 if (!target_mtext) {
2763 ret = -TARGET_EFAULT;
2764 goto end;
2765 }
aurel321c54ff92008-10-13 21:08:44 +00002766 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002767 unlock_user(target_mtext, target_mtext_addr, ret);
2768 }
aurel321c54ff92008-10-13 21:08:44 +00002769
ths1bc012f2007-06-03 14:27:49 +00002770 target_mb->mtype = tswapl(host_mb->mtype);
2771 free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002772
bellard579a97f2007-11-11 14:26:47 +00002773end:
2774 if (target_mb)
2775 unlock_user_struct(target_mb, msgp, 1);
ths1bc012f2007-06-03 14:27:49 +00002776 return ret;
2777}
2778
Riku Voipio88a8c982009-04-03 10:42:00 +03002779struct target_shmid_ds
2780{
2781 struct target_ipc_perm shm_perm;
2782 abi_ulong shm_segsz;
2783 abi_ulong shm_atime;
2784#if TARGET_ABI_BITS == 32
2785 abi_ulong __unused1;
2786#endif
2787 abi_ulong shm_dtime;
2788#if TARGET_ABI_BITS == 32
2789 abi_ulong __unused2;
2790#endif
2791 abi_ulong shm_ctime;
2792#if TARGET_ABI_BITS == 32
2793 abi_ulong __unused3;
2794#endif
2795 int shm_cpid;
2796 int shm_lpid;
2797 abi_ulong shm_nattch;
2798 unsigned long int __unused4;
2799 unsigned long int __unused5;
2800};
2801
2802static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2803 abi_ulong target_addr)
2804{
2805 struct target_shmid_ds *target_sd;
2806
2807 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2808 return -TARGET_EFAULT;
2809 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2810 return -TARGET_EFAULT;
2811 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2812 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2813 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2814 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2815 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2816 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2817 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2818 unlock_user_struct(target_sd, target_addr, 0);
2819 return 0;
2820}
2821
2822static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2823 struct shmid_ds *host_sd)
2824{
2825 struct target_shmid_ds *target_sd;
2826
2827 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2828 return -TARGET_EFAULT;
2829 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2830 return -TARGET_EFAULT;
2831 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2832 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2833 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2834 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2835 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2836 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2837 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2838 unlock_user_struct(target_sd, target_addr, 1);
2839 return 0;
2840}
2841
2842struct target_shminfo {
2843 abi_ulong shmmax;
2844 abi_ulong shmmin;
2845 abi_ulong shmmni;
2846 abi_ulong shmseg;
2847 abi_ulong shmall;
2848};
2849
2850static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2851 struct shminfo *host_shminfo)
2852{
2853 struct target_shminfo *target_shminfo;
2854 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2855 return -TARGET_EFAULT;
2856 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2857 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2858 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2859 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2860 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2861 unlock_user_struct(target_shminfo, target_addr, 1);
2862 return 0;
2863}
2864
2865struct target_shm_info {
2866 int used_ids;
2867 abi_ulong shm_tot;
2868 abi_ulong shm_rss;
2869 abi_ulong shm_swp;
2870 abi_ulong swap_attempts;
2871 abi_ulong swap_successes;
2872};
2873
2874static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2875 struct shm_info *host_shm_info)
2876{
2877 struct target_shm_info *target_shm_info;
2878 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2879 return -TARGET_EFAULT;
2880 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2881 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2882 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2883 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2884 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2885 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2886 unlock_user_struct(target_shm_info, target_addr, 1);
2887 return 0;
2888}
2889
2890static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2891{
2892 struct shmid_ds dsarg;
2893 struct shminfo shminfo;
2894 struct shm_info shm_info;
2895 abi_long ret = -TARGET_EINVAL;
2896
2897 cmd &= 0xff;
2898
2899 switch(cmd) {
2900 case IPC_STAT:
2901 case IPC_SET:
2902 case SHM_STAT:
2903 if (target_to_host_shmid_ds(&dsarg, buf))
2904 return -TARGET_EFAULT;
2905 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2906 if (host_to_target_shmid_ds(buf, &dsarg))
2907 return -TARGET_EFAULT;
2908 break;
2909 case IPC_INFO:
2910 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2911 if (host_to_target_shminfo(buf, &shminfo))
2912 return -TARGET_EFAULT;
2913 break;
2914 case SHM_INFO:
2915 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2916 if (host_to_target_shm_info(buf, &shm_info))
2917 return -TARGET_EFAULT;
2918 break;
2919 case IPC_RMID:
2920 case SHM_LOCK:
2921 case SHM_UNLOCK:
2922 ret = get_errno(shmctl(shmid, cmd, NULL));
2923 break;
2924 }
2925
2926 return ret;
2927}
2928
2929static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2930{
2931 abi_long raddr;
2932 void *host_raddr;
2933 struct shmid_ds shm_info;
2934 int i,ret;
2935
2936 /* find out the length of the shared memory segment */
2937 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2938 if (is_error(ret)) {
2939 /* can't get length, bail out */
2940 return ret;
2941 }
2942
2943 mmap_lock();
2944
2945 if (shmaddr)
2946 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2947 else {
2948 abi_ulong mmap_start;
2949
2950 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2951
2952 if (mmap_start == -1) {
2953 errno = ENOMEM;
2954 host_raddr = (void *)-1;
2955 } else
2956 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2957 }
2958
2959 if (host_raddr == (void *)-1) {
2960 mmap_unlock();
2961 return get_errno((long)host_raddr);
2962 }
2963 raddr=h2g((unsigned long)host_raddr);
2964
2965 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2966 PAGE_VALID | PAGE_READ |
2967 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2968
2969 for (i = 0; i < N_SHM_REGIONS; i++) {
2970 if (shm_regions[i].start == 0) {
2971 shm_regions[i].start = raddr;
2972 shm_regions[i].size = shm_info.shm_segsz;
2973 break;
2974 }
2975 }
2976
2977 mmap_unlock();
2978 return raddr;
2979
2980}
2981
2982static inline abi_long do_shmdt(abi_ulong shmaddr)
2983{
2984 int i;
2985
2986 for (i = 0; i < N_SHM_REGIONS; ++i) {
2987 if (shm_regions[i].start == shmaddr) {
2988 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09002989 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03002990 break;
2991 }
2992 }
2993
2994 return get_errno(shmdt(g2h(shmaddr)));
2995}
2996
aurel321c54ff92008-10-13 21:08:44 +00002997#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00002998/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00002999/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003000static abi_long do_ipc(unsigned int call, int first,
3001 int second, int third,
3002 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003003{
3004 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003005 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003006
3007 version = call >> 16;
3008 call &= 0xffff;
3009
3010 switch (call) {
thsfa294812007-02-02 22:05:00 +00003011 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003012 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003013 break;
3014
3015 case IPCOP_semget:
3016 ret = get_errno(semget(first, second, third));
3017 break;
3018
3019 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003020 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003021 break;
thsd96372e2007-02-02 22:05:44 +00003022
aurel321c54ff92008-10-13 21:08:44 +00003023 case IPCOP_msgget:
3024 ret = get_errno(msgget(first, second));
3025 break;
thsd96372e2007-02-02 22:05:44 +00003026
aurel321c54ff92008-10-13 21:08:44 +00003027 case IPCOP_msgsnd:
3028 ret = do_msgsnd(first, ptr, second, third);
3029 break;
thsd96372e2007-02-02 22:05:44 +00003030
aurel321c54ff92008-10-13 21:08:44 +00003031 case IPCOP_msgctl:
3032 ret = do_msgctl(first, second, ptr);
3033 break;
thsd96372e2007-02-02 22:05:44 +00003034
aurel321c54ff92008-10-13 21:08:44 +00003035 case IPCOP_msgrcv:
3036 switch (version) {
3037 case 0:
3038 {
3039 struct target_ipc_kludge {
3040 abi_long msgp;
3041 abi_long msgtyp;
3042 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003043
aurel321c54ff92008-10-13 21:08:44 +00003044 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3045 ret = -TARGET_EFAULT;
3046 break;
ths1bc012f2007-06-03 14:27:49 +00003047 }
aurel321c54ff92008-10-13 21:08:44 +00003048
3049 ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
3050
3051 unlock_user_struct(tmp, ptr, 0);
3052 break;
3053 }
3054 default:
3055 ret = do_msgrcv(first, ptr, second, fifth, third);
3056 }
3057 break;
thsd96372e2007-02-02 22:05:44 +00003058
bellard8853f862004-02-22 14:57:26 +00003059 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003060 switch (version) {
3061 default:
bellard5a4a8982007-11-11 17:39:18 +00003062 {
3063 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003064 raddr = do_shmat(first, ptr, second);
3065 if (is_error(raddr))
3066 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003067 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003068 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003069 break;
3070 }
3071 case 1:
3072 ret = -TARGET_EINVAL;
3073 break;
bellard5a4a8982007-11-11 17:39:18 +00003074 }
bellard8853f862004-02-22 14:57:26 +00003075 break;
3076 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003077 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003078 break;
3079
3080 case IPCOP_shmget:
3081 /* IPC_* flag values are the same on all linux platforms */
3082 ret = get_errno(shmget(first, second, third));
3083 break;
3084
3085 /* IPC_* and SHM_* command values are the same on all linux platforms */
3086 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003087 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003088 break;
3089 default:
j_mayer32407102007-09-26 23:01:49 +00003090 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003091 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003092 break;
3093 }
3094 return ret;
3095}
j_mayer32407102007-09-26 23:01:49 +00003096#endif
bellard8853f862004-02-22 14:57:26 +00003097
bellard31e31b82003-02-18 22:55:36 +00003098/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003099
Blue Swirl001faf32009-05-13 17:53:17 +00003100#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003101#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3102enum {
3103#include "syscall_types.h"
3104};
3105#undef STRUCT
3106#undef STRUCT_SPECIAL
3107
Blue Swirl001faf32009-05-13 17:53:17 +00003108#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003109#define STRUCT_SPECIAL(name)
3110#include "syscall_types.h"
3111#undef STRUCT
3112#undef STRUCT_SPECIAL
3113
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003114typedef struct IOCTLEntry IOCTLEntry;
3115
3116typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3117 int fd, abi_long cmd, abi_long arg);
3118
3119struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003120 unsigned int target_cmd;
3121 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003122 const char *name;
3123 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003124 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003125 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003126};
bellard31e31b82003-02-18 22:55:36 +00003127
3128#define IOC_R 0x0001
3129#define IOC_W 0x0002
3130#define IOC_RW (IOC_R | IOC_W)
3131
3132#define MAX_STRUCT_SIZE 4096
3133
Peter Maydelldace20d2011-01-10 13:11:24 +00003134#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003135/* So fiemap access checks don't overflow on 32 bit systems.
3136 * This is very slightly smaller than the limit imposed by
3137 * the underlying kernel.
3138 */
3139#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3140 / sizeof(struct fiemap_extent))
3141
3142static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3143 int fd, abi_long cmd, abi_long arg)
3144{
3145 /* The parameter for this ioctl is a struct fiemap followed
3146 * by an array of struct fiemap_extent whose size is set
3147 * in fiemap->fm_extent_count. The array is filled in by the
3148 * ioctl.
3149 */
3150 int target_size_in, target_size_out;
3151 struct fiemap *fm;
3152 const argtype *arg_type = ie->arg_type;
3153 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3154 void *argptr, *p;
3155 abi_long ret;
3156 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3157 uint32_t outbufsz;
3158 int free_fm = 0;
3159
3160 assert(arg_type[0] == TYPE_PTR);
3161 assert(ie->access == IOC_RW);
3162 arg_type++;
3163 target_size_in = thunk_type_size(arg_type, 0);
3164 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3165 if (!argptr) {
3166 return -TARGET_EFAULT;
3167 }
3168 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3169 unlock_user(argptr, arg, 0);
3170 fm = (struct fiemap *)buf_temp;
3171 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3172 return -TARGET_EINVAL;
3173 }
3174
3175 outbufsz = sizeof (*fm) +
3176 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3177
3178 if (outbufsz > MAX_STRUCT_SIZE) {
3179 /* We can't fit all the extents into the fixed size buffer.
3180 * Allocate one that is large enough and use it instead.
3181 */
3182 fm = malloc(outbufsz);
3183 if (!fm) {
3184 return -TARGET_ENOMEM;
3185 }
3186 memcpy(fm, buf_temp, sizeof(struct fiemap));
3187 free_fm = 1;
3188 }
3189 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3190 if (!is_error(ret)) {
3191 target_size_out = target_size_in;
3192 /* An extent_count of 0 means we were only counting the extents
3193 * so there are no structs to copy
3194 */
3195 if (fm->fm_extent_count != 0) {
3196 target_size_out += fm->fm_mapped_extents * extent_size;
3197 }
3198 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3199 if (!argptr) {
3200 ret = -TARGET_EFAULT;
3201 } else {
3202 /* Convert the struct fiemap */
3203 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3204 if (fm->fm_extent_count != 0) {
3205 p = argptr + target_size_in;
3206 /* ...and then all the struct fiemap_extents */
3207 for (i = 0; i < fm->fm_mapped_extents; i++) {
3208 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3209 THUNK_TARGET);
3210 p += extent_size;
3211 }
3212 }
3213 unlock_user(argptr, arg, target_size_out);
3214 }
3215 }
3216 if (free_fm) {
3217 free(fm);
3218 }
3219 return ret;
3220}
Peter Maydelldace20d2011-01-10 13:11:24 +00003221#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003222
Laurent Vivier059c2f22011-03-30 00:12:12 +02003223static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3224 int fd, abi_long cmd, abi_long arg)
3225{
3226 const argtype *arg_type = ie->arg_type;
3227 int target_size;
3228 void *argptr;
3229 int ret;
3230 struct ifconf *host_ifconf;
3231 uint32_t outbufsz;
3232 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3233 int target_ifreq_size;
3234 int nb_ifreq;
3235 int free_buf = 0;
3236 int i;
3237 int target_ifc_len;
3238 abi_long target_ifc_buf;
3239 int host_ifc_len;
3240 char *host_ifc_buf;
3241
3242 assert(arg_type[0] == TYPE_PTR);
3243 assert(ie->access == IOC_RW);
3244
3245 arg_type++;
3246 target_size = thunk_type_size(arg_type, 0);
3247
3248 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3249 if (!argptr)
3250 return -TARGET_EFAULT;
3251 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3252 unlock_user(argptr, arg, 0);
3253
3254 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3255 target_ifc_len = host_ifconf->ifc_len;
3256 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3257
3258 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3259 nb_ifreq = target_ifc_len / target_ifreq_size;
3260 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3261
3262 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3263 if (outbufsz > MAX_STRUCT_SIZE) {
3264 /* We can't fit all the extents into the fixed size buffer.
3265 * Allocate one that is large enough and use it instead.
3266 */
3267 host_ifconf = malloc(outbufsz);
3268 if (!host_ifconf) {
3269 return -TARGET_ENOMEM;
3270 }
3271 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3272 free_buf = 1;
3273 }
3274 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3275
3276 host_ifconf->ifc_len = host_ifc_len;
3277 host_ifconf->ifc_buf = host_ifc_buf;
3278
3279 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3280 if (!is_error(ret)) {
3281 /* convert host ifc_len to target ifc_len */
3282
3283 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3284 target_ifc_len = nb_ifreq * target_ifreq_size;
3285 host_ifconf->ifc_len = target_ifc_len;
3286
3287 /* restore target ifc_buf */
3288
3289 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3290
3291 /* copy struct ifconf to target user */
3292
3293 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3294 if (!argptr)
3295 return -TARGET_EFAULT;
3296 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3297 unlock_user(argptr, arg, target_size);
3298
3299 /* copy ifreq[] to target user */
3300
3301 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3302 for (i = 0; i < nb_ifreq ; i++) {
3303 thunk_convert(argptr + i * target_ifreq_size,
3304 host_ifc_buf + i * sizeof(struct ifreq),
3305 ifreq_arg_type, THUNK_TARGET);
3306 }
3307 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3308 }
3309
3310 if (free_buf) {
3311 free(host_ifconf);
3312 }
3313
3314 return ret;
3315}
3316
blueswir19f106a72008-10-05 10:52:52 +00003317static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003318#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003319 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3320#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3321 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003322#include "ioctls.h"
3323 { 0, 0, },
3324};
3325
pbrook53a59602006-03-25 19:31:22 +00003326/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003327/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003328static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003329{
3330 const IOCTLEntry *ie;
3331 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003332 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003333 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003334 int target_size;
3335 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003336
3337 ie = ioctl_entries;
3338 for(;;) {
3339 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003340 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003341 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003342 }
3343 if (ie->target_cmd == cmd)
3344 break;
3345 ie++;
3346 }
3347 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003348#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003349 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003350#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003351 if (ie->do_ioctl) {
3352 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3353 }
3354
bellard31e31b82003-02-18 22:55:36 +00003355 switch(arg_type[0]) {
3356 case TYPE_NULL:
3357 /* no argument */
3358 ret = get_errno(ioctl(fd, ie->host_cmd));
3359 break;
3360 case TYPE_PTRVOID:
3361 case TYPE_INT:
3362 /* int argment */
3363 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3364 break;
3365 case TYPE_PTR:
3366 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003367 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003368 switch(ie->access) {
3369 case IOC_R:
3370 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3371 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003372 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3373 if (!argptr)
3374 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003375 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3376 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003377 }
3378 break;
3379 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003380 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3381 if (!argptr)
3382 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003383 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3384 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003385 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3386 break;
3387 default:
3388 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003389 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3390 if (!argptr)
3391 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003392 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3393 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003394 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3395 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003396 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3397 if (!argptr)
3398 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003399 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3400 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003401 }
3402 break;
3403 }
3404 break;
3405 default:
j_mayer32407102007-09-26 23:01:49 +00003406 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3407 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003408 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003409 break;
3410 }
3411 return ret;
3412}
3413
blueswir1b39bc502008-10-05 10:51:10 +00003414static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003415 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3416 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3417 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3418 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3419 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3420 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3421 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3422 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3423 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3424 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3425 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3426 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3427 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3428 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3429 { 0, 0, 0, 0 }
3430};
3431
blueswir1b39bc502008-10-05 10:51:10 +00003432static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003433 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3434 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3435 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3436 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3437 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3438 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3439 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3440 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3441 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3442 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3443 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3444 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3445 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3446 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3447 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3448 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3449 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3450 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3451 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3452 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3453 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3454 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3455 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3456 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3457 { 0, 0, 0, 0 }
3458};
3459
blueswir1b39bc502008-10-05 10:51:10 +00003460static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003461 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3462 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3463 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3464 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3465 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3466 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3467 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3468 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3469 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3470 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3471 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3472 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3473 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3474 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3475 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3476 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3477 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3478 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3479 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3480 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3481 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3482 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3483 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3484 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3485 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3486 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3487 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3488 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3489 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3490 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3491 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3492 { 0, 0, 0, 0 }
3493};
3494
blueswir1b39bc502008-10-05 10:51:10 +00003495static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003496 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3497 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3498 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3499 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3500 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3501 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3502 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3503 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3504 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3505 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3506 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3507 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3508 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3509 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3510 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3511 { 0, 0, 0, 0 }
3512};
3513
3514static void target_to_host_termios (void *dst, const void *src)
3515{
3516 struct host_termios *host = dst;
3517 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003518
ths5fafdf22007-09-16 21:08:06 +00003519 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003520 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003521 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003522 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003523 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003524 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003525 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003526 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3527 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003528
Arnaud Patard44607122009-04-21 17:39:08 +03003529 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003530 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3531 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003532 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003533 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003534 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003535 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003536 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003537 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003538 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003539 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3540 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003541 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3542 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3543 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3544 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3545 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003546 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003547}
ths3b46e622007-09-17 08:09:54 +00003548
bellard31e31b82003-02-18 22:55:36 +00003549static void host_to_target_termios (void *dst, const void *src)
3550{
3551 struct target_termios *target = dst;
3552 const struct host_termios *host = src;
3553
ths5fafdf22007-09-16 21:08:06 +00003554 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003555 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003556 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003557 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003558 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003559 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003560 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003561 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3562 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003563
Arnaud Patard44607122009-04-21 17:39:08 +03003564 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003565 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3566 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3567 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3568 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3569 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3570 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3571 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3572 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3573 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3574 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3575 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3576 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3577 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3578 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3579 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3580 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3581 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3582}
3583
blueswir18e853dc2008-10-05 10:49:32 +00003584static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003585 .convert = { host_to_target_termios, target_to_host_termios },
3586 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3587 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3588};
3589
bellard5286db72003-06-05 00:57:30 +00003590static bitmask_transtbl mmap_flags_tbl[] = {
3591 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3592 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3593 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3594 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3595 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3596 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3597 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3598 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3599 { 0, 0, 0, 0 }
3600};
3601
bellard2ab83ea2003-06-15 19:56:46 +00003602#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003603
3604/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003605static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003606
bellard03acab62007-11-11 14:57:14 +00003607static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003608{
3609 int size;
pbrook53a59602006-03-25 19:31:22 +00003610 void *p;
bellard6dbad632003-03-16 18:05:05 +00003611
3612 if (!ldt_table)
3613 return 0;
3614 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3615 if (size > bytecount)
3616 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003617 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3618 if (!p)
bellard03acab62007-11-11 14:57:14 +00003619 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003620 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003621 memcpy(p, ldt_table, size);
3622 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003623 return size;
3624}
3625
3626/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003627static abi_long write_ldt(CPUX86State *env,
3628 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003629{
3630 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003631 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003632 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003633 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003634 uint32_t *lp, entry_1, entry_2;
3635
3636 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003637 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003638 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003639 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003640 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3641 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3642 ldt_info.limit = tswap32(target_ldt_info->limit);
3643 ldt_info.flags = tswap32(target_ldt_info->flags);
3644 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003645
bellard6dbad632003-03-16 18:05:05 +00003646 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003647 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003648 seg_32bit = ldt_info.flags & 1;
3649 contents = (ldt_info.flags >> 1) & 3;
3650 read_exec_only = (ldt_info.flags >> 3) & 1;
3651 limit_in_pages = (ldt_info.flags >> 4) & 1;
3652 seg_not_present = (ldt_info.flags >> 5) & 1;
3653 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003654#ifdef TARGET_ABI32
3655 lm = 0;
3656#else
3657 lm = (ldt_info.flags >> 7) & 1;
3658#endif
bellard6dbad632003-03-16 18:05:05 +00003659 if (contents == 3) {
3660 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003661 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003662 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003663 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003664 }
3665 /* allocate the LDT */
3666 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003667 env->ldt.base = target_mmap(0,
3668 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3669 PROT_READ|PROT_WRITE,
3670 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3671 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003672 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003673 memset(g2h(env->ldt.base), 0,
3674 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003675 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003676 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003677 }
3678
3679 /* NOTE: same code as Linux kernel */
3680 /* Allow LDTs to be cleared by the user. */
3681 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3682 if (oldmode ||
3683 (contents == 0 &&
3684 read_exec_only == 1 &&
3685 seg_32bit == 0 &&
3686 limit_in_pages == 0 &&
3687 seg_not_present == 1 &&
3688 useable == 0 )) {
3689 entry_1 = 0;
3690 entry_2 = 0;
3691 goto install;
3692 }
3693 }
ths3b46e622007-09-17 08:09:54 +00003694
bellard6dbad632003-03-16 18:05:05 +00003695 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3696 (ldt_info.limit & 0x0ffff);
3697 entry_2 = (ldt_info.base_addr & 0xff000000) |
3698 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3699 (ldt_info.limit & 0xf0000) |
3700 ((read_exec_only ^ 1) << 9) |
3701 (contents << 10) |
3702 ((seg_not_present ^ 1) << 15) |
3703 (seg_32bit << 22) |
3704 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00003705 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00003706 0x7000;
3707 if (!oldmode)
3708 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00003709
bellard6dbad632003-03-16 18:05:05 +00003710 /* Install the new entry ... */
3711install:
3712 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
3713 lp[0] = tswap32(entry_1);
3714 lp[1] = tswap32(entry_2);
3715 return 0;
3716}
3717
3718/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00003719static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
3720 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003721{
bellard03acab62007-11-11 14:57:14 +00003722 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00003723
bellard6dbad632003-03-16 18:05:05 +00003724 switch (func) {
3725 case 0:
3726 ret = read_ldt(ptr, bytecount);
3727 break;
3728 case 1:
3729 ret = write_ldt(env, ptr, bytecount, 1);
3730 break;
3731 case 0x11:
3732 ret = write_ldt(env, ptr, bytecount, 0);
3733 break;
bellard03acab62007-11-11 14:57:14 +00003734 default:
3735 ret = -TARGET_ENOSYS;
3736 break;
bellard6dbad632003-03-16 18:05:05 +00003737 }
3738 return ret;
3739}
bellard1b6b0292003-03-22 17:31:38 +00003740
blueswir14583f582008-08-24 10:35:55 +00003741#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00003742static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003743{
3744 uint64_t *gdt_table = g2h(env->gdt.base);
3745 struct target_modify_ldt_ldt_s ldt_info;
3746 struct target_modify_ldt_ldt_s *target_ldt_info;
3747 int seg_32bit, contents, read_exec_only, limit_in_pages;
3748 int seg_not_present, useable, lm;
3749 uint32_t *lp, entry_1, entry_2;
3750 int i;
3751
3752 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3753 if (!target_ldt_info)
3754 return -TARGET_EFAULT;
3755 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
3756 ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
3757 ldt_info.limit = tswap32(target_ldt_info->limit);
3758 ldt_info.flags = tswap32(target_ldt_info->flags);
3759 if (ldt_info.entry_number == -1) {
3760 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
3761 if (gdt_table[i] == 0) {
3762 ldt_info.entry_number = i;
3763 target_ldt_info->entry_number = tswap32(i);
3764 break;
3765 }
3766 }
3767 }
3768 unlock_user_struct(target_ldt_info, ptr, 1);
3769
3770 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
3771 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
3772 return -TARGET_EINVAL;
3773 seg_32bit = ldt_info.flags & 1;
3774 contents = (ldt_info.flags >> 1) & 3;
3775 read_exec_only = (ldt_info.flags >> 3) & 1;
3776 limit_in_pages = (ldt_info.flags >> 4) & 1;
3777 seg_not_present = (ldt_info.flags >> 5) & 1;
3778 useable = (ldt_info.flags >> 6) & 1;
3779#ifdef TARGET_ABI32
3780 lm = 0;
3781#else
3782 lm = (ldt_info.flags >> 7) & 1;
3783#endif
3784
3785 if (contents == 3) {
3786 if (seg_not_present == 0)
3787 return -TARGET_EINVAL;
3788 }
3789
3790 /* NOTE: same code as Linux kernel */
3791 /* Allow LDTs to be cleared by the user. */
3792 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3793 if ((contents == 0 &&
3794 read_exec_only == 1 &&
3795 seg_32bit == 0 &&
3796 limit_in_pages == 0 &&
3797 seg_not_present == 1 &&
3798 useable == 0 )) {
3799 entry_1 = 0;
3800 entry_2 = 0;
3801 goto install;
3802 }
3803 }
3804
3805 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
3806 (ldt_info.limit & 0x0ffff);
3807 entry_2 = (ldt_info.base_addr & 0xff000000) |
3808 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
3809 (ldt_info.limit & 0xf0000) |
3810 ((read_exec_only ^ 1) << 9) |
3811 (contents << 10) |
3812 ((seg_not_present ^ 1) << 15) |
3813 (seg_32bit << 22) |
3814 (limit_in_pages << 23) |
3815 (useable << 20) |
3816 (lm << 21) |
3817 0x7000;
3818
3819 /* Install the new entry ... */
3820install:
3821 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
3822 lp[0] = tswap32(entry_1);
3823 lp[1] = tswap32(entry_2);
3824 return 0;
3825}
3826
blueswir18fcd3692008-08-17 20:26:25 +00003827static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00003828{
3829 struct target_modify_ldt_ldt_s *target_ldt_info;
3830 uint64_t *gdt_table = g2h(env->gdt.base);
3831 uint32_t base_addr, limit, flags;
3832 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
3833 int seg_not_present, useable, lm;
3834 uint32_t *lp, entry_1, entry_2;
3835
3836 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
3837 if (!target_ldt_info)
3838 return -TARGET_EFAULT;
3839 idx = tswap32(target_ldt_info->entry_number);
3840 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
3841 idx > TARGET_GDT_ENTRY_TLS_MAX) {
3842 unlock_user_struct(target_ldt_info, ptr, 1);
3843 return -TARGET_EINVAL;
3844 }
3845 lp = (uint32_t *)(gdt_table + idx);
3846 entry_1 = tswap32(lp[0]);
3847 entry_2 = tswap32(lp[1]);
3848
3849 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
3850 contents = (entry_2 >> 10) & 3;
3851 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
3852 seg_32bit = (entry_2 >> 22) & 1;
3853 limit_in_pages = (entry_2 >> 23) & 1;
3854 useable = (entry_2 >> 20) & 1;
3855#ifdef TARGET_ABI32
3856 lm = 0;
3857#else
3858 lm = (entry_2 >> 21) & 1;
3859#endif
3860 flags = (seg_32bit << 0) | (contents << 1) |
3861 (read_exec_only << 3) | (limit_in_pages << 4) |
3862 (seg_not_present << 5) | (useable << 6) | (lm << 7);
3863 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
3864 base_addr = (entry_1 >> 16) |
3865 (entry_2 & 0xff000000) |
3866 ((entry_2 & 0xff) << 16);
3867 target_ldt_info->base_addr = tswapl(base_addr);
3868 target_ldt_info->limit = tswap32(limit);
3869 target_ldt_info->flags = tswap32(flags);
3870 unlock_user_struct(target_ldt_info, ptr, 1);
3871 return 0;
3872}
blueswir14583f582008-08-24 10:35:55 +00003873#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00003874
bellardd2fd1af2007-11-14 18:08:56 +00003875#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00003876static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00003877{
Juan Quintela1add8692011-06-16 17:37:09 +01003878 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00003879 abi_ulong val;
3880 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01003881
bellardd2fd1af2007-11-14 18:08:56 +00003882 switch(code) {
3883 case TARGET_ARCH_SET_GS:
3884 case TARGET_ARCH_SET_FS:
3885 if (code == TARGET_ARCH_SET_GS)
3886 idx = R_GS;
3887 else
3888 idx = R_FS;
3889 cpu_x86_load_seg(env, idx, 0);
3890 env->segs[idx].base = addr;
3891 break;
3892 case TARGET_ARCH_GET_GS:
3893 case TARGET_ARCH_GET_FS:
3894 if (code == TARGET_ARCH_GET_GS)
3895 idx = R_GS;
3896 else
3897 idx = R_FS;
3898 val = env->segs[idx].base;
3899 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01003900 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00003901 break;
3902 default:
3903 ret = -TARGET_EINVAL;
3904 break;
3905 }
Juan Quintela1add8692011-06-16 17:37:09 +01003906 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00003907}
3908#endif
3909
bellard2ab83ea2003-06-15 19:56:46 +00003910#endif /* defined(TARGET_I386) */
3911
Riku Voipio05098a92011-03-04 15:27:29 +02003912#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00003913
Riku Voipio05098a92011-03-04 15:27:29 +02003914#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003915
3916static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
3917typedef struct {
3918 CPUState *env;
3919 pthread_mutex_t mutex;
3920 pthread_cond_t cond;
3921 pthread_t thread;
3922 uint32_t tid;
3923 abi_ulong child_tidptr;
3924 abi_ulong parent_tidptr;
3925 sigset_t sigmask;
3926} new_thread_info;
3927
3928static void *clone_func(void *arg)
3929{
3930 new_thread_info *info = arg;
3931 CPUState *env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003932 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00003933
3934 env = info->env;
3935 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003936 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00003937 info->tid = gettid();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07003938 env->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003939 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00003940 if (info->child_tidptr)
3941 put_user_u32(info->tid, info->child_tidptr);
3942 if (info->parent_tidptr)
3943 put_user_u32(info->tid, info->parent_tidptr);
3944 /* Enable signals. */
3945 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
3946 /* Signal to the parent that we're ready. */
3947 pthread_mutex_lock(&info->mutex);
3948 pthread_cond_broadcast(&info->cond);
3949 pthread_mutex_unlock(&info->mutex);
3950 /* Wait until the parent has finshed initializing the tls state. */
3951 pthread_mutex_lock(&clone_lock);
3952 pthread_mutex_unlock(&clone_lock);
3953 cpu_loop(env);
3954 /* never exits */
3955 return NULL;
3956}
3957#else
bellard1b6b0292003-03-22 17:31:38 +00003958
3959static int clone_func(void *arg)
3960{
bellard2ab83ea2003-06-15 19:56:46 +00003961 CPUState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00003962 cpu_loop(env);
3963 /* never exits */
3964 return 0;
3965}
pbrookd865bab2008-06-07 22:12:17 +00003966#endif
bellard1b6b0292003-03-22 17:31:38 +00003967
ths0da46a62007-10-20 20:23:07 +00003968/* do_fork() Must return host values and target errnos (unlike most
3969 do_*() functions). */
pbrookd865bab2008-06-07 22:12:17 +00003970static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3971 abi_ulong parent_tidptr, target_ulong newtls,
3972 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00003973{
3974 int ret;
bellard5cd43932003-03-29 16:54:36 +00003975 TaskState *ts;
bellard2ab83ea2003-06-15 19:56:46 +00003976 CPUState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003977#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003978 unsigned int nptl_flags;
3979 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02003980#else
3981 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00003982#endif
ths3b46e622007-09-17 08:09:54 +00003983
balrog436d1242008-09-21 02:39:45 +00003984 /* Emulate vfork() with fork() */
3985 if (flags & CLONE_VFORK)
3986 flags &= ~(CLONE_VFORK | CLONE_VM);
3987
bellard1b6b0292003-03-22 17:31:38 +00003988 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03003989 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02003990#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00003991 new_thread_info info;
3992 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00003993#endif
Nathan Froyd48e15fc2010-10-29 07:48:57 -07003994 ts = qemu_mallocz(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00003995 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00003996 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00003997 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00003998#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3999 cpu_reset(new_env);
4000#endif
pbrook6e68e072008-05-30 17:22:15 +00004001 /* Init regs that differ from the parent. */
4002 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004003 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004004 ts->bprm = parent_ts->bprm;
4005 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004006#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004007 nptl_flags = flags;
4008 flags &= ~CLONE_NPTL_FLAGS2;
4009
pbrookc2764712009-03-07 15:24:59 +00004010 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4011 ts->child_tidptr = child_tidptr;
4012 }
4013
pbrookd865bab2008-06-07 22:12:17 +00004014 if (nptl_flags & CLONE_SETTLS)
4015 cpu_set_tls (new_env, newtls);
4016
4017 /* Grab a mutex so that thread setup appears atomic. */
4018 pthread_mutex_lock(&clone_lock);
4019
4020 memset(&info, 0, sizeof(info));
4021 pthread_mutex_init(&info.mutex, NULL);
4022 pthread_mutex_lock(&info.mutex);
4023 pthread_cond_init(&info.cond, NULL);
4024 info.env = new_env;
4025 if (nptl_flags & CLONE_CHILD_SETTID)
4026 info.child_tidptr = child_tidptr;
4027 if (nptl_flags & CLONE_PARENT_SETTID)
4028 info.parent_tidptr = parent_tidptr;
4029
4030 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004031 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4032 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004033 /* It is not safe to deliver signals until the child has finished
4034 initializing, so temporarily block all signals. */
4035 sigfillset(&sigmask);
4036 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4037
4038 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004039 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004040
4041 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4042 pthread_attr_destroy(&attr);
4043 if (ret == 0) {
4044 /* Wait for the child to initialize. */
4045 pthread_cond_wait(&info.cond, &info.mutex);
4046 ret = info.tid;
4047 if (flags & CLONE_PARENT_SETTID)
4048 put_user_u32(ret, parent_tidptr);
4049 } else {
4050 ret = -1;
4051 }
4052 pthread_mutex_unlock(&info.mutex);
4053 pthread_cond_destroy(&info.cond);
4054 pthread_mutex_destroy(&info.mutex);
4055 pthread_mutex_unlock(&clone_lock);
4056#else
4057 if (flags & CLONE_NPTL_FLAGS2)
4058 return -EINVAL;
4059 /* This is probably going to die very quickly, but do it anyway. */
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004060 new_stack = qemu_mallocz (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004061#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004062 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004063#else
4064 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4065#endif
pbrookd865bab2008-06-07 22:12:17 +00004066#endif
bellard1b6b0292003-03-22 17:31:38 +00004067 } else {
4068 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004069 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004070 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004071 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004072 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004073 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004074 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004075 cpu_clone_regs(env, newsp);
4076 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004077#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004078 /* There is a race condition here. The parent process could
4079 theoretically read the TID in the child process before the child
4080 tid is set. This would require using either ptrace
4081 (not implemented) or having *_tidptr to point at a shared memory
4082 mapping. We can't repeat the spinlock hack used above because
4083 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004084 if (flags & CLONE_CHILD_SETTID)
4085 put_user_u32(gettid(), child_tidptr);
4086 if (flags & CLONE_PARENT_SETTID)
4087 put_user_u32(gettid(), parent_tidptr);
4088 ts = (TaskState *)env->opaque;
4089 if (flags & CLONE_SETTLS)
4090 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004091 if (flags & CLONE_CHILD_CLEARTID)
4092 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004093#endif
pbrookd865bab2008-06-07 22:12:17 +00004094 } else {
4095 fork_end(0);
4096 }
bellard1b6b0292003-03-22 17:31:38 +00004097 }
4098 return ret;
4099}
4100
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004101/* warning : doesn't handle linux specific flags... */
4102static int target_to_host_fcntl_cmd(int cmd)
4103{
4104 switch(cmd) {
4105 case TARGET_F_DUPFD:
4106 case TARGET_F_GETFD:
4107 case TARGET_F_SETFD:
4108 case TARGET_F_GETFL:
4109 case TARGET_F_SETFL:
4110 return cmd;
4111 case TARGET_F_GETLK:
4112 return F_GETLK;
4113 case TARGET_F_SETLK:
4114 return F_SETLK;
4115 case TARGET_F_SETLKW:
4116 return F_SETLKW;
4117 case TARGET_F_GETOWN:
4118 return F_GETOWN;
4119 case TARGET_F_SETOWN:
4120 return F_SETOWN;
4121 case TARGET_F_GETSIG:
4122 return F_GETSIG;
4123 case TARGET_F_SETSIG:
4124 return F_SETSIG;
4125#if TARGET_ABI_BITS == 32
4126 case TARGET_F_GETLK64:
4127 return F_GETLK64;
4128 case TARGET_F_SETLK64:
4129 return F_SETLK64;
4130 case TARGET_F_SETLKW64:
4131 return F_SETLKW64;
4132#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004133 case TARGET_F_SETLEASE:
4134 return F_SETLEASE;
4135 case TARGET_F_GETLEASE:
4136 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004137#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004138 case TARGET_F_DUPFD_CLOEXEC:
4139 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004140#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004141 case TARGET_F_NOTIFY:
4142 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004143 default:
4144 return -TARGET_EINVAL;
4145 }
4146 return -TARGET_EINVAL;
4147}
4148
blueswir1992f48a2007-10-14 16:27:31 +00004149static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004150{
4151 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004152 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004153 struct flock64 fl64;
4154 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004155 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004156 int host_cmd = target_to_host_fcntl_cmd(cmd);
4157
4158 if (host_cmd == -TARGET_EINVAL)
4159 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004160
bellard7775e9e2003-05-14 22:46:48 +00004161 switch(cmd) {
4162 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004163 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4164 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004165 fl.l_type = tswap16(target_fl->l_type);
4166 fl.l_whence = tswap16(target_fl->l_whence);
4167 fl.l_start = tswapl(target_fl->l_start);
4168 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004169 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004170 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004171 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004172 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004173 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4174 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004175 target_fl->l_type = tswap16(fl.l_type);
4176 target_fl->l_whence = tswap16(fl.l_whence);
4177 target_fl->l_start = tswapl(fl.l_start);
4178 target_fl->l_len = tswapl(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004179 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004180 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004181 }
4182 break;
ths3b46e622007-09-17 08:09:54 +00004183
bellard7775e9e2003-05-14 22:46:48 +00004184 case TARGET_F_SETLK:
4185 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004186 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4187 return -TARGET_EFAULT;
bellard7775e9e2003-05-14 22:46:48 +00004188 fl.l_type = tswap16(target_fl->l_type);
4189 fl.l_whence = tswap16(target_fl->l_whence);
4190 fl.l_start = tswapl(target_fl->l_start);
4191 fl.l_len = tswapl(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004192 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004193 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004194 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004195 break;
ths3b46e622007-09-17 08:09:54 +00004196
bellard7775e9e2003-05-14 22:46:48 +00004197 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004198 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4199 return -TARGET_EFAULT;
ths58134272007-03-31 18:59:32 +00004200 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4201 fl64.l_whence = tswap16(target_fl64->l_whence);
4202 fl64.l_start = tswapl(target_fl64->l_start);
4203 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004204 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004205 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004206 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004207 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004208 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4209 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004210 target_fl64->l_type = tswap16(fl64.l_type) >> 1;
4211 target_fl64->l_whence = tswap16(fl64.l_whence);
4212 target_fl64->l_start = tswapl(fl64.l_start);
4213 target_fl64->l_len = tswapl(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004214 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004215 unlock_user_struct(target_fl64, arg, 1);
4216 }
bellard9ee1fa22007-11-11 15:11:19 +00004217 break;
bellard7775e9e2003-05-14 22:46:48 +00004218 case TARGET_F_SETLK64:
4219 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004220 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4221 return -TARGET_EFAULT;
ths43f238d2007-01-05 20:55:49 +00004222 fl64.l_type = tswap16(target_fl64->l_type) >> 1;
4223 fl64.l_whence = tswap16(target_fl64->l_whence);
4224 fl64.l_start = tswapl(target_fl64->l_start);
4225 fl64.l_len = tswapl(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004226 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004227 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004228 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004229 break;
4230
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004231 case TARGET_F_GETFL:
4232 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004233 if (ret >= 0) {
4234 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4235 }
bellardffa65c32004-01-04 23:57:22 +00004236 break;
4237
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004238 case TARGET_F_SETFL:
4239 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4240 break;
4241
4242 case TARGET_F_SETOWN:
4243 case TARGET_F_GETOWN:
4244 case TARGET_F_SETSIG:
4245 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004246 case TARGET_F_SETLEASE:
4247 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004248 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004249 break;
4250
bellard7775e9e2003-05-14 22:46:48 +00004251 default:
bellard9ee1fa22007-11-11 15:11:19 +00004252 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004253 break;
4254 }
4255 return ret;
4256}
4257
bellard67867302003-11-23 17:05:30 +00004258#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004259
bellard67867302003-11-23 17:05:30 +00004260static inline int high2lowuid(int uid)
4261{
4262 if (uid > 65535)
4263 return 65534;
4264 else
4265 return uid;
4266}
4267
4268static inline int high2lowgid(int gid)
4269{
4270 if (gid > 65535)
4271 return 65534;
4272 else
4273 return gid;
4274}
4275
4276static inline int low2highuid(int uid)
4277{
4278 if ((int16_t)uid == -1)
4279 return -1;
4280 else
4281 return uid;
4282}
4283
4284static inline int low2highgid(int gid)
4285{
4286 if ((int16_t)gid == -1)
4287 return -1;
4288 else
4289 return gid;
4290}
Riku Voipio0c866a72011-04-18 15:23:06 +03004291static inline int tswapid(int id)
4292{
4293 return tswap16(id);
4294}
4295#else /* !USE_UID16 */
4296static inline int high2lowuid(int uid)
4297{
4298 return uid;
4299}
4300static inline int high2lowgid(int gid)
4301{
4302 return gid;
4303}
4304static inline int low2highuid(int uid)
4305{
4306 return uid;
4307}
4308static inline int low2highgid(int gid)
4309{
4310 return gid;
4311}
4312static inline int tswapid(int id)
4313{
4314 return tswap32(id);
4315}
bellard67867302003-11-23 17:05:30 +00004316#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004317
bellard31e31b82003-02-18 22:55:36 +00004318void syscall_init(void)
4319{
bellard2ab83ea2003-06-15 19:56:46 +00004320 IOCTLEntry *ie;
4321 const argtype *arg_type;
4322 int size;
thsb92c47c2007-11-01 00:07:38 +00004323 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004324
Blue Swirl001faf32009-05-13 17:53:17 +00004325#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004326#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004327#include "syscall_types.h"
4328#undef STRUCT
4329#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004330
4331 /* we patch the ioctl size if necessary. We rely on the fact that
4332 no ioctl has all the bits at '1' in the size field */
4333 ie = ioctl_entries;
4334 while (ie->target_cmd != 0) {
4335 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4336 TARGET_IOC_SIZEMASK) {
4337 arg_type = ie->arg_type;
4338 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004339 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004340 ie->target_cmd);
4341 exit(1);
4342 }
4343 arg_type++;
4344 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004345 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004346 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4347 (size << TARGET_IOC_SIZESHIFT);
4348 }
thsb92c47c2007-11-01 00:07:38 +00004349
4350 /* Build target_to_host_errno_table[] table from
4351 * host_to_target_errno_table[]. */
4352 for (i=0; i < ERRNO_TABLE_SIZE; i++)
4353 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4354
bellard2ab83ea2003-06-15 19:56:46 +00004355 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004356#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4357 (defined(__x86_64__) && defined(TARGET_X86_64))
4358 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4359 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4360 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004361 }
4362#endif
4363 ie++;
4364 }
bellard31e31b82003-02-18 22:55:36 +00004365}
bellardc573ff62004-01-04 15:51:36 +00004366
blueswir1992f48a2007-10-14 16:27:31 +00004367#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004368static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4369{
thsaf325d32008-06-10 15:29:15 +00004370#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004371 return ((uint64_t)word0 << 32) | word1;
4372#else
4373 return ((uint64_t)word1 << 32) | word0;
4374#endif
4375}
blueswir1992f48a2007-10-14 16:27:31 +00004376#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004377static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4378{
4379 return word0;
4380}
blueswir1992f48a2007-10-14 16:27:31 +00004381#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004382
4383#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004384static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4385 abi_long arg2,
4386 abi_long arg3,
4387 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004388{
Riku Voipio48e515d2011-07-12 15:40:51 +03004389 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004390 arg2 = arg3;
4391 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004392 }
pbrookce4defa2006-02-09 16:49:55 +00004393 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4394}
4395#endif
4396
4397#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004398static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4399 abi_long arg2,
4400 abi_long arg3,
4401 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004402{
Riku Voipio48e515d2011-07-12 15:40:51 +03004403 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004404 arg2 = arg3;
4405 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004406 }
pbrookce4defa2006-02-09 16:49:55 +00004407 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4408}
4409#endif
4410
bellard579a97f2007-11-11 14:26:47 +00004411static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4412 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004413{
4414 struct target_timespec *target_ts;
4415
bellard579a97f2007-11-11 14:26:47 +00004416 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4417 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004418 host_ts->tv_sec = tswapl(target_ts->tv_sec);
4419 host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
4420 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004421 return 0;
pbrook53a59602006-03-25 19:31:22 +00004422}
4423
bellard579a97f2007-11-11 14:26:47 +00004424static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4425 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004426{
4427 struct target_timespec *target_ts;
4428
bellard579a97f2007-11-11 14:26:47 +00004429 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4430 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004431 target_ts->tv_sec = tswapl(host_ts->tv_sec);
4432 target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
4433 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004434 return 0;
pbrook53a59602006-03-25 19:31:22 +00004435}
4436
aurel329d33b762009-04-08 23:07:05 +00004437#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004438static inline abi_long host_to_target_stat64(void *cpu_env,
4439 abi_ulong target_addr,
4440 struct stat *host_st)
4441{
4442#ifdef TARGET_ARM
4443 if (((CPUARMState *)cpu_env)->eabi) {
4444 struct target_eabi_stat64 *target_st;
4445
4446 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4447 return -TARGET_EFAULT;
4448 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4449 __put_user(host_st->st_dev, &target_st->st_dev);
4450 __put_user(host_st->st_ino, &target_st->st_ino);
4451#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4452 __put_user(host_st->st_ino, &target_st->__st_ino);
4453#endif
4454 __put_user(host_st->st_mode, &target_st->st_mode);
4455 __put_user(host_st->st_nlink, &target_st->st_nlink);
4456 __put_user(host_st->st_uid, &target_st->st_uid);
4457 __put_user(host_st->st_gid, &target_st->st_gid);
4458 __put_user(host_st->st_rdev, &target_st->st_rdev);
4459 __put_user(host_st->st_size, &target_st->st_size);
4460 __put_user(host_st->st_blksize, &target_st->st_blksize);
4461 __put_user(host_st->st_blocks, &target_st->st_blocks);
4462 __put_user(host_st->st_atime, &target_st->target_st_atime);
4463 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4464 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4465 unlock_user_struct(target_st, target_addr, 1);
4466 } else
4467#endif
4468 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004469#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004470 struct target_stat *target_st;
4471#else
balrog6a24a772008-09-20 02:23:36 +00004472 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004473#endif
balrog6a24a772008-09-20 02:23:36 +00004474
4475 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4476 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004477 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004478 __put_user(host_st->st_dev, &target_st->st_dev);
4479 __put_user(host_st->st_ino, &target_st->st_ino);
4480#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4481 __put_user(host_st->st_ino, &target_st->__st_ino);
4482#endif
4483 __put_user(host_st->st_mode, &target_st->st_mode);
4484 __put_user(host_st->st_nlink, &target_st->st_nlink);
4485 __put_user(host_st->st_uid, &target_st->st_uid);
4486 __put_user(host_st->st_gid, &target_st->st_gid);
4487 __put_user(host_st->st_rdev, &target_st->st_rdev);
4488 /* XXX: better use of kernel struct */
4489 __put_user(host_st->st_size, &target_st->st_size);
4490 __put_user(host_st->st_blksize, &target_st->st_blksize);
4491 __put_user(host_st->st_blocks, &target_st->st_blocks);
4492 __put_user(host_st->st_atime, &target_st->target_st_atime);
4493 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4494 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4495 unlock_user_struct(target_st, target_addr, 1);
4496 }
4497
4498 return 0;
4499}
4500#endif
4501
Juan Quintela2f7bb872009-07-27 16:13:24 +02004502#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004503/* ??? Using host futex calls even when target atomic operations
4504 are not really atomic probably breaks things. However implementing
4505 futexes locally would make futexes shared between multiple processes
4506 tricky. However they're probably useless because guest atomic
4507 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004508static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4509 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004510{
4511 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004512 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004513
4514 /* ??? We assume FUTEX_* constants are the same on both host
4515 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004516#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004517 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004518#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004519 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004520#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004521 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004522 case FUTEX_WAIT:
4523 if (timeout) {
4524 pts = &ts;
4525 target_to_host_timespec(pts, timeout);
4526 } else {
4527 pts = NULL;
4528 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004529 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pbrookbd0c5662008-05-29 14:34:11 +00004530 pts, NULL, 0));
4531 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004532 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004533 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004534 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004535 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004536 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004537 case FUTEX_WAKE_OP:
4538 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4539 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4540 But the prototype takes a `struct timespec *'; insert casts
4541 to satisfy the compiler. We do not need to tswap TIMEOUT
4542 since it's not compared to guest memory. */
4543 pts = (struct timespec *)(uintptr_t) timeout;
4544 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4545 g2h(uaddr2),
4546 (base_op == FUTEX_CMP_REQUEUE
4547 ? tswap32(val3)
4548 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004549 default:
4550 return -TARGET_ENOSYS;
4551 }
4552}
4553#endif
4554
pbrook1d9d8b52009-04-16 15:17:02 +00004555/* Map host to target signal numbers for the wait family of syscalls.
4556 Assume all other status bits are the same. */
4557static int host_to_target_waitstatus(int status)
4558{
4559 if (WIFSIGNALED(status)) {
4560 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4561 }
4562 if (WIFSTOPPED(status)) {
4563 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4564 | (status & 0xff);
4565 }
4566 return status;
4567}
4568
pbrooka745ec62008-05-06 15:36:17 +00004569int get_osversion(void)
4570{
4571 static int osversion;
4572 struct new_utsname buf;
4573 const char *s;
4574 int i, n, tmp;
4575 if (osversion)
4576 return osversion;
4577 if (qemu_uname_release && *qemu_uname_release) {
4578 s = qemu_uname_release;
4579 } else {
4580 if (sys_uname(&buf))
4581 return 0;
4582 s = buf.release;
4583 }
4584 tmp = 0;
4585 for (i = 0; i < 3; i++) {
4586 n = 0;
4587 while (*s >= '0' && *s <= '9') {
4588 n *= 10;
4589 n += *s - '0';
4590 s++;
4591 }
4592 tmp = (tmp << 8) + n;
4593 if (*s == '.')
4594 s++;
4595 }
4596 osversion = tmp;
4597 return osversion;
4598}
4599
ths0da46a62007-10-20 20:23:07 +00004600/* do_syscall() should always have a single exit point at the end so
4601 that actions, such as logging of syscall results, can be performed.
4602 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00004603abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4604 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01004605 abi_long arg5, abi_long arg6, abi_long arg7,
4606 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00004607{
blueswir1992f48a2007-10-14 16:27:31 +00004608 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004609 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00004610 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00004611 void *p;
ths3b46e622007-09-17 08:09:54 +00004612
bellard72f03902003-02-18 23:33:18 +00004613#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00004614 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00004615#endif
thsb92c47c2007-11-01 00:07:38 +00004616 if(do_strace)
4617 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
4618
bellard31e31b82003-02-18 22:55:36 +00004619 switch(num) {
4620 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02004621#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00004622 /* In old applications this may be used to implement _exit(2).
4623 However in threaded applictions it is used for thread termination,
4624 and _exit_group is used for application termination.
4625 Do thread termination if we have more then one thread. */
4626 /* FIXME: This probably breaks if a signal arrives. We should probably
4627 be disabling signals. */
4628 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004629 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00004630 CPUState **lastp;
4631 CPUState *p;
4632
4633 cpu_list_lock();
4634 lastp = &first_cpu;
4635 p = first_cpu;
4636 while (p && p != (CPUState *)cpu_env) {
4637 lastp = &p->next_cpu;
4638 p = p->next_cpu;
4639 }
4640 /* If we didn't find the CPU for this thread then something is
4641 horribly wrong. */
4642 if (!p)
4643 abort();
4644 /* Remove the CPU from the list. */
4645 *lastp = p->next_cpu;
4646 cpu_list_unlock();
Nathan Froyd1e9fa732009-06-03 11:33:08 -07004647 ts = ((CPUState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00004648 if (ts->child_tidptr) {
4649 put_user_u32(0, ts->child_tidptr);
4650 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
4651 NULL, NULL, 0);
4652 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004653 thread_env = NULL;
4654 qemu_free(cpu_env);
4655 qemu_free(ts);
pbrookc2764712009-03-07 15:24:59 +00004656 pthread_exit(NULL);
4657 }
4658#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02004659#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00004660 _mcleanup();
4661#endif
bellarde9009672005-04-26 20:42:36 +00004662 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00004663 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00004664 ret = 0; /* avoid warning */
4665 break;
4666 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00004667 if (arg3 == 0)
4668 ret = 0;
4669 else {
4670 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
4671 goto efault;
4672 ret = get_errno(read(arg1, p, arg3));
4673 unlock_user(p, arg2, ret);
4674 }
bellard31e31b82003-02-18 22:55:36 +00004675 break;
4676 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00004677 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
4678 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004679 ret = get_errno(write(arg1, p, arg3));
4680 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00004681 break;
4682 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00004683 if (!(p = lock_user_string(arg1)))
4684 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004685 ret = get_errno(open(path(p),
bellardffa65c32004-01-04 23:57:22 +00004686 target_to_host_bitmask(arg2, fcntl_flags_tbl),
4687 arg3));
pbrook53a59602006-03-25 19:31:22 +00004688 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004689 break;
ths82424832007-09-24 09:21:55 +00004690#if defined(TARGET_NR_openat) && defined(__NR_openat)
4691 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00004692 if (!(p = lock_user_string(arg2)))
4693 goto efault;
4694 ret = get_errno(sys_openat(arg1,
4695 path(p),
4696 target_to_host_bitmask(arg3, fcntl_flags_tbl),
4697 arg4));
4698 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00004699 break;
4700#endif
bellard31e31b82003-02-18 22:55:36 +00004701 case TARGET_NR_close:
4702 ret = get_errno(close(arg1));
4703 break;
4704 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00004705 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00004706 break;
4707 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00004708 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00004709 break;
thse5febef2007-04-01 18:31:35 +00004710#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00004711 case TARGET_NR_waitpid:
4712 {
pbrook53a59602006-03-25 19:31:22 +00004713 int status;
4714 ret = get_errno(waitpid(arg1, &status, arg3));
bellard2f619692007-11-16 10:46:05 +00004715 if (!is_error(ret) && arg2
pbrook1d9d8b52009-04-16 15:17:02 +00004716 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00004717 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004718 }
4719 break;
thse5febef2007-04-01 18:31:35 +00004720#endif
pbrookf0cbb612008-05-30 18:20:05 +00004721#ifdef TARGET_NR_waitid
4722 case TARGET_NR_waitid:
4723 {
4724 siginfo_t info;
4725 info.si_pid = 0;
4726 ret = get_errno(waitid(arg1, arg2, &info, arg4));
4727 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004728 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00004729 goto efault;
4730 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05004731 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00004732 }
4733 }
4734 break;
4735#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004736#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004737 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00004738 if (!(p = lock_user_string(arg1)))
4739 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004740 ret = get_errno(creat(p, arg2));
4741 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004742 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004743#endif
bellard31e31b82003-02-18 22:55:36 +00004744 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00004745 {
4746 void * p2;
4747 p = lock_user_string(arg1);
4748 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00004749 if (!p || !p2)
4750 ret = -TARGET_EFAULT;
4751 else
4752 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00004753 unlock_user(p2, arg2, 0);
4754 unlock_user(p, arg1, 0);
4755 }
bellard31e31b82003-02-18 22:55:36 +00004756 break;
ths64f0ce42007-09-24 09:25:06 +00004757#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
4758 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00004759 {
4760 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00004761 if (!arg2 || !arg4)
4762 goto efault;
ths64f0ce42007-09-24 09:25:06 +00004763 p = lock_user_string(arg2);
4764 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00004765 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00004766 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00004767 else
4768 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00004769 unlock_user(p, arg2, 0);
4770 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00004771 }
4772 break;
4773#endif
bellard31e31b82003-02-18 22:55:36 +00004774 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00004775 if (!(p = lock_user_string(arg1)))
4776 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004777 ret = get_errno(unlink(p));
4778 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004779 break;
ths8170f562007-09-24 09:24:11 +00004780#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
4781 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00004782 if (!(p = lock_user_string(arg2)))
4783 goto efault;
4784 ret = get_errno(sys_unlinkat(arg1, p, arg3));
4785 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00004786 break;
balrogb7d35e62007-12-12 00:40:24 +00004787#endif
bellard31e31b82003-02-18 22:55:36 +00004788 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00004789 {
4790 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00004791 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00004792 abi_ulong gp;
4793 abi_ulong guest_argp;
4794 abi_ulong guest_envp;
4795 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00004796 char **q;
4797
bellardf7341ff2003-03-30 21:00:25 +00004798 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00004799 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00004800 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004801 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004802 goto efault;
ths03aa1972007-12-02 06:28:08 +00004803 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004804 break;
bellard7854b052003-03-29 17:22:23 +00004805 argc++;
bellard2f619692007-11-16 10:46:05 +00004806 }
bellardf7341ff2003-03-30 21:00:25 +00004807 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00004808 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00004809 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00004810 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00004811 goto efault;
ths03aa1972007-12-02 06:28:08 +00004812 if (!addr)
bellard2f619692007-11-16 10:46:05 +00004813 break;
bellard7854b052003-03-29 17:22:23 +00004814 envc++;
bellard2f619692007-11-16 10:46:05 +00004815 }
bellard7854b052003-03-29 17:22:23 +00004816
bellardf7341ff2003-03-30 21:00:25 +00004817 argp = alloca((argc + 1) * sizeof(void *));
4818 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00004819
pbrookda94d262008-05-30 18:24:00 +00004820 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004821 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004822 if (get_user_ual(addr, gp))
4823 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004824 if (!addr)
4825 break;
bellard2f619692007-11-16 10:46:05 +00004826 if (!(*q = lock_user_string(addr)))
4827 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004828 }
bellardf7341ff2003-03-30 21:00:25 +00004829 *q = NULL;
4830
pbrookda94d262008-05-30 18:24:00 +00004831 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00004832 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004833 if (get_user_ual(addr, gp))
4834 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004835 if (!addr)
4836 break;
bellard2f619692007-11-16 10:46:05 +00004837 if (!(*q = lock_user_string(addr)))
4838 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004839 }
bellardf7341ff2003-03-30 21:00:25 +00004840 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00004841
bellard2f619692007-11-16 10:46:05 +00004842 if (!(p = lock_user_string(arg1)))
4843 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00004844 ret = get_errno(execve(p, argp, envp));
4845 unlock_user(p, arg1, 0);
4846
bellard2f619692007-11-16 10:46:05 +00004847 goto execve_end;
4848
4849 execve_efault:
4850 ret = -TARGET_EFAULT;
4851
4852 execve_end:
pbrook53a59602006-03-25 19:31:22 +00004853 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004854 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004855 if (get_user_ual(addr, gp)
4856 || !addr)
4857 break;
pbrook53a59602006-03-25 19:31:22 +00004858 unlock_user(*q, addr, 0);
4859 }
4860 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00004861 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00004862 if (get_user_ual(addr, gp)
4863 || !addr)
4864 break;
pbrook53a59602006-03-25 19:31:22 +00004865 unlock_user(*q, addr, 0);
4866 }
bellard7854b052003-03-29 17:22:23 +00004867 }
bellard31e31b82003-02-18 22:55:36 +00004868 break;
4869 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00004870 if (!(p = lock_user_string(arg1)))
4871 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004872 ret = get_errno(chdir(p));
4873 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004874 break;
bellarda315a142005-01-30 22:59:18 +00004875#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00004876 case TARGET_NR_time:
4877 {
pbrook53a59602006-03-25 19:31:22 +00004878 time_t host_time;
4879 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00004880 if (!is_error(ret)
4881 && arg1
4882 && put_user_sal(host_time, arg1))
4883 goto efault;
bellard31e31b82003-02-18 22:55:36 +00004884 }
4885 break;
bellarda315a142005-01-30 22:59:18 +00004886#endif
bellard31e31b82003-02-18 22:55:36 +00004887 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00004888 if (!(p = lock_user_string(arg1)))
4889 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004890 ret = get_errno(mknod(p, arg2, arg3));
4891 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004892 break;
ths75ac37a2007-09-24 09:23:05 +00004893#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
4894 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00004895 if (!(p = lock_user_string(arg2)))
4896 goto efault;
4897 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
4898 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00004899 break;
4900#endif
bellard31e31b82003-02-18 22:55:36 +00004901 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00004902 if (!(p = lock_user_string(arg1)))
4903 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004904 ret = get_errno(chmod(p, arg2));
4905 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004906 break;
bellardebc05482003-09-30 21:08:41 +00004907#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00004908 case TARGET_NR_break:
4909 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004910#endif
4911#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00004912 case TARGET_NR_oldstat:
4913 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004914#endif
bellard31e31b82003-02-18 22:55:36 +00004915 case TARGET_NR_lseek:
4916 ret = get_errno(lseek(arg1, arg2, arg3));
4917 break;
Richard Henderson92317332010-05-03 10:07:53 -07004918#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
4919 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00004920 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07004921 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00004922 ret = get_errno(getpid());
4923 break;
Richard Henderson92317332010-05-03 10:07:53 -07004924#endif
4925#ifdef TARGET_NR_getpid
4926 case TARGET_NR_getpid:
4927 ret = get_errno(getpid());
4928 break;
4929#endif
bellard31e31b82003-02-18 22:55:36 +00004930 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00004931 {
4932 /* need to look at the data field */
4933 void *p2, *p3;
4934 p = lock_user_string(arg1);
4935 p2 = lock_user_string(arg2);
4936 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00004937 if (!p || !p2 || !p3)
4938 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004939 else {
bellard579a97f2007-11-11 14:26:47 +00004940 /* FIXME - arg5 should be locked, but it isn't clear how to
4941 * do that since it's not guaranteed to be a NULL-terminated
4942 * string.
4943 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03004944 if ( ! arg5 )
4945 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
4946 else
4947 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
4948 }
bellard579a97f2007-11-11 14:26:47 +00004949 unlock_user(p, arg1, 0);
4950 unlock_user(p2, arg2, 0);
4951 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00004952 break;
4953 }
thse5febef2007-04-01 18:31:35 +00004954#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00004955 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00004956 if (!(p = lock_user_string(arg1)))
4957 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004958 ret = get_errno(umount(p));
4959 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00004960 break;
thse5febef2007-04-01 18:31:35 +00004961#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004962#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004963 case TARGET_NR_stime:
4964 {
pbrook53a59602006-03-25 19:31:22 +00004965 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00004966 if (get_user_sal(host_time, arg1))
4967 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004968 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00004969 }
4970 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004971#endif
bellard31e31b82003-02-18 22:55:36 +00004972 case TARGET_NR_ptrace:
4973 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00004974#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004975 case TARGET_NR_alarm:
4976 ret = alarm(arg1);
4977 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004978#endif
bellardebc05482003-09-30 21:08:41 +00004979#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00004980 case TARGET_NR_oldfstat:
4981 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00004982#endif
j_mayer7a3148a2007-04-05 07:13:51 +00004983#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00004984 case TARGET_NR_pause:
4985 ret = get_errno(pause());
4986 break;
j_mayer7a3148a2007-04-05 07:13:51 +00004987#endif
thse5febef2007-04-01 18:31:35 +00004988#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00004989 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00004990 {
pbrook53a59602006-03-25 19:31:22 +00004991 struct utimbuf tbuf, *host_tbuf;
4992 struct target_utimbuf *target_tbuf;
4993 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00004994 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
4995 goto efault;
pbrook53a59602006-03-25 19:31:22 +00004996 tbuf.actime = tswapl(target_tbuf->actime);
4997 tbuf.modtime = tswapl(target_tbuf->modtime);
4998 unlock_user_struct(target_tbuf, arg2, 0);
4999 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005000 } else {
pbrook53a59602006-03-25 19:31:22 +00005001 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005002 }
bellard579a97f2007-11-11 14:26:47 +00005003 if (!(p = lock_user_string(arg1)))
5004 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005005 ret = get_errno(utime(p, host_tbuf));
5006 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005007 }
5008 break;
thse5febef2007-04-01 18:31:35 +00005009#endif
bellard978a66f2004-12-06 22:58:05 +00005010 case TARGET_NR_utimes:
5011 {
bellard978a66f2004-12-06 22:58:05 +00005012 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005013 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005014 if (copy_from_user_timeval(&tv[0], arg2)
5015 || copy_from_user_timeval(&tv[1],
5016 arg2 + sizeof(struct target_timeval)))
5017 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005018 tvp = tv;
5019 } else {
5020 tvp = NULL;
5021 }
bellard579a97f2007-11-11 14:26:47 +00005022 if (!(p = lock_user_string(arg1)))
5023 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005024 ret = get_errno(utimes(p, tvp));
5025 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005026 }
5027 break;
balrogac8a6552008-09-20 02:25:39 +00005028#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5029 case TARGET_NR_futimesat:
5030 {
5031 struct timeval *tvp, tv[2];
5032 if (arg3) {
5033 if (copy_from_user_timeval(&tv[0], arg3)
5034 || copy_from_user_timeval(&tv[1],
5035 arg3 + sizeof(struct target_timeval)))
5036 goto efault;
5037 tvp = tv;
5038 } else {
5039 tvp = NULL;
5040 }
5041 if (!(p = lock_user_string(arg2)))
5042 goto efault;
5043 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5044 unlock_user(p, arg2, 0);
5045 }
5046 break;
5047#endif
bellardebc05482003-09-30 21:08:41 +00005048#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005049 case TARGET_NR_stty:
5050 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005051#endif
5052#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005053 case TARGET_NR_gtty:
5054 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005055#endif
bellard31e31b82003-02-18 22:55:36 +00005056 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005057 if (!(p = lock_user_string(arg1)))
5058 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005059 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005060 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005061 break;
ths92a34c12007-09-24 09:27:49 +00005062#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5063 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005064 if (!(p = lock_user_string(arg2)))
5065 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005066 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005067 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005068 break;
5069#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005070#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005071 case TARGET_NR_nice:
5072 ret = get_errno(nice(arg1));
5073 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005074#endif
bellardebc05482003-09-30 21:08:41 +00005075#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005076 case TARGET_NR_ftime:
5077 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005078#endif
bellard31e31b82003-02-18 22:55:36 +00005079 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005080 sync();
5081 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005082 break;
5083 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005084 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005085 break;
5086 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005087 {
5088 void *p2;
5089 p = lock_user_string(arg1);
5090 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005091 if (!p || !p2)
5092 ret = -TARGET_EFAULT;
5093 else
5094 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005095 unlock_user(p2, arg2, 0);
5096 unlock_user(p, arg1, 0);
5097 }
bellard31e31b82003-02-18 22:55:36 +00005098 break;
ths722183f2007-09-24 09:24:37 +00005099#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5100 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005101 {
bellard579a97f2007-11-11 14:26:47 +00005102 void *p2;
ths722183f2007-09-24 09:24:37 +00005103 p = lock_user_string(arg2);
5104 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005105 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005106 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005107 else
5108 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005109 unlock_user(p2, arg4, 0);
5110 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005111 }
5112 break;
5113#endif
bellard31e31b82003-02-18 22:55:36 +00005114 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005115 if (!(p = lock_user_string(arg1)))
5116 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005117 ret = get_errno(mkdir(p, arg2));
5118 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005119 break;
ths4472ad02007-09-24 09:22:32 +00005120#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5121 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005122 if (!(p = lock_user_string(arg2)))
5123 goto efault;
5124 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5125 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005126 break;
5127#endif
bellard31e31b82003-02-18 22:55:36 +00005128 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005129 if (!(p = lock_user_string(arg1)))
5130 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005131 ret = get_errno(rmdir(p));
5132 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005133 break;
5134 case TARGET_NR_dup:
5135 ret = get_errno(dup(arg1));
5136 break;
5137 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005138 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005139 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005140#ifdef TARGET_NR_pipe2
5141 case TARGET_NR_pipe2:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005142 ret = do_pipe(cpu_env, arg1, arg2, 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005143 break;
5144#endif
bellard31e31b82003-02-18 22:55:36 +00005145 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005146 {
pbrook53a59602006-03-25 19:31:22 +00005147 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005148 struct tms tms;
5149 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005150 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005151 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5152 if (!tmsp)
5153 goto efault;
bellardc596ed12003-07-13 17:32:31 +00005154 tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
5155 tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
5156 tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
5157 tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005158 }
bellardc596ed12003-07-13 17:32:31 +00005159 if (!is_error(ret))
5160 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005161 }
5162 break;
bellardebc05482003-09-30 21:08:41 +00005163#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005164 case TARGET_NR_prof:
5165 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005166#endif
thse5febef2007-04-01 18:31:35 +00005167#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005168 case TARGET_NR_signal:
5169 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005170#endif
bellard31e31b82003-02-18 22:55:36 +00005171 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005172 if (arg1 == 0) {
5173 ret = get_errno(acct(NULL));
5174 } else {
5175 if (!(p = lock_user_string(arg1)))
5176 goto efault;
5177 ret = get_errno(acct(path(p)));
5178 unlock_user(p, arg1, 0);
5179 }
pbrook24836682006-04-16 14:14:53 +00005180 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005181#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005182 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005183 if (!(p = lock_user_string(arg1)))
5184 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005185 ret = get_errno(umount2(p, arg2));
5186 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005187 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005188#endif
bellardebc05482003-09-30 21:08:41 +00005189#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005190 case TARGET_NR_lock:
5191 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005192#endif
bellard31e31b82003-02-18 22:55:36 +00005193 case TARGET_NR_ioctl:
5194 ret = do_ioctl(arg1, arg2, arg3);
5195 break;
5196 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005197 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005198 break;
bellardebc05482003-09-30 21:08:41 +00005199#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005200 case TARGET_NR_mpx:
5201 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005202#endif
bellard31e31b82003-02-18 22:55:36 +00005203 case TARGET_NR_setpgid:
5204 ret = get_errno(setpgid(arg1, arg2));
5205 break;
bellardebc05482003-09-30 21:08:41 +00005206#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005207 case TARGET_NR_ulimit:
5208 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005209#endif
5210#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005211 case TARGET_NR_oldolduname:
5212 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005213#endif
bellard31e31b82003-02-18 22:55:36 +00005214 case TARGET_NR_umask:
5215 ret = get_errno(umask(arg1));
5216 break;
5217 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005218 if (!(p = lock_user_string(arg1)))
5219 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005220 ret = get_errno(chroot(p));
5221 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005222 break;
5223 case TARGET_NR_ustat:
5224 goto unimplemented;
5225 case TARGET_NR_dup2:
5226 ret = get_errno(dup2(arg1, arg2));
5227 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005228#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5229 case TARGET_NR_dup3:
5230 ret = get_errno(dup3(arg1, arg2, arg3));
5231 break;
5232#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005233#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005234 case TARGET_NR_getppid:
5235 ret = get_errno(getppid());
5236 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005237#endif
bellard31e31b82003-02-18 22:55:36 +00005238 case TARGET_NR_getpgrp:
5239 ret = get_errno(getpgrp());
5240 break;
5241 case TARGET_NR_setsid:
5242 ret = get_errno(setsid());
5243 break;
thse5febef2007-04-01 18:31:35 +00005244#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005245 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005246 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005247#if defined(TARGET_ALPHA)
5248 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005249 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005250 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005251 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5252 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005253 act._sa_handler = old_act->_sa_handler;
5254 target_siginitset(&act.sa_mask, old_act->sa_mask);
5255 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005256 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005257 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005258 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005259 }
5260 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005261 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005262 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5263 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005264 old_act->_sa_handler = oact._sa_handler;
5265 old_act->sa_mask = oact.sa_mask.sig[0];
5266 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005267 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005268 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005269#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005270 struct target_sigaction act, oact, *pact, *old_act;
5271
5272 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005273 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5274 goto efault;
bellard106ec872006-06-27 21:08:10 +00005275 act._sa_handler = old_act->_sa_handler;
5276 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5277 act.sa_flags = old_act->sa_flags;
5278 unlock_user_struct(old_act, arg2, 0);
5279 pact = &act;
5280 } else {
5281 pact = NULL;
5282 }
5283
5284 ret = get_errno(do_sigaction(arg1, pact, &oact));
5285
5286 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005287 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5288 goto efault;
bellard106ec872006-06-27 21:08:10 +00005289 old_act->_sa_handler = oact._sa_handler;
5290 old_act->sa_flags = oact.sa_flags;
5291 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5292 old_act->sa_mask.sig[1] = 0;
5293 old_act->sa_mask.sig[2] = 0;
5294 old_act->sa_mask.sig[3] = 0;
5295 unlock_user_struct(old_act, arg3, 1);
5296 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005297#else
5298 struct target_old_sigaction *old_act;
5299 struct target_sigaction act, oact, *pact;
5300 if (arg2) {
5301 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5302 goto efault;
5303 act._sa_handler = old_act->_sa_handler;
5304 target_siginitset(&act.sa_mask, old_act->sa_mask);
5305 act.sa_flags = old_act->sa_flags;
5306 act.sa_restorer = old_act->sa_restorer;
5307 unlock_user_struct(old_act, arg2, 0);
5308 pact = &act;
5309 } else {
5310 pact = NULL;
5311 }
5312 ret = get_errno(do_sigaction(arg1, pact, &oact));
5313 if (!is_error(ret) && arg3) {
5314 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5315 goto efault;
5316 old_act->_sa_handler = oact._sa_handler;
5317 old_act->sa_mask = oact.sa_mask.sig[0];
5318 old_act->sa_flags = oact.sa_flags;
5319 old_act->sa_restorer = oact.sa_restorer;
5320 unlock_user_struct(old_act, arg3, 1);
5321 }
ths388bb212007-05-13 13:58:00 +00005322#endif
bellard31e31b82003-02-18 22:55:36 +00005323 }
5324 break;
thse5febef2007-04-01 18:31:35 +00005325#endif
bellard66fb9762003-03-23 01:06:05 +00005326 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005327 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005328#if defined(TARGET_ALPHA)
5329 struct target_sigaction act, oact, *pact = 0;
5330 struct target_rt_sigaction *rt_act;
5331 /* ??? arg4 == sizeof(sigset_t). */
5332 if (arg2) {
5333 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5334 goto efault;
5335 act._sa_handler = rt_act->_sa_handler;
5336 act.sa_mask = rt_act->sa_mask;
5337 act.sa_flags = rt_act->sa_flags;
5338 act.sa_restorer = arg5;
5339 unlock_user_struct(rt_act, arg2, 0);
5340 pact = &act;
5341 }
5342 ret = get_errno(do_sigaction(arg1, pact, &oact));
5343 if (!is_error(ret) && arg3) {
5344 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5345 goto efault;
5346 rt_act->_sa_handler = oact._sa_handler;
5347 rt_act->sa_mask = oact.sa_mask;
5348 rt_act->sa_flags = oact.sa_flags;
5349 unlock_user_struct(rt_act, arg3, 1);
5350 }
5351#else
pbrook53a59602006-03-25 19:31:22 +00005352 struct target_sigaction *act;
5353 struct target_sigaction *oact;
5354
bellard579a97f2007-11-11 14:26:47 +00005355 if (arg2) {
5356 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5357 goto efault;
5358 } else
pbrook53a59602006-03-25 19:31:22 +00005359 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005360 if (arg3) {
5361 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5362 ret = -TARGET_EFAULT;
5363 goto rt_sigaction_fail;
5364 }
5365 } else
pbrook53a59602006-03-25 19:31:22 +00005366 oact = NULL;
5367 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005368 rt_sigaction_fail:
5369 if (act)
pbrook53a59602006-03-25 19:31:22 +00005370 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005371 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005372 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005373#endif
pbrook53a59602006-03-25 19:31:22 +00005374 }
bellard66fb9762003-03-23 01:06:05 +00005375 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005376#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005377 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005378 {
5379 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005380 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005381 sigprocmask(0, NULL, &cur_set);
5382 host_to_target_old_sigset(&target_set, &cur_set);
5383 ret = target_set;
5384 }
5385 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005386#endif
5387#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005388 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005389 {
5390 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005391 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005392 sigprocmask(0, NULL, &cur_set);
5393 target_to_host_old_sigset(&set, &target_set);
5394 sigorset(&set, &set, &cur_set);
5395 sigprocmask(SIG_SETMASK, &set, &oset);
5396 host_to_target_old_sigset(&target_set, &oset);
5397 ret = target_set;
5398 }
5399 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005400#endif
thse5febef2007-04-01 18:31:35 +00005401#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005402 case TARGET_NR_sigprocmask:
5403 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005404#if defined(TARGET_ALPHA)
5405 sigset_t set, oldset;
5406 abi_ulong mask;
5407 int how;
5408
5409 switch (arg1) {
5410 case TARGET_SIG_BLOCK:
5411 how = SIG_BLOCK;
5412 break;
5413 case TARGET_SIG_UNBLOCK:
5414 how = SIG_UNBLOCK;
5415 break;
5416 case TARGET_SIG_SETMASK:
5417 how = SIG_SETMASK;
5418 break;
5419 default:
5420 ret = -TARGET_EINVAL;
5421 goto fail;
5422 }
5423 mask = arg2;
5424 target_to_host_old_sigset(&set, &mask);
5425
5426 ret = get_errno(sigprocmask(how, &set, &oldset));
5427
5428 if (!is_error(ret)) {
5429 host_to_target_old_sigset(&mask, &oldset);
5430 ret = mask;
5431 ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
5432 }
5433#else
bellard66fb9762003-03-23 01:06:05 +00005434 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07005435 int how;
ths3b46e622007-09-17 08:09:54 +00005436
pbrook53a59602006-03-25 19:31:22 +00005437 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005438 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00005439 case TARGET_SIG_BLOCK:
5440 how = SIG_BLOCK;
5441 break;
5442 case TARGET_SIG_UNBLOCK:
5443 how = SIG_UNBLOCK;
5444 break;
5445 case TARGET_SIG_SETMASK:
5446 how = SIG_SETMASK;
5447 break;
5448 default:
ths0da46a62007-10-20 20:23:07 +00005449 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005450 goto fail;
5451 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005452 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005453 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005454 target_to_host_old_sigset(&set, p);
5455 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005456 set_ptr = &set;
5457 } else {
5458 how = 0;
5459 set_ptr = NULL;
5460 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005461 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005462 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005463 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005464 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005465 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005466 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005467 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07005468#endif
bellard66fb9762003-03-23 01:06:05 +00005469 }
5470 break;
thse5febef2007-04-01 18:31:35 +00005471#endif
bellard66fb9762003-03-23 01:06:05 +00005472 case TARGET_NR_rt_sigprocmask:
5473 {
5474 int how = arg1;
5475 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00005476
pbrook53a59602006-03-25 19:31:22 +00005477 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00005478 switch(how) {
5479 case TARGET_SIG_BLOCK:
5480 how = SIG_BLOCK;
5481 break;
5482 case TARGET_SIG_UNBLOCK:
5483 how = SIG_UNBLOCK;
5484 break;
5485 case TARGET_SIG_SETMASK:
5486 how = SIG_SETMASK;
5487 break;
5488 default:
ths0da46a62007-10-20 20:23:07 +00005489 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00005490 goto fail;
5491 }
Anthony Liguoric227f092009-10-01 16:12:16 -05005492 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005493 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005494 target_to_host_sigset(&set, p);
5495 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005496 set_ptr = &set;
5497 } else {
5498 how = 0;
5499 set_ptr = NULL;
5500 }
5501 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00005502 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005503 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005504 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005505 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05005506 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005507 }
5508 }
5509 break;
thse5febef2007-04-01 18:31:35 +00005510#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00005511 case TARGET_NR_sigpending:
5512 {
5513 sigset_t set;
5514 ret = get_errno(sigpending(&set));
5515 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005516 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005517 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005518 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005519 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005520 }
5521 }
5522 break;
thse5febef2007-04-01 18:31:35 +00005523#endif
bellard66fb9762003-03-23 01:06:05 +00005524 case TARGET_NR_rt_sigpending:
5525 {
5526 sigset_t set;
5527 ret = get_errno(sigpending(&set));
5528 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005529 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005530 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005531 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05005532 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00005533 }
5534 }
5535 break;
thse5febef2007-04-01 18:31:35 +00005536#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00005537 case TARGET_NR_sigsuspend:
5538 {
5539 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07005540#if defined(TARGET_ALPHA)
5541 abi_ulong mask = arg1;
5542 target_to_host_old_sigset(&set, &mask);
5543#else
Anthony Liguoric227f092009-10-01 16:12:16 -05005544 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005545 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005546 target_to_host_old_sigset(&set, p);
5547 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07005548#endif
bellard66fb9762003-03-23 01:06:05 +00005549 ret = get_errno(sigsuspend(&set));
5550 }
5551 break;
thse5febef2007-04-01 18:31:35 +00005552#endif
bellard66fb9762003-03-23 01:06:05 +00005553 case TARGET_NR_rt_sigsuspend:
5554 {
5555 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005556 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005557 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005558 target_to_host_sigset(&set, p);
5559 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005560 ret = get_errno(sigsuspend(&set));
5561 }
5562 break;
5563 case TARGET_NR_rt_sigtimedwait:
5564 {
bellard66fb9762003-03-23 01:06:05 +00005565 sigset_t set;
5566 struct timespec uts, *puts;
5567 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00005568
Anthony Liguoric227f092009-10-01 16:12:16 -05005569 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005570 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005571 target_to_host_sigset(&set, p);
5572 unlock_user(p, arg1, 0);
5573 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00005574 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00005575 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00005576 } else {
5577 puts = NULL;
5578 }
5579 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00005580 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005581 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00005582 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005583 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05005584 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00005585 }
5586 }
5587 break;
5588 case TARGET_NR_rt_sigqueueinfo:
5589 {
5590 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05005591 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00005592 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005593 target_to_host_siginfo(&uinfo, p);
5594 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00005595 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
5596 }
5597 break;
thse5febef2007-04-01 18:31:35 +00005598#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00005599 case TARGET_NR_sigreturn:
5600 /* NOTE: ret is eax, so not transcoding must be done */
5601 ret = do_sigreturn(cpu_env);
5602 break;
thse5febef2007-04-01 18:31:35 +00005603#endif
bellard66fb9762003-03-23 01:06:05 +00005604 case TARGET_NR_rt_sigreturn:
5605 /* NOTE: ret is eax, so not transcoding must be done */
5606 ret = do_rt_sigreturn(cpu_env);
5607 break;
bellard31e31b82003-02-18 22:55:36 +00005608 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00005609 if (!(p = lock_user_string(arg1)))
5610 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005611 ret = get_errno(sethostname(p, arg2));
5612 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005613 break;
5614 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00005615 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005616 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005617 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005618 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00005619 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
5620 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005621 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
5622 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005623 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00005624 ret = get_errno(setrlimit(resource, &rlim));
5625 }
5626 break;
bellard31e31b82003-02-18 22:55:36 +00005627 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00005628 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03005629 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00005630 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00005631 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00005632
bellard9de5e442003-03-23 16:49:39 +00005633 ret = get_errno(getrlimit(resource, &rlim));
5634 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005635 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
5636 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09005637 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
5638 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00005639 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00005640 }
5641 }
5642 break;
bellard31e31b82003-02-18 22:55:36 +00005643 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00005644 {
5645 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00005646 ret = get_errno(getrusage(arg1, &rusage));
5647 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00005648 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00005649 }
5650 }
5651 break;
bellard31e31b82003-02-18 22:55:36 +00005652 case TARGET_NR_gettimeofday:
5653 {
bellard31e31b82003-02-18 22:55:36 +00005654 struct timeval tv;
5655 ret = get_errno(gettimeofday(&tv, NULL));
5656 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00005657 if (copy_to_user_timeval(arg1, &tv))
5658 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005659 }
5660 }
5661 break;
5662 case TARGET_NR_settimeofday:
5663 {
bellard31e31b82003-02-18 22:55:36 +00005664 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00005665 if (copy_from_user_timeval(&tv, arg1))
5666 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005667 ret = get_errno(settimeofday(&tv, NULL));
5668 }
5669 break;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005670#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
bellard31e31b82003-02-18 22:55:36 +00005671 case TARGET_NR_select:
bellardf2674e32003-07-09 12:26:09 +00005672 {
pbrook53a59602006-03-25 19:31:22 +00005673 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00005674 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00005675 long nsel;
5676
bellard579a97f2007-11-11 14:26:47 +00005677 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
5678 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005679 nsel = tswapl(sel->n);
5680 inp = tswapl(sel->inp);
5681 outp = tswapl(sel->outp);
5682 exp = tswapl(sel->exp);
5683 tvp = tswapl(sel->tvp);
5684 unlock_user_struct(sel, arg1, 0);
5685 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00005686 }
5687 break;
bellard048f6b42005-11-26 18:47:20 +00005688#endif
Riku Voipio9e423822010-05-07 12:28:05 +00005689#ifdef TARGET_NR_pselect6
5690 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04005691 {
5692 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
5693 fd_set rfds, wfds, efds;
5694 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
5695 struct timespec ts, *ts_ptr;
5696
5697 /*
5698 * The 6th arg is actually two args smashed together,
5699 * so we cannot use the C library.
5700 */
5701 sigset_t set;
5702 struct {
5703 sigset_t *set;
5704 size_t size;
5705 } sig, *sig_ptr;
5706
5707 abi_ulong arg_sigset, arg_sigsize, *arg7;
5708 target_sigset_t *target_sigset;
5709
5710 n = arg1;
5711 rfd_addr = arg2;
5712 wfd_addr = arg3;
5713 efd_addr = arg4;
5714 ts_addr = arg5;
5715
5716 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
5717 if (ret) {
5718 goto fail;
5719 }
5720 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
5721 if (ret) {
5722 goto fail;
5723 }
5724 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
5725 if (ret) {
5726 goto fail;
5727 }
5728
5729 /*
5730 * This takes a timespec, and not a timeval, so we cannot
5731 * use the do_select() helper ...
5732 */
5733 if (ts_addr) {
5734 if (target_to_host_timespec(&ts, ts_addr)) {
5735 goto efault;
5736 }
5737 ts_ptr = &ts;
5738 } else {
5739 ts_ptr = NULL;
5740 }
5741
5742 /* Extract the two packed args for the sigset */
5743 if (arg6) {
5744 sig_ptr = &sig;
5745 sig.size = _NSIG / 8;
5746
5747 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
5748 if (!arg7) {
5749 goto efault;
5750 }
5751 arg_sigset = tswapl(arg7[0]);
5752 arg_sigsize = tswapl(arg7[1]);
5753 unlock_user(arg7, arg6, 0);
5754
5755 if (arg_sigset) {
5756 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01005757 if (arg_sigsize != sizeof(*target_sigset)) {
5758 /* Like the kernel, we enforce correct size sigsets */
5759 ret = -TARGET_EINVAL;
5760 goto fail;
5761 }
Mike Frysinger055e0902011-06-03 17:01:49 -04005762 target_sigset = lock_user(VERIFY_READ, arg_sigset,
5763 sizeof(*target_sigset), 1);
5764 if (!target_sigset) {
5765 goto efault;
5766 }
5767 target_to_host_sigset(&set, target_sigset);
5768 unlock_user(target_sigset, arg_sigset, 0);
5769 } else {
5770 sig.set = NULL;
5771 }
5772 } else {
5773 sig_ptr = NULL;
5774 }
5775
5776 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
5777 ts_ptr, sig_ptr));
5778
5779 if (!is_error(ret)) {
5780 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
5781 goto efault;
5782 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
5783 goto efault;
5784 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
5785 goto efault;
5786
5787 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
5788 goto efault;
5789 }
5790 }
5791 break;
Riku Voipio9e423822010-05-07 12:28:05 +00005792#endif
bellard31e31b82003-02-18 22:55:36 +00005793 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00005794 {
5795 void *p2;
5796 p = lock_user_string(arg1);
5797 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005798 if (!p || !p2)
5799 ret = -TARGET_EFAULT;
5800 else
5801 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005802 unlock_user(p2, arg2, 0);
5803 unlock_user(p, arg1, 0);
5804 }
bellard31e31b82003-02-18 22:55:36 +00005805 break;
thsf0b62432007-09-24 09:25:40 +00005806#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
5807 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00005808 {
bellard579a97f2007-11-11 14:26:47 +00005809 void *p2;
thsf0b62432007-09-24 09:25:40 +00005810 p = lock_user_string(arg1);
5811 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005812 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005813 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00005814 else
5815 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00005816 unlock_user(p2, arg3, 0);
5817 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00005818 }
5819 break;
5820#endif
bellardebc05482003-09-30 21:08:41 +00005821#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00005822 case TARGET_NR_oldlstat:
5823 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005824#endif
bellard31e31b82003-02-18 22:55:36 +00005825 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00005826 {
aurel32d088d662009-01-30 20:09:01 +00005827 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00005828 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00005829 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
5830 if (!p || !p2)
5831 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00005832 else {
5833 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
5834 char real[PATH_MAX];
5835 temp = realpath(exec_path,real);
5836 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
5837 snprintf((char *)p2, arg3, "%s", real);
5838 }
5839 else
5840 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00005841 }
pbrook53a59602006-03-25 19:31:22 +00005842 unlock_user(p2, arg2, ret);
5843 unlock_user(p, arg1, 0);
5844 }
bellard31e31b82003-02-18 22:55:36 +00005845 break;
ths5e0ccb12007-09-24 09:26:10 +00005846#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
5847 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00005848 {
bellard579a97f2007-11-11 14:26:47 +00005849 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00005850 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005851 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
5852 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005853 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00005854 else
5855 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00005856 unlock_user(p2, arg3, ret);
5857 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00005858 }
5859 break;
5860#endif
thse5febef2007-04-01 18:31:35 +00005861#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00005862 case TARGET_NR_uselib:
5863 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005864#endif
5865#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00005866 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00005867 if (!(p = lock_user_string(arg1)))
5868 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005869 ret = get_errno(swapon(p, arg2));
5870 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005871 break;
thse5febef2007-04-01 18:31:35 +00005872#endif
bellard31e31b82003-02-18 22:55:36 +00005873 case TARGET_NR_reboot:
5874 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005875#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00005876 case TARGET_NR_readdir:
5877 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005878#endif
5879#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00005880 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02005881#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
5882 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
5883 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00005884 {
blueswir1992f48a2007-10-14 16:27:31 +00005885 abi_ulong *v;
5886 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00005887 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
5888 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005889 v1 = tswapl(v[0]);
5890 v2 = tswapl(v[1]);
5891 v3 = tswapl(v[2]);
5892 v4 = tswapl(v[3]);
5893 v5 = tswapl(v[4]);
5894 v6 = tswapl(v[5]);
5895 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00005896 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00005897 target_to_host_bitmask(v4, mmap_flags_tbl),
5898 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00005899 }
bellard31e31b82003-02-18 22:55:36 +00005900#else
ths5fafdf22007-09-16 21:08:06 +00005901 ret = get_errno(target_mmap(arg1, arg2, arg3,
5902 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00005903 arg5,
5904 arg6));
bellard31e31b82003-02-18 22:55:36 +00005905#endif
bellard6fb883e2003-07-09 17:12:39 +00005906 break;
thse5febef2007-04-01 18:31:35 +00005907#endif
bellarda315a142005-01-30 22:59:18 +00005908#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00005909 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00005910#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00005911#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00005912#endif
ths5fafdf22007-09-16 21:08:06 +00005913 ret = get_errno(target_mmap(arg1, arg2, arg3,
5914 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00005915 arg5,
bellardc573ff62004-01-04 15:51:36 +00005916 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00005917 break;
bellarda315a142005-01-30 22:59:18 +00005918#endif
bellard31e31b82003-02-18 22:55:36 +00005919 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00005920 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005921 break;
bellard9de5e442003-03-23 16:49:39 +00005922 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01005923 {
5924 TaskState *ts = ((CPUState *)cpu_env)->opaque;
5925 /* Special hack to detect libc making the stack executable. */
5926 if ((arg3 & PROT_GROWSDOWN)
5927 && arg1 >= ts->info->stack_limit
5928 && arg1 <= ts->info->start_stack) {
5929 arg3 &= ~PROT_GROWSDOWN;
5930 arg2 = arg2 + arg1 - ts->info->stack_limit;
5931 arg1 = ts->info->stack_limit;
5932 }
5933 }
bellard54936002003-05-13 00:25:15 +00005934 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005935 break;
thse5febef2007-04-01 18:31:35 +00005936#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00005937 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00005938 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00005939 break;
thse5febef2007-04-01 18:31:35 +00005940#endif
pbrook53a59602006-03-25 19:31:22 +00005941 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00005942#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00005943 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00005944 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00005945 break;
thse5febef2007-04-01 18:31:35 +00005946#endif
5947#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00005948 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00005949 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005950 break;
thse5febef2007-04-01 18:31:35 +00005951#endif
5952#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00005953 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00005954 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00005955 break;
thse5febef2007-04-01 18:31:35 +00005956#endif
5957#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00005958 case TARGET_NR_mlockall:
5959 ret = get_errno(mlockall(arg1));
5960 break;
thse5febef2007-04-01 18:31:35 +00005961#endif
5962#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00005963 case TARGET_NR_munlockall:
5964 ret = get_errno(munlockall());
5965 break;
thse5febef2007-04-01 18:31:35 +00005966#endif
bellard31e31b82003-02-18 22:55:36 +00005967 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00005968 if (!(p = lock_user_string(arg1)))
5969 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005970 ret = get_errno(truncate(p, arg2));
5971 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005972 break;
5973 case TARGET_NR_ftruncate:
5974 ret = get_errno(ftruncate(arg1, arg2));
5975 break;
5976 case TARGET_NR_fchmod:
5977 ret = get_errno(fchmod(arg1, arg2));
5978 break;
ths814d7972007-09-24 09:26:51 +00005979#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
5980 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00005981 if (!(p = lock_user_string(arg2)))
5982 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005983 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005984 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00005985 break;
5986#endif
bellard31e31b82003-02-18 22:55:36 +00005987 case TARGET_NR_getpriority:
thsc6cda172007-10-09 03:42:34 +00005988 /* libc does special remapping of the return value of
5989 * sys_getpriority() so it's just easiest to call
5990 * sys_getpriority() directly rather than through libc. */
Ulrich Hecht69137202009-09-17 21:08:37 +03005991 ret = get_errno(sys_getpriority(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00005992 break;
5993 case TARGET_NR_setpriority:
5994 ret = get_errno(setpriority(arg1, arg2, arg3));
5995 break;
bellardebc05482003-09-30 21:08:41 +00005996#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00005997 case TARGET_NR_profil:
5998 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005999#endif
bellard31e31b82003-02-18 22:55:36 +00006000 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006001 if (!(p = lock_user_string(arg1)))
6002 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006003 ret = get_errno(statfs(path(p), &stfs));
6004 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006005 convert_statfs:
6006 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006007 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006008
bellard579a97f2007-11-11 14:26:47 +00006009 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6010 goto efault;
6011 __put_user(stfs.f_type, &target_stfs->f_type);
6012 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6013 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6014 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6015 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6016 __put_user(stfs.f_files, &target_stfs->f_files);
6017 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6018 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6019 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6020 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
pbrook53a59602006-03-25 19:31:22 +00006021 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006022 }
6023 break;
6024 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006025 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006026 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006027#ifdef TARGET_NR_statfs64
6028 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006029 if (!(p = lock_user_string(arg1)))
6030 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006031 ret = get_errno(statfs(path(p), &stfs));
6032 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006033 convert_statfs64:
6034 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006035 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006036
bellard579a97f2007-11-11 14:26:47 +00006037 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6038 goto efault;
6039 __put_user(stfs.f_type, &target_stfs->f_type);
6040 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6041 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6042 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6043 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6044 __put_user(stfs.f_files, &target_stfs->f_files);
6045 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6046 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6047 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6048 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
6049 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006050 }
6051 break;
6052 case TARGET_NR_fstatfs64:
6053 ret = get_errno(fstatfs(arg1, &stfs));
6054 goto convert_statfs64;
6055#endif
bellardebc05482003-09-30 21:08:41 +00006056#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006057 case TARGET_NR_ioperm:
6058 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006059#endif
thse5febef2007-04-01 18:31:35 +00006060#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006061 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006062 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006063 break;
thse5febef2007-04-01 18:31:35 +00006064#endif
bellard3532fa72006-06-24 15:06:03 +00006065#ifdef TARGET_NR_accept
6066 case TARGET_NR_accept:
pbrook1be9e1d2006-11-19 15:26:04 +00006067 ret = do_accept(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006068 break;
6069#endif
6070#ifdef TARGET_NR_bind
6071 case TARGET_NR_bind:
6072 ret = do_bind(arg1, arg2, arg3);
6073 break;
6074#endif
6075#ifdef TARGET_NR_connect
6076 case TARGET_NR_connect:
6077 ret = do_connect(arg1, arg2, arg3);
6078 break;
6079#endif
6080#ifdef TARGET_NR_getpeername
6081 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006082 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006083 break;
6084#endif
6085#ifdef TARGET_NR_getsockname
6086 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006087 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006088 break;
6089#endif
6090#ifdef TARGET_NR_getsockopt
6091 case TARGET_NR_getsockopt:
6092 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6093 break;
6094#endif
6095#ifdef TARGET_NR_listen
6096 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006097 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006098 break;
6099#endif
6100#ifdef TARGET_NR_recv
6101 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006102 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006103 break;
6104#endif
6105#ifdef TARGET_NR_recvfrom
6106 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006107 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006108 break;
6109#endif
6110#ifdef TARGET_NR_recvmsg
6111 case TARGET_NR_recvmsg:
6112 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6113 break;
6114#endif
6115#ifdef TARGET_NR_send
6116 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006117 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006118 break;
6119#endif
6120#ifdef TARGET_NR_sendmsg
6121 case TARGET_NR_sendmsg:
6122 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6123 break;
6124#endif
6125#ifdef TARGET_NR_sendto
6126 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006127 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006128 break;
6129#endif
6130#ifdef TARGET_NR_shutdown
6131 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006132 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006133 break;
6134#endif
6135#ifdef TARGET_NR_socket
6136 case TARGET_NR_socket:
6137 ret = do_socket(arg1, arg2, arg3);
6138 break;
6139#endif
6140#ifdef TARGET_NR_socketpair
6141 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006142 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006143 break;
6144#endif
6145#ifdef TARGET_NR_setsockopt
6146 case TARGET_NR_setsockopt:
6147 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6148 break;
6149#endif
ths7494b0f2007-02-11 18:26:53 +00006150
bellard31e31b82003-02-18 22:55:36 +00006151 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006152 if (!(p = lock_user_string(arg2)))
6153 goto efault;
thse5574482007-02-11 20:03:13 +00006154 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6155 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006156 break;
6157
bellard31e31b82003-02-18 22:55:36 +00006158 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006159 {
bellard66fb9762003-03-23 01:06:05 +00006160 struct itimerval value, ovalue, *pvalue;
6161
pbrook53a59602006-03-25 19:31:22 +00006162 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006163 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006164 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6165 || copy_from_user_timeval(&pvalue->it_value,
6166 arg2 + sizeof(struct target_timeval)))
6167 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006168 } else {
6169 pvalue = NULL;
6170 }
6171 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006172 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006173 if (copy_to_user_timeval(arg3,
6174 &ovalue.it_interval)
6175 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6176 &ovalue.it_value))
6177 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006178 }
6179 }
6180 break;
bellard31e31b82003-02-18 22:55:36 +00006181 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006182 {
bellard66fb9762003-03-23 01:06:05 +00006183 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006184
bellard66fb9762003-03-23 01:06:05 +00006185 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006186 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006187 if (copy_to_user_timeval(arg2,
6188 &value.it_interval)
6189 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6190 &value.it_value))
6191 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006192 }
6193 }
6194 break;
bellard31e31b82003-02-18 22:55:36 +00006195 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006196 if (!(p = lock_user_string(arg1)))
6197 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006198 ret = get_errno(stat(path(p), &st));
6199 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006200 goto do_stat;
6201 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006202 if (!(p = lock_user_string(arg1)))
6203 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006204 ret = get_errno(lstat(path(p), &st));
6205 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006206 goto do_stat;
6207 case TARGET_NR_fstat:
6208 {
6209 ret = get_errno(fstat(arg1, &st));
6210 do_stat:
6211 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006212 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006213
bellard579a97f2007-11-11 14:26:47 +00006214 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6215 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006216 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006217 __put_user(st.st_dev, &target_st->st_dev);
6218 __put_user(st.st_ino, &target_st->st_ino);
6219 __put_user(st.st_mode, &target_st->st_mode);
6220 __put_user(st.st_uid, &target_st->st_uid);
6221 __put_user(st.st_gid, &target_st->st_gid);
6222 __put_user(st.st_nlink, &target_st->st_nlink);
6223 __put_user(st.st_rdev, &target_st->st_rdev);
6224 __put_user(st.st_size, &target_st->st_size);
6225 __put_user(st.st_blksize, &target_st->st_blksize);
6226 __put_user(st.st_blocks, &target_st->st_blocks);
6227 __put_user(st.st_atime, &target_st->target_st_atime);
6228 __put_user(st.st_mtime, &target_st->target_st_mtime);
6229 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006230 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006231 }
6232 }
6233 break;
bellardebc05482003-09-30 21:08:41 +00006234#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006235 case TARGET_NR_olduname:
6236 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006237#endif
6238#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006239 case TARGET_NR_iopl:
6240 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006241#endif
bellard31e31b82003-02-18 22:55:36 +00006242 case TARGET_NR_vhangup:
6243 ret = get_errno(vhangup());
6244 break;
bellardebc05482003-09-30 21:08:41 +00006245#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006246 case TARGET_NR_idle:
6247 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006248#endif
bellard42ad6ae2005-01-03 22:48:11 +00006249#ifdef TARGET_NR_syscall
6250 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006251 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6252 arg6, arg7, arg8, 0);
6253 break;
bellard42ad6ae2005-01-03 22:48:11 +00006254#endif
bellard31e31b82003-02-18 22:55:36 +00006255 case TARGET_NR_wait4:
6256 {
6257 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006258 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006259 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006260 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006261 if (target_rusage)
6262 rusage_ptr = &rusage;
6263 else
6264 rusage_ptr = NULL;
6265 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6266 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00006267 if (status_ptr) {
pbrook1d9d8b52009-04-16 15:17:02 +00006268 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006269 if (put_user_s32(status, status_ptr))
6270 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006271 }
bellard2f619692007-11-16 10:46:05 +00006272 if (target_rusage)
6273 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006274 }
6275 }
6276 break;
thse5febef2007-04-01 18:31:35 +00006277#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006278 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006279 if (!(p = lock_user_string(arg1)))
6280 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006281 ret = get_errno(swapoff(p));
6282 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006283 break;
thse5febef2007-04-01 18:31:35 +00006284#endif
bellard31e31b82003-02-18 22:55:36 +00006285 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006286 {
pbrook53a59602006-03-25 19:31:22 +00006287 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006288 struct sysinfo value;
6289 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006290 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006291 {
bellard579a97f2007-11-11 14:26:47 +00006292 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6293 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006294 __put_user(value.uptime, &target_value->uptime);
6295 __put_user(value.loads[0], &target_value->loads[0]);
6296 __put_user(value.loads[1], &target_value->loads[1]);
6297 __put_user(value.loads[2], &target_value->loads[2]);
6298 __put_user(value.totalram, &target_value->totalram);
6299 __put_user(value.freeram, &target_value->freeram);
6300 __put_user(value.sharedram, &target_value->sharedram);
6301 __put_user(value.bufferram, &target_value->bufferram);
6302 __put_user(value.totalswap, &target_value->totalswap);
6303 __put_user(value.freeswap, &target_value->freeswap);
6304 __put_user(value.procs, &target_value->procs);
6305 __put_user(value.totalhigh, &target_value->totalhigh);
6306 __put_user(value.freehigh, &target_value->freehigh);
6307 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006308 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006309 }
6310 }
6311 break;
thse5febef2007-04-01 18:31:35 +00006312#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006313 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006314 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6315 break;
thse5febef2007-04-01 18:31:35 +00006316#endif
aurel32e5289082009-04-18 16:16:12 +00006317#ifdef TARGET_NR_semget
6318 case TARGET_NR_semget:
6319 ret = get_errno(semget(arg1, arg2, arg3));
6320 break;
6321#endif
6322#ifdef TARGET_NR_semop
6323 case TARGET_NR_semop:
6324 ret = get_errno(do_semop(arg1, arg2, arg3));
6325 break;
6326#endif
6327#ifdef TARGET_NR_semctl
6328 case TARGET_NR_semctl:
6329 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6330 break;
6331#endif
aurel32eeb438c2008-10-13 21:08:55 +00006332#ifdef TARGET_NR_msgctl
6333 case TARGET_NR_msgctl:
6334 ret = do_msgctl(arg1, arg2, arg3);
6335 break;
6336#endif
6337#ifdef TARGET_NR_msgget
6338 case TARGET_NR_msgget:
6339 ret = get_errno(msgget(arg1, arg2));
6340 break;
6341#endif
6342#ifdef TARGET_NR_msgrcv
6343 case TARGET_NR_msgrcv:
6344 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6345 break;
6346#endif
6347#ifdef TARGET_NR_msgsnd
6348 case TARGET_NR_msgsnd:
6349 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6350 break;
6351#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006352#ifdef TARGET_NR_shmget
6353 case TARGET_NR_shmget:
6354 ret = get_errno(shmget(arg1, arg2, arg3));
6355 break;
6356#endif
6357#ifdef TARGET_NR_shmctl
6358 case TARGET_NR_shmctl:
6359 ret = do_shmctl(arg1, arg2, arg3);
6360 break;
6361#endif
6362#ifdef TARGET_NR_shmat
6363 case TARGET_NR_shmat:
6364 ret = do_shmat(arg1, arg2, arg3);
6365 break;
6366#endif
6367#ifdef TARGET_NR_shmdt
6368 case TARGET_NR_shmdt:
6369 ret = do_shmdt(arg1);
6370 break;
6371#endif
bellard31e31b82003-02-18 22:55:36 +00006372 case TARGET_NR_fsync:
6373 ret = get_errno(fsync(arg1));
6374 break;
bellard31e31b82003-02-18 22:55:36 +00006375 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07006376#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00006377 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00006378#elif defined(TARGET_CRIS)
6379 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006380#elif defined(TARGET_S390X)
6381 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00006382#else
pbrookd865bab2008-06-07 22:12:17 +00006383 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00006384#endif
bellard1b6b0292003-03-22 17:31:38 +00006385 break;
bellardec86b0f2003-04-11 00:15:04 +00006386#ifdef __NR_exit_group
6387 /* new thread calls */
6388 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02006389#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00006390 _mcleanup();
6391#endif
bellarde9009672005-04-26 20:42:36 +00006392 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00006393 ret = get_errno(exit_group(arg1));
6394 break;
6395#endif
bellard31e31b82003-02-18 22:55:36 +00006396 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00006397 if (!(p = lock_user_string(arg1)))
6398 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006399 ret = get_errno(setdomainname(p, arg2));
6400 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006401 break;
6402 case TARGET_NR_uname:
6403 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00006404 {
6405 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00006406
bellard579a97f2007-11-11 14:26:47 +00006407 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
6408 goto efault;
bellard29e619b2004-09-13 21:41:04 +00006409 ret = get_errno(sys_uname(buf));
6410 if (!is_error(ret)) {
6411 /* Overrite the native machine name with whatever is being
6412 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01006413 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00006414 /* Allow the user to override the reported release. */
6415 if (qemu_uname_release && *qemu_uname_release)
6416 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00006417 }
pbrook53a59602006-03-25 19:31:22 +00006418 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00006419 }
bellard31e31b82003-02-18 22:55:36 +00006420 break;
bellard6dbad632003-03-16 18:05:05 +00006421#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00006422 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00006423 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00006424 break;
j_mayer84409dd2007-04-06 08:56:50 +00006425#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00006426 case TARGET_NR_vm86old:
6427 goto unimplemented;
6428 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00006429 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00006430 break;
6431#endif
j_mayer84409dd2007-04-06 08:56:50 +00006432#endif
bellard31e31b82003-02-18 22:55:36 +00006433 case TARGET_NR_adjtimex:
6434 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006435#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00006436 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00006437#endif
bellard31e31b82003-02-18 22:55:36 +00006438 case TARGET_NR_init_module:
6439 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00006440#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00006441 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00006442#endif
bellard31e31b82003-02-18 22:55:36 +00006443 goto unimplemented;
6444 case TARGET_NR_quotactl:
6445 goto unimplemented;
6446 case TARGET_NR_getpgid:
6447 ret = get_errno(getpgid(arg1));
6448 break;
6449 case TARGET_NR_fchdir:
6450 ret = get_errno(fchdir(arg1));
6451 break;
j_mayer84409dd2007-04-06 08:56:50 +00006452#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00006453 case TARGET_NR_bdflush:
6454 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00006455#endif
thse5febef2007-04-01 18:31:35 +00006456#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00006457 case TARGET_NR_sysfs:
6458 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006459#endif
bellard31e31b82003-02-18 22:55:36 +00006460 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00006461 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00006462 break;
thse5febef2007-04-01 18:31:35 +00006463#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00006464 case TARGET_NR_afs_syscall:
6465 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006466#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006467#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006468 case TARGET_NR__llseek:
6469 {
6470 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00006471#if !defined(__NR_llseek)
6472 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
6473 if (res == -1) {
6474 ret = get_errno(res);
6475 } else {
6476 ret = 0;
6477 }
6478#else
bellard31e31b82003-02-18 22:55:36 +00006479 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00006480#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00006481 if ((ret == 0) && put_user_s64(res, arg4)) {
6482 goto efault;
6483 }
bellard31e31b82003-02-18 22:55:36 +00006484 }
6485 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006486#endif
bellard31e31b82003-02-18 22:55:36 +00006487 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02006488#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00006489 {
pbrook53a59602006-03-25 19:31:22 +00006490 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00006491 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006492 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00006493
6494 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00006495 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00006496 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00006497 goto fail;
6498 }
ths3b46e622007-09-17 08:09:54 +00006499
bellard4add45b2003-06-05 01:52:59 +00006500 ret = get_errno(sys_getdents(arg1, dirp, count));
6501 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006502 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00006503 struct target_dirent *tde;
6504 int len = ret;
6505 int reclen, treclen;
6506 int count1, tnamelen;
6507
6508 count1 = 0;
6509 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00006510 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6511 goto efault;
bellard4add45b2003-06-05 01:52:59 +00006512 tde = target_dirp;
6513 while (len > 0) {
6514 reclen = de->d_reclen;
blueswir1992f48a2007-10-14 16:27:31 +00006515 treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
bellard4add45b2003-06-05 01:52:59 +00006516 tde->d_reclen = tswap16(treclen);
6517 tde->d_ino = tswapl(de->d_ino);
6518 tde->d_off = tswapl(de->d_off);
blueswir1992f48a2007-10-14 16:27:31 +00006519 tnamelen = treclen - (2 * sizeof(abi_long) + 2);
bellard4add45b2003-06-05 01:52:59 +00006520 if (tnamelen > 256)
6521 tnamelen = 256;
bellard80a9d032005-01-03 23:31:27 +00006522 /* XXX: may not be correct */
blueswir1be15b142008-10-25 11:21:28 +00006523 pstrcpy(tde->d_name, tnamelen, de->d_name);
aurel326556a832008-10-13 21:08:17 +00006524 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00006525 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00006526 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00006527 count1 += treclen;
6528 }
6529 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00006530 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00006531 }
6532 free(dirp);
6533 }
6534#else
bellard31e31b82003-02-18 22:55:36 +00006535 {
aurel326556a832008-10-13 21:08:17 +00006536 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006537 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00006538
bellard579a97f2007-11-11 14:26:47 +00006539 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6540 goto efault;
bellard72f03902003-02-18 23:33:18 +00006541 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00006542 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006543 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00006544 int len = ret;
6545 int reclen;
6546 de = dirp;
6547 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006548 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00006549 if (reclen > len)
6550 break;
bellard8083a3e2003-03-24 23:12:16 +00006551 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00006552 tswapls(&de->d_ino);
6553 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006554 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00006555 len -= reclen;
6556 }
6557 }
pbrook53a59602006-03-25 19:31:22 +00006558 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00006559 }
bellard4add45b2003-06-05 01:52:59 +00006560#endif
bellard31e31b82003-02-18 22:55:36 +00006561 break;
ths3ae43202007-09-16 21:39:48 +00006562#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00006563 case TARGET_NR_getdents64:
6564 {
aurel326556a832008-10-13 21:08:17 +00006565 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00006566 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00006567 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
6568 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00006569 ret = get_errno(sys_getdents64(arg1, dirp, count));
6570 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00006571 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00006572 int len = ret;
6573 int reclen;
6574 de = dirp;
6575 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00006576 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00006577 if (reclen > len)
6578 break;
bellard8083a3e2003-03-24 23:12:16 +00006579 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00006580 tswap64s((uint64_t *)&de->d_ino);
6581 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00006582 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00006583 len -= reclen;
6584 }
6585 }
pbrook53a59602006-03-25 19:31:22 +00006586 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00006587 }
6588 break;
bellarda541f292004-04-12 20:39:29 +00006589#endif /* TARGET_NR_getdents64 */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006590#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
6591#ifdef TARGET_S390X
6592 case TARGET_NR_select:
6593#else
bellard31e31b82003-02-18 22:55:36 +00006594 case TARGET_NR__newselect:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006595#endif
pbrook53a59602006-03-25 19:31:22 +00006596 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00006597 break;
thse5febef2007-04-01 18:31:35 +00006598#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05006599#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
6600# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00006601 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05006602# endif
6603# ifdef TARGET_NR_ppoll
6604 case TARGET_NR_ppoll:
6605# endif
bellard9de5e442003-03-23 16:49:39 +00006606 {
pbrook53a59602006-03-25 19:31:22 +00006607 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00006608 unsigned int nfds = arg2;
6609 int timeout = arg3;
6610 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00006611 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00006612
bellard579a97f2007-11-11 14:26:47 +00006613 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
6614 if (!target_pfd)
6615 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05006616
bellard9de5e442003-03-23 16:49:39 +00006617 pfd = alloca(sizeof(struct pollfd) * nfds);
6618 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006619 pfd[i].fd = tswap32(target_pfd[i].fd);
6620 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00006621 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05006622
6623# ifdef TARGET_NR_ppoll
6624 if (num == TARGET_NR_ppoll) {
6625 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
6626 target_sigset_t *target_set;
6627 sigset_t _set, *set = &_set;
6628
6629 if (arg3) {
6630 if (target_to_host_timespec(timeout_ts, arg3)) {
6631 unlock_user(target_pfd, arg1, 0);
6632 goto efault;
6633 }
6634 } else {
6635 timeout_ts = NULL;
6636 }
6637
6638 if (arg4) {
6639 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
6640 if (!target_set) {
6641 unlock_user(target_pfd, arg1, 0);
6642 goto efault;
6643 }
6644 target_to_host_sigset(set, target_set);
6645 } else {
6646 set = NULL;
6647 }
6648
6649 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
6650
6651 if (!is_error(ret) && arg3) {
6652 host_to_target_timespec(arg3, timeout_ts);
6653 }
6654 if (arg4) {
6655 unlock_user(target_set, arg4, 0);
6656 }
6657 } else
6658# endif
6659 ret = get_errno(poll(pfd, nfds, timeout));
6660
bellard9de5e442003-03-23 16:49:39 +00006661 if (!is_error(ret)) {
6662 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00006663 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00006664 }
6665 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00006666 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00006667 }
6668 break;
thse5febef2007-04-01 18:31:35 +00006669#endif
bellard31e31b82003-02-18 22:55:36 +00006670 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00006671 /* NOTE: the flock constant seems to be the same for every
6672 Linux platform */
6673 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006674 break;
6675 case TARGET_NR_readv:
6676 {
6677 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006678 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006679
6680 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006681 if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
6682 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006683 ret = get_errno(readv(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006684 unlock_iovec(vec, arg2, count, 1);
bellard31e31b82003-02-18 22:55:36 +00006685 }
6686 break;
6687 case TARGET_NR_writev:
6688 {
6689 int count = arg3;
bellard31e31b82003-02-18 22:55:36 +00006690 struct iovec *vec;
bellard31e31b82003-02-18 22:55:36 +00006691
6692 vec = alloca(count * sizeof(struct iovec));
bellard41df8412008-02-04 22:26:57 +00006693 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
6694 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006695 ret = get_errno(writev(arg1, vec, count));
pbrook53a59602006-03-25 19:31:22 +00006696 unlock_iovec(vec, arg2, count, 0);
bellard31e31b82003-02-18 22:55:36 +00006697 }
6698 break;
6699 case TARGET_NR_getsid:
6700 ret = get_errno(getsid(arg1));
6701 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006702#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00006703 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00006704 ret = get_errno(fdatasync(arg1));
6705 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006706#endif
bellard31e31b82003-02-18 22:55:36 +00006707 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00006708 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00006709 return value. */
ths0da46a62007-10-20 20:23:07 +00006710 ret = -TARGET_ENOTDIR;
6711 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05006712 case TARGET_NR_sched_getaffinity:
6713 {
6714 unsigned int mask_size;
6715 unsigned long *mask;
6716
6717 /*
6718 * sched_getaffinity needs multiples of ulong, so need to take
6719 * care of mismatches between target ulong and host ulong sizes.
6720 */
6721 if (arg2 & (sizeof(abi_ulong) - 1)) {
6722 ret = -TARGET_EINVAL;
6723 break;
6724 }
6725 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6726
6727 mask = alloca(mask_size);
6728 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
6729
6730 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09006731 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05006732 goto efault;
6733 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05006734 }
6735 }
6736 break;
6737 case TARGET_NR_sched_setaffinity:
6738 {
6739 unsigned int mask_size;
6740 unsigned long *mask;
6741
6742 /*
6743 * sched_setaffinity needs multiples of ulong, so need to take
6744 * care of mismatches between target ulong and host ulong sizes.
6745 */
6746 if (arg2 & (sizeof(abi_ulong) - 1)) {
6747 ret = -TARGET_EINVAL;
6748 break;
6749 }
6750 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
6751
6752 mask = alloca(mask_size);
6753 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
6754 goto efault;
6755 }
6756 memcpy(mask, p, arg2);
6757 unlock_user_struct(p, arg2, 0);
6758
6759 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
6760 }
6761 break;
bellard31e31b82003-02-18 22:55:36 +00006762 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00006763 {
pbrook53a59602006-03-25 19:31:22 +00006764 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006765 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00006766
bellard579a97f2007-11-11 14:26:47 +00006767 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
6768 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006769 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006770 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00006771 ret = get_errno(sched_setparam(arg1, &schp));
6772 }
6773 break;
bellard31e31b82003-02-18 22:55:36 +00006774 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00006775 {
pbrook53a59602006-03-25 19:31:22 +00006776 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006777 struct sched_param schp;
6778 ret = get_errno(sched_getparam(arg1, &schp));
6779 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006780 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
6781 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006782 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006783 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00006784 }
6785 }
6786 break;
bellard31e31b82003-02-18 22:55:36 +00006787 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00006788 {
pbrook53a59602006-03-25 19:31:22 +00006789 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00006790 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00006791 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
6792 goto efault;
bellard5cd43932003-03-29 16:54:36 +00006793 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00006794 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00006795 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
6796 }
6797 break;
bellard31e31b82003-02-18 22:55:36 +00006798 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00006799 ret = get_errno(sched_getscheduler(arg1));
6800 break;
bellard31e31b82003-02-18 22:55:36 +00006801 case TARGET_NR_sched_yield:
6802 ret = get_errno(sched_yield());
6803 break;
6804 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00006805 ret = get_errno(sched_get_priority_max(arg1));
6806 break;
bellard31e31b82003-02-18 22:55:36 +00006807 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00006808 ret = get_errno(sched_get_priority_min(arg1));
6809 break;
bellard31e31b82003-02-18 22:55:36 +00006810 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00006811 {
bellard5cd43932003-03-29 16:54:36 +00006812 struct timespec ts;
6813 ret = get_errno(sched_rr_get_interval(arg1, &ts));
6814 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006815 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00006816 }
6817 }
6818 break;
bellard31e31b82003-02-18 22:55:36 +00006819 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00006820 {
bellard1b6b0292003-03-22 17:31:38 +00006821 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00006822 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00006823 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00006824 if (is_error(ret) && arg2) {
6825 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00006826 }
6827 }
6828 break;
thse5febef2007-04-01 18:31:35 +00006829#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00006830 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00006831 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006832#endif
6833#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00006834 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00006835 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006836#endif
bellard31e31b82003-02-18 22:55:36 +00006837 case TARGET_NR_prctl:
thse5574482007-02-11 20:03:13 +00006838 switch (arg1)
6839 {
6840 case PR_GET_PDEATHSIG:
6841 {
6842 int deathsig;
6843 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
bellard2f619692007-11-16 10:46:05 +00006844 if (!is_error(ret) && arg2
6845 && put_user_ual(deathsig, arg2))
6846 goto efault;
thse5574482007-02-11 20:03:13 +00006847 }
6848 break;
6849 default:
6850 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
6851 break;
6852 }
ths39b9aae2007-02-11 18:36:44 +00006853 break;
bellardd2fd1af2007-11-14 18:08:56 +00006854#ifdef TARGET_NR_arch_prctl
6855 case TARGET_NR_arch_prctl:
6856#if defined(TARGET_I386) && !defined(TARGET_ABI32)
6857 ret = do_arch_prctl(cpu_env, arg1, arg2);
6858 break;
6859#else
6860 goto unimplemented;
6861#endif
6862#endif
bellard67867302003-11-23 17:05:30 +00006863#ifdef TARGET_NR_pread
bellard31e31b82003-02-18 22:55:36 +00006864 case TARGET_NR_pread:
Riku Voipio48e515d2011-07-12 15:40:51 +03006865 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006866 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006867 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6868 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006869 ret = get_errno(pread(arg1, p, arg3, arg4));
6870 unlock_user(p, arg2, ret);
bellard206f0fa2003-05-14 19:01:56 +00006871 break;
bellard31e31b82003-02-18 22:55:36 +00006872 case TARGET_NR_pwrite:
Riku Voipio48e515d2011-07-12 15:40:51 +03006873 if (regpairs_aligned(cpu_env))
balroga4ae00b2008-09-20 03:14:14 +00006874 arg4 = arg5;
bellard579a97f2007-11-11 14:26:47 +00006875 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6876 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006877 ret = get_errno(pwrite(arg1, p, arg3, arg4));
6878 unlock_user(p, arg2, 0);
bellard206f0fa2003-05-14 19:01:56 +00006879 break;
bellard67867302003-11-23 17:05:30 +00006880#endif
aurel32f2c7ba12008-03-28 22:32:06 +00006881#ifdef TARGET_NR_pread64
6882 case TARGET_NR_pread64:
6883 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6884 goto efault;
6885 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
6886 unlock_user(p, arg2, ret);
6887 break;
6888 case TARGET_NR_pwrite64:
6889 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6890 goto efault;
6891 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
6892 unlock_user(p, arg2, 0);
6893 break;
6894#endif
bellard31e31b82003-02-18 22:55:36 +00006895 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00006896 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
6897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006898 ret = get_errno(sys_getcwd1(p, arg2));
6899 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00006900 break;
6901 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00006902 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006903 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00006904 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00006905 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00006906#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02006907 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006908 defined(TARGET_M68K) || defined(TARGET_S390X)
bellard579a97f2007-11-11 14:26:47 +00006909 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00006910 break;
6911#else
bellard5cd43932003-03-29 16:54:36 +00006912 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00006913#endif
bellard31e31b82003-02-18 22:55:36 +00006914 case TARGET_NR_sendfile:
bellard5cd43932003-03-29 16:54:36 +00006915 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006916#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00006917 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00006918 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006919#endif
6920#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00006921 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00006922 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006923#endif
bellard048f6b42005-11-26 18:47:20 +00006924#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00006925 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00006926 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
6927 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006928 break;
bellard048f6b42005-11-26 18:47:20 +00006929#endif
bellardebc05482003-09-30 21:08:41 +00006930#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00006931 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00006932 {
6933 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006934 int resource = target_to_host_resource(arg1);
6935 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00006936 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006937 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00006938 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6939 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006940 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6941 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006942 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00006943 }
6944 break;
6945 }
bellardebc05482003-09-30 21:08:41 +00006946#endif
bellarda315a142005-01-30 22:59:18 +00006947#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00006948 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00006949 if (!(p = lock_user_string(arg1)))
6950 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006951 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
6952 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00006953 break;
bellarda315a142005-01-30 22:59:18 +00006954#endif
6955#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00006956 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00006957 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00006958 break;
bellarda315a142005-01-30 22:59:18 +00006959#endif
6960#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00006961 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00006962 if (!(p = lock_user_string(arg1)))
6963 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006964 ret = get_errno(stat(path(p), &st));
6965 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006966 if (!is_error(ret))
6967 ret = host_to_target_stat64(cpu_env, arg2, &st);
6968 break;
bellarda315a142005-01-30 22:59:18 +00006969#endif
6970#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00006971 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00006972 if (!(p = lock_user_string(arg1)))
6973 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006974 ret = get_errno(lstat(path(p), &st));
6975 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00006976 if (!is_error(ret))
6977 ret = host_to_target_stat64(cpu_env, arg2, &st);
6978 break;
bellarda315a142005-01-30 22:59:18 +00006979#endif
6980#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00006981 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00006982 ret = get_errno(fstat(arg1, &st));
6983 if (!is_error(ret))
6984 ret = host_to_target_stat64(cpu_env, arg2, &st);
6985 break;
bellardec86b0f2003-04-11 00:15:04 +00006986#endif
aurel329d33b762009-04-08 23:07:05 +00006987#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
6988 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
6989#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006990 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00006991#endif
6992#ifdef TARGET_NR_newfstatat
6993 case TARGET_NR_newfstatat:
6994#endif
balrog6a24a772008-09-20 02:23:36 +00006995 if (!(p = lock_user_string(arg2)))
6996 goto efault;
aurel329d33b762009-04-08 23:07:05 +00006997#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00006998 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00006999#else
7000 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7001#endif
balrog6a24a772008-09-20 02:23:36 +00007002 if (!is_error(ret))
7003 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007004 break;
bellarda315a142005-01-30 22:59:18 +00007005#endif
bellard67867302003-11-23 17:05:30 +00007006 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007007 if (!(p = lock_user_string(arg1)))
7008 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007009 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7010 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007011 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007012#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007013 case TARGET_NR_getuid:
7014 ret = get_errno(high2lowuid(getuid()));
7015 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007016#endif
7017#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007018 case TARGET_NR_getgid:
7019 ret = get_errno(high2lowgid(getgid()));
7020 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007021#endif
7022#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007023 case TARGET_NR_geteuid:
7024 ret = get_errno(high2lowuid(geteuid()));
7025 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007026#endif
7027#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007028 case TARGET_NR_getegid:
7029 ret = get_errno(high2lowgid(getegid()));
7030 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007031#endif
bellard67867302003-11-23 17:05:30 +00007032 case TARGET_NR_setreuid:
7033 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7034 break;
7035 case TARGET_NR_setregid:
7036 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7037 break;
7038 case TARGET_NR_getgroups:
7039 {
7040 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007041 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007042 gid_t *grouplist;
7043 int i;
7044
7045 grouplist = alloca(gidsetsize * sizeof(gid_t));
7046 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007047 if (gidsetsize == 0)
7048 break;
bellard67867302003-11-23 17:05:30 +00007049 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007050 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7051 if (!target_grouplist)
7052 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007053 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007054 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007055 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007056 }
7057 }
7058 break;
7059 case TARGET_NR_setgroups:
7060 {
7061 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007062 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007063 gid_t *grouplist;
7064 int i;
7065
7066 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007067 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7068 if (!target_grouplist) {
7069 ret = -TARGET_EFAULT;
7070 goto fail;
7071 }
bellard67867302003-11-23 17:05:30 +00007072 for(i = 0;i < gidsetsize; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007073 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007074 unlock_user(target_grouplist, arg2, 0);
bellard67867302003-11-23 17:05:30 +00007075 ret = get_errno(setgroups(gidsetsize, grouplist));
7076 }
7077 break;
7078 case TARGET_NR_fchown:
7079 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7080 break;
thsccfa72b2007-09-24 09:23:34 +00007081#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7082 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007083 if (!(p = lock_user_string(arg2)))
7084 goto efault;
7085 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7086 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007087 break;
7088#endif
bellard67867302003-11-23 17:05:30 +00007089#ifdef TARGET_NR_setresuid
7090 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007091 ret = get_errno(setresuid(low2highuid(arg1),
7092 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007093 low2highuid(arg3)));
7094 break;
7095#endif
7096#ifdef TARGET_NR_getresuid
7097 case TARGET_NR_getresuid:
7098 {
pbrook53a59602006-03-25 19:31:22 +00007099 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007100 ret = get_errno(getresuid(&ruid, &euid, &suid));
7101 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007102 if (put_user_u16(high2lowuid(ruid), arg1)
7103 || put_user_u16(high2lowuid(euid), arg2)
7104 || put_user_u16(high2lowuid(suid), arg3))
7105 goto efault;
bellard67867302003-11-23 17:05:30 +00007106 }
7107 }
7108 break;
7109#endif
7110#ifdef TARGET_NR_getresgid
7111 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007112 ret = get_errno(setresgid(low2highgid(arg1),
7113 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007114 low2highgid(arg3)));
7115 break;
7116#endif
7117#ifdef TARGET_NR_getresgid
7118 case TARGET_NR_getresgid:
7119 {
pbrook53a59602006-03-25 19:31:22 +00007120 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007121 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7122 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007123 if (put_user_u16(high2lowgid(rgid), arg1)
7124 || put_user_u16(high2lowgid(egid), arg2)
7125 || put_user_u16(high2lowgid(sgid), arg3))
7126 goto efault;
bellard67867302003-11-23 17:05:30 +00007127 }
7128 }
7129 break;
7130#endif
7131 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007132 if (!(p = lock_user_string(arg1)))
7133 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007134 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7135 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007136 break;
7137 case TARGET_NR_setuid:
7138 ret = get_errno(setuid(low2highuid(arg1)));
7139 break;
7140 case TARGET_NR_setgid:
7141 ret = get_errno(setgid(low2highgid(arg1)));
7142 break;
7143 case TARGET_NR_setfsuid:
7144 ret = get_errno(setfsuid(arg1));
7145 break;
7146 case TARGET_NR_setfsgid:
7147 ret = get_errno(setfsgid(arg1));
7148 break;
bellard67867302003-11-23 17:05:30 +00007149
bellarda315a142005-01-30 22:59:18 +00007150#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007151 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007152 if (!(p = lock_user_string(arg1)))
7153 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007154 ret = get_errno(lchown(p, arg2, arg3));
7155 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007156 break;
bellarda315a142005-01-30 22:59:18 +00007157#endif
7158#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007159 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007160 ret = get_errno(getuid());
7161 break;
bellarda315a142005-01-30 22:59:18 +00007162#endif
aurel3264b4d282008-11-14 17:20:15 +00007163
7164#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7165 /* Alpha specific */
7166 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007167 {
7168 uid_t euid;
7169 euid=geteuid();
7170 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7171 }
aurel3264b4d282008-11-14 17:20:15 +00007172 ret = get_errno(getuid());
7173 break;
7174#endif
7175#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7176 /* Alpha specific */
7177 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007178 {
7179 uid_t egid;
7180 egid=getegid();
7181 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7182 }
aurel3264b4d282008-11-14 17:20:15 +00007183 ret = get_errno(getgid());
7184 break;
7185#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007186#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7187 /* Alpha specific */
7188 case TARGET_NR_osf_getsysinfo:
7189 ret = -TARGET_EOPNOTSUPP;
7190 switch (arg1) {
7191 case TARGET_GSI_IEEE_FP_CONTROL:
7192 {
7193 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7194
7195 /* Copied from linux ieee_fpcr_to_swcr. */
7196 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7197 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7198 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7199 | SWCR_TRAP_ENABLE_DZE
7200 | SWCR_TRAP_ENABLE_OVF);
7201 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7202 | SWCR_TRAP_ENABLE_INE);
7203 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7204 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7205
7206 if (put_user_u64 (swcr, arg2))
7207 goto efault;
7208 ret = 0;
7209 }
7210 break;
7211
7212 /* case GSI_IEEE_STATE_AT_SIGNAL:
7213 -- Not implemented in linux kernel.
7214 case GSI_UACPROC:
7215 -- Retrieves current unaligned access state; not much used.
7216 case GSI_PROC_TYPE:
7217 -- Retrieves implver information; surely not used.
7218 case GSI_GET_HWRPB:
7219 -- Grabs a copy of the HWRPB; surely not used.
7220 */
7221 }
7222 break;
7223#endif
7224#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7225 /* Alpha specific */
7226 case TARGET_NR_osf_setsysinfo:
7227 ret = -TARGET_EOPNOTSUPP;
7228 switch (arg1) {
7229 case TARGET_SSI_IEEE_FP_CONTROL:
7230 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7231 {
7232 uint64_t swcr, fpcr, orig_fpcr;
7233
7234 if (get_user_u64 (swcr, arg2))
7235 goto efault;
7236 orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
7237 fpcr = orig_fpcr & FPCR_DYN_MASK;
7238
7239 /* Copied from linux ieee_swcr_to_fpcr. */
7240 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7241 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7242 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7243 | SWCR_TRAP_ENABLE_DZE
7244 | SWCR_TRAP_ENABLE_OVF)) << 48;
7245 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7246 | SWCR_TRAP_ENABLE_INE)) << 57;
7247 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7248 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7249
7250 cpu_alpha_store_fpcr (cpu_env, fpcr);
7251 ret = 0;
7252
7253 if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
7254 /* Old exceptions are not signaled. */
7255 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
7256
7257 /* If any exceptions set by this call, and are unmasked,
7258 send a signal. */
7259 /* ??? FIXME */
7260 }
7261 }
7262 break;
7263
7264 /* case SSI_NVPAIRS:
7265 -- Used with SSIN_UACPROC to enable unaligned accesses.
7266 case SSI_IEEE_STATE_AT_SIGNAL:
7267 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
7268 -- Not implemented in linux kernel
7269 */
7270 }
7271 break;
7272#endif
7273#ifdef TARGET_NR_osf_sigprocmask
7274 /* Alpha specific. */
7275 case TARGET_NR_osf_sigprocmask:
7276 {
7277 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01007278 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08007279 sigset_t set, oldset;
7280
7281 switch(arg1) {
7282 case TARGET_SIG_BLOCK:
7283 how = SIG_BLOCK;
7284 break;
7285 case TARGET_SIG_UNBLOCK:
7286 how = SIG_UNBLOCK;
7287 break;
7288 case TARGET_SIG_SETMASK:
7289 how = SIG_SETMASK;
7290 break;
7291 default:
7292 ret = -TARGET_EINVAL;
7293 goto fail;
7294 }
7295 mask = arg2;
7296 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01007297 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007298 host_to_target_old_sigset(&mask, &oldset);
7299 ret = mask;
7300 }
7301 break;
7302#endif
aurel3264b4d282008-11-14 17:20:15 +00007303
bellarda315a142005-01-30 22:59:18 +00007304#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00007305 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00007306 ret = get_errno(getgid());
7307 break;
bellarda315a142005-01-30 22:59:18 +00007308#endif
7309#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00007310 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00007311 ret = get_errno(geteuid());
7312 break;
bellarda315a142005-01-30 22:59:18 +00007313#endif
7314#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00007315 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00007316 ret = get_errno(getegid());
7317 break;
bellarda315a142005-01-30 22:59:18 +00007318#endif
7319#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00007320 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00007321 ret = get_errno(setreuid(arg1, arg2));
7322 break;
bellarda315a142005-01-30 22:59:18 +00007323#endif
7324#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00007325 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00007326 ret = get_errno(setregid(arg1, arg2));
7327 break;
bellarda315a142005-01-30 22:59:18 +00007328#endif
7329#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00007330 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00007331 {
7332 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007333 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007334 gid_t *grouplist;
7335 int i;
7336
7337 grouplist = alloca(gidsetsize * sizeof(gid_t));
7338 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007339 if (gidsetsize == 0)
7340 break;
bellard99c475a2005-01-31 20:45:13 +00007341 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007342 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
7343 if (!target_grouplist) {
7344 ret = -TARGET_EFAULT;
7345 goto fail;
7346 }
balroga2155fc2008-09-20 02:12:08 +00007347 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00007348 target_grouplist[i] = tswap32(grouplist[i]);
7349 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00007350 }
7351 }
7352 break;
bellarda315a142005-01-30 22:59:18 +00007353#endif
7354#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00007355 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00007356 {
7357 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00007358 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00007359 gid_t *grouplist;
7360 int i;
ths3b46e622007-09-17 08:09:54 +00007361
bellard99c475a2005-01-31 20:45:13 +00007362 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00007363 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
7364 if (!target_grouplist) {
7365 ret = -TARGET_EFAULT;
7366 goto fail;
7367 }
bellard99c475a2005-01-31 20:45:13 +00007368 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00007369 grouplist[i] = tswap32(target_grouplist[i]);
7370 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00007371 ret = get_errno(setgroups(gidsetsize, grouplist));
7372 }
7373 break;
bellarda315a142005-01-30 22:59:18 +00007374#endif
7375#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00007376 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00007377 ret = get_errno(fchown(arg1, arg2, arg3));
7378 break;
bellarda315a142005-01-30 22:59:18 +00007379#endif
7380#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00007381 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007382 ret = get_errno(setresuid(arg1, arg2, arg3));
7383 break;
bellarda315a142005-01-30 22:59:18 +00007384#endif
7385#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00007386 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00007387 {
pbrook53a59602006-03-25 19:31:22 +00007388 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00007389 ret = get_errno(getresuid(&ruid, &euid, &suid));
7390 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007391 if (put_user_u32(ruid, arg1)
7392 || put_user_u32(euid, arg2)
7393 || put_user_u32(suid, arg3))
7394 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007395 }
7396 }
7397 break;
bellarda315a142005-01-30 22:59:18 +00007398#endif
7399#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00007400 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007401 ret = get_errno(setresgid(arg1, arg2, arg3));
7402 break;
bellarda315a142005-01-30 22:59:18 +00007403#endif
7404#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00007405 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00007406 {
pbrook53a59602006-03-25 19:31:22 +00007407 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00007408 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7409 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007410 if (put_user_u32(rgid, arg1)
7411 || put_user_u32(egid, arg2)
7412 || put_user_u32(sgid, arg3))
7413 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00007414 }
7415 }
7416 break;
bellarda315a142005-01-30 22:59:18 +00007417#endif
7418#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00007419 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00007420 if (!(p = lock_user_string(arg1)))
7421 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007422 ret = get_errno(chown(p, arg2, arg3));
7423 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007424 break;
bellarda315a142005-01-30 22:59:18 +00007425#endif
7426#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00007427 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00007428 ret = get_errno(setuid(arg1));
7429 break;
bellarda315a142005-01-30 22:59:18 +00007430#endif
7431#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00007432 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00007433 ret = get_errno(setgid(arg1));
7434 break;
bellarda315a142005-01-30 22:59:18 +00007435#endif
7436#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00007437 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00007438 ret = get_errno(setfsuid(arg1));
7439 break;
bellarda315a142005-01-30 22:59:18 +00007440#endif
7441#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00007442 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00007443 ret = get_errno(setfsgid(arg1));
7444 break;
bellarda315a142005-01-30 22:59:18 +00007445#endif
bellard67867302003-11-23 17:05:30 +00007446
bellard31e31b82003-02-18 22:55:36 +00007447 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00007448 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00007449#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00007450 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00007451 {
7452 void *a;
7453 ret = -TARGET_EFAULT;
7454 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
7455 goto efault;
7456 if (!(p = lock_user_string(arg3)))
7457 goto mincore_fail;
7458 ret = get_errno(mincore(a, arg2, p));
7459 unlock_user(p, arg3, ret);
7460 mincore_fail:
7461 unlock_user(a, arg1, 0);
7462 }
7463 break;
bellardffa65c32004-01-04 23:57:22 +00007464#endif
aurel32408321b2008-10-01 21:46:32 +00007465#ifdef TARGET_NR_arm_fadvise64_64
7466 case TARGET_NR_arm_fadvise64_64:
7467 {
7468 /*
7469 * arm_fadvise64_64 looks like fadvise64_64 but
7470 * with different argument order
7471 */
7472 abi_long temp;
7473 temp = arg3;
7474 arg3 = arg4;
7475 arg4 = temp;
7476 }
7477#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007478#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00007479#ifdef TARGET_NR_fadvise64_64
7480 case TARGET_NR_fadvise64_64:
7481#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02007482#ifdef TARGET_NR_fadvise64
7483 case TARGET_NR_fadvise64:
7484#endif
7485#ifdef TARGET_S390X
7486 switch (arg4) {
7487 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
7488 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
7489 case 6: arg4 = POSIX_FADV_DONTNEED; break;
7490 case 7: arg4 = POSIX_FADV_NOREUSE; break;
7491 default: break;
7492 }
7493#endif
7494 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00007495 break;
7496#endif
bellardffa65c32004-01-04 23:57:22 +00007497#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00007498 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00007499 /* A straight passthrough may not be safe because qemu sometimes
7500 turns private flie-backed mappings into anonymous mappings.
7501 This will break MADV_DONTNEED.
7502 This is a hint, so ignoring and returning success is ok. */
7503 ret = get_errno(0);
7504 break;
bellardffa65c32004-01-04 23:57:22 +00007505#endif
blueswir1992f48a2007-10-14 16:27:31 +00007506#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00007507 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00007508 {
thsb1e341e2007-03-20 21:50:52 +00007509 int cmd;
bellard77e46722003-04-29 20:39:06 +00007510 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00007511 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00007512#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00007513 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00007514#endif
bellard77e46722003-04-29 20:39:06 +00007515
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007516 cmd = target_to_host_fcntl_cmd(arg2);
7517 if (cmd == -TARGET_EINVAL)
7518 return cmd;
thsb1e341e2007-03-20 21:50:52 +00007519
bellard60cd49d2003-03-16 22:53:56 +00007520 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00007521 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00007522#ifdef TARGET_ARM
7523 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007524 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7525 goto efault;
ths58134272007-03-31 18:59:32 +00007526 fl.l_type = tswap16(target_efl->l_type);
7527 fl.l_whence = tswap16(target_efl->l_whence);
7528 fl.l_start = tswap64(target_efl->l_start);
7529 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007530 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00007531 unlock_user_struct(target_efl, arg3, 0);
7532 } else
7533#endif
7534 {
bellard9ee1fa22007-11-11 15:11:19 +00007535 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7536 goto efault;
ths58134272007-03-31 18:59:32 +00007537 fl.l_type = tswap16(target_fl->l_type);
7538 fl.l_whence = tswap16(target_fl->l_whence);
7539 fl.l_start = tswap64(target_fl->l_start);
7540 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007541 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00007542 unlock_user_struct(target_fl, arg3, 0);
7543 }
thsb1e341e2007-03-20 21:50:52 +00007544 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007545 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00007546#ifdef TARGET_ARM
7547 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007548 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
7549 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007550 target_efl->l_type = tswap16(fl.l_type);
7551 target_efl->l_whence = tswap16(fl.l_whence);
7552 target_efl->l_start = tswap64(fl.l_start);
7553 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007554 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007555 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007556 } else
7557#endif
7558 {
bellard9ee1fa22007-11-11 15:11:19 +00007559 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
7560 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007561 target_fl->l_type = tswap16(fl.l_type);
7562 target_fl->l_whence = tswap16(fl.l_whence);
7563 target_fl->l_start = tswap64(fl.l_start);
7564 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007565 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00007566 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00007567 }
bellard77e46722003-04-29 20:39:06 +00007568 }
7569 break;
7570
thsb1e341e2007-03-20 21:50:52 +00007571 case TARGET_F_SETLK64:
7572 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00007573#ifdef TARGET_ARM
7574 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00007575 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
7576 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007577 fl.l_type = tswap16(target_efl->l_type);
7578 fl.l_whence = tswap16(target_efl->l_whence);
7579 fl.l_start = tswap64(target_efl->l_start);
7580 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007581 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007582 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007583 } else
7584#endif
7585 {
bellard9ee1fa22007-11-11 15:11:19 +00007586 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
7587 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00007588 fl.l_type = tswap16(target_fl->l_type);
7589 fl.l_whence = tswap16(target_fl->l_whence);
7590 fl.l_start = tswap64(target_fl->l_start);
7591 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007592 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00007593 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00007594 }
thsb1e341e2007-03-20 21:50:52 +00007595 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00007596 break;
bellard60cd49d2003-03-16 22:53:56 +00007597 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007598 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00007599 break;
7600 }
bellard77e46722003-04-29 20:39:06 +00007601 break;
7602 }
bellard60cd49d2003-03-16 22:53:56 +00007603#endif
ths7d600c82006-12-08 01:32:58 +00007604#ifdef TARGET_NR_cacheflush
7605 case TARGET_NR_cacheflush:
7606 /* self-modifying code is handled automatically, so nothing needed */
7607 ret = 0;
7608 break;
7609#endif
bellardebc05482003-09-30 21:08:41 +00007610#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00007611 case TARGET_NR_security:
7612 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007613#endif
bellardc573ff62004-01-04 15:51:36 +00007614#ifdef TARGET_NR_getpagesize
7615 case TARGET_NR_getpagesize:
7616 ret = TARGET_PAGE_SIZE;
7617 break;
7618#endif
bellard31e31b82003-02-18 22:55:36 +00007619 case TARGET_NR_gettid:
7620 ret = get_errno(gettid());
7621 break;
thse5febef2007-04-01 18:31:35 +00007622#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00007623 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00007624#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03007625 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00007626 arg2 = arg3;
7627 arg3 = arg4;
7628 arg4 = arg5;
7629 }
aurel322054ac92008-10-13 21:08:07 +00007630 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
7631#else
7632 ret = get_errno(readahead(arg1, arg2, arg3));
7633#endif
7634 break;
thse5febef2007-04-01 18:31:35 +00007635#endif
bellardebc05482003-09-30 21:08:41 +00007636#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00007637 case TARGET_NR_setxattr:
7638 case TARGET_NR_lsetxattr:
7639 case TARGET_NR_fsetxattr:
7640 case TARGET_NR_getxattr:
7641 case TARGET_NR_lgetxattr:
7642 case TARGET_NR_fgetxattr:
7643 case TARGET_NR_listxattr:
7644 case TARGET_NR_llistxattr:
7645 case TARGET_NR_flistxattr:
7646 case TARGET_NR_removexattr:
7647 case TARGET_NR_lremovexattr:
7648 case TARGET_NR_fremovexattr:
Arnaud Patard6f932f92009-04-21 21:04:18 +03007649 ret = -TARGET_EOPNOTSUPP;
7650 break;
bellardebc05482003-09-30 21:08:41 +00007651#endif
7652#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00007653 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007654#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00007655 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
7656 ret = 0;
7657 break;
edgar_iglef967792009-01-07 14:19:38 +00007658#elif defined(TARGET_CRIS)
7659 if (arg1 & 0xff)
7660 ret = -TARGET_EINVAL;
7661 else {
7662 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
7663 ret = 0;
7664 }
7665 break;
bellard8d18e892007-11-14 15:18:40 +00007666#elif defined(TARGET_I386) && defined(TARGET_ABI32)
7667 ret = do_set_thread_area(cpu_env, arg1);
7668 break;
ths6f5b89a2007-03-02 20:48:00 +00007669#else
7670 goto unimplemented_nowarn;
7671#endif
7672#endif
7673#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00007674 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00007675#if defined(TARGET_I386) && defined(TARGET_ABI32)
7676 ret = do_get_thread_area(cpu_env, arg1);
7677#else
bellard5cd43932003-03-29 16:54:36 +00007678 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00007679#endif
bellard8d18e892007-11-14 15:18:40 +00007680#endif
bellard48dc41e2006-06-21 18:15:50 +00007681#ifdef TARGET_NR_getdomainname
7682 case TARGET_NR_getdomainname:
7683 goto unimplemented_nowarn;
7684#endif
ths6f5b89a2007-03-02 20:48:00 +00007685
thsb5906f92007-03-19 13:32:45 +00007686#ifdef TARGET_NR_clock_gettime
7687 case TARGET_NR_clock_gettime:
7688 {
7689 struct timespec ts;
7690 ret = get_errno(clock_gettime(arg1, &ts));
7691 if (!is_error(ret)) {
7692 host_to_target_timespec(arg2, &ts);
7693 }
7694 break;
7695 }
7696#endif
7697#ifdef TARGET_NR_clock_getres
7698 case TARGET_NR_clock_getres:
7699 {
7700 struct timespec ts;
7701 ret = get_errno(clock_getres(arg1, &ts));
7702 if (!is_error(ret)) {
7703 host_to_target_timespec(arg2, &ts);
7704 }
7705 break;
7706 }
7707#endif
pbrook63d76512008-05-29 13:43:29 +00007708#ifdef TARGET_NR_clock_nanosleep
7709 case TARGET_NR_clock_nanosleep:
7710 {
7711 struct timespec ts;
7712 target_to_host_timespec(&ts, arg3);
7713 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
7714 if (arg4)
7715 host_to_target_timespec(arg4, &ts);
7716 break;
7717 }
7718#endif
thsb5906f92007-03-19 13:32:45 +00007719
ths6f5b89a2007-03-02 20:48:00 +00007720#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
7721 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00007722 ret = get_errno(set_tid_address((int *)g2h(arg1)));
7723 break;
ths6f5b89a2007-03-02 20:48:00 +00007724#endif
7725
ths3ae43202007-09-16 21:39:48 +00007726#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00007727 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00007728 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00007729 break;
7730#endif
7731
ths3ae43202007-09-16 21:39:48 +00007732#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00007733 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00007734 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
7735 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00007736 break;
7737#endif
7738
ths4f2b1fe2007-06-21 21:57:12 +00007739#ifdef TARGET_NR_set_robust_list
7740 case TARGET_NR_set_robust_list:
7741 goto unimplemented_nowarn;
7742#endif
7743
ths9007f0e2007-09-25 17:50:37 +00007744#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
7745 case TARGET_NR_utimensat:
7746 {
Riku Voipioebc996f2009-04-21 15:01:51 +03007747 struct timespec *tsp, ts[2];
7748 if (!arg3) {
7749 tsp = NULL;
7750 } else {
7751 target_to_host_timespec(ts, arg3);
7752 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
7753 tsp = ts;
7754 }
ths9007f0e2007-09-25 17:50:37 +00007755 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03007756 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00007757 else {
bellard579a97f2007-11-11 14:26:47 +00007758 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00007759 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00007760 goto fail;
7761 }
Riku Voipioebc996f2009-04-21 15:01:51 +03007762 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00007763 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00007764 }
7765 }
7766 break;
7767#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02007768#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00007769 case TARGET_NR_futex:
7770 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
7771 break;
7772#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007773#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00007774 case TARGET_NR_inotify_init:
7775 ret = get_errno(sys_inotify_init());
7776 break;
7777#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007778#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00007779#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
7780 case TARGET_NR_inotify_init1:
7781 ret = get_errno(sys_inotify_init1(arg1));
7782 break;
7783#endif
Stefan Weila1606b02010-03-28 11:44:41 +02007784#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007785#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00007786 case TARGET_NR_inotify_add_watch:
7787 p = lock_user_string(arg2);
7788 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
7789 unlock_user(p, arg2, 0);
7790 break;
7791#endif
aurel32dbfe4c32009-04-08 21:29:30 +00007792#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00007793 case TARGET_NR_inotify_rm_watch:
7794 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
7795 break;
7796#endif
ths9007f0e2007-09-25 17:50:37 +00007797
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07007798#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00007799 case TARGET_NR_mq_open:
7800 {
7801 struct mq_attr posix_mq_attr;
7802
7803 p = lock_user_string(arg1 - 1);
7804 if (arg4 != 0)
7805 copy_from_user_mq_attr (&posix_mq_attr, arg4);
7806 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
7807 unlock_user (p, arg1, 0);
7808 }
7809 break;
7810
7811 case TARGET_NR_mq_unlink:
7812 p = lock_user_string(arg1 - 1);
7813 ret = get_errno(mq_unlink(p));
7814 unlock_user (p, arg1, 0);
7815 break;
7816
7817 case TARGET_NR_mq_timedsend:
7818 {
7819 struct timespec ts;
7820
7821 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7822 if (arg5 != 0) {
7823 target_to_host_timespec(&ts, arg5);
7824 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
7825 host_to_target_timespec(arg5, &ts);
7826 }
7827 else
7828 ret = get_errno(mq_send(arg1, p, arg3, arg4));
7829 unlock_user (p, arg2, arg3);
7830 }
7831 break;
7832
7833 case TARGET_NR_mq_timedreceive:
7834 {
7835 struct timespec ts;
7836 unsigned int prio;
7837
7838 p = lock_user (VERIFY_READ, arg2, arg3, 1);
7839 if (arg5 != 0) {
7840 target_to_host_timespec(&ts, arg5);
7841 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
7842 host_to_target_timespec(arg5, &ts);
7843 }
7844 else
7845 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
7846 unlock_user (p, arg2, arg3);
7847 if (arg4 != 0)
7848 put_user_u32(prio, arg4);
7849 }
7850 break;
7851
7852 /* Not implemented for now... */
7853/* case TARGET_NR_mq_notify: */
7854/* break; */
7855
7856 case TARGET_NR_mq_getsetattr:
7857 {
7858 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
7859 ret = 0;
7860 if (arg3 != 0) {
7861 ret = mq_getattr(arg1, &posix_mq_attr_out);
7862 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
7863 }
7864 if (arg2 != 0) {
7865 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
7866 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
7867 }
7868
7869 }
7870 break;
7871#endif
7872
vibisreenivasan3ce34df2009-05-16 18:32:41 +05307873#ifdef CONFIG_SPLICE
7874#ifdef TARGET_NR_tee
7875 case TARGET_NR_tee:
7876 {
7877 ret = get_errno(tee(arg1,arg2,arg3,arg4));
7878 }
7879 break;
7880#endif
7881#ifdef TARGET_NR_splice
7882 case TARGET_NR_splice:
7883 {
7884 loff_t loff_in, loff_out;
7885 loff_t *ploff_in = NULL, *ploff_out = NULL;
7886 if(arg2) {
7887 get_user_u64(loff_in, arg2);
7888 ploff_in = &loff_in;
7889 }
7890 if(arg4) {
7891 get_user_u64(loff_out, arg2);
7892 ploff_out = &loff_out;
7893 }
7894 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
7895 }
7896 break;
7897#endif
7898#ifdef TARGET_NR_vmsplice
7899 case TARGET_NR_vmsplice:
7900 {
7901 int count = arg3;
7902 struct iovec *vec;
7903
7904 vec = alloca(count * sizeof(struct iovec));
7905 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
7906 goto efault;
7907 ret = get_errno(vmsplice(arg1, vec, count, arg4));
7908 unlock_iovec(vec, arg2, count, 0);
7909 }
7910 break;
7911#endif
7912#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03007913#ifdef CONFIG_EVENTFD
7914#if defined(TARGET_NR_eventfd)
7915 case TARGET_NR_eventfd:
7916 ret = get_errno(eventfd(arg1, 0));
7917 break;
7918#endif
7919#if defined(TARGET_NR_eventfd2)
7920 case TARGET_NR_eventfd2:
7921 ret = get_errno(eventfd(arg1, arg2));
7922 break;
7923#endif
7924#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03007925#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
7926 case TARGET_NR_fallocate:
7927 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
7928 break;
7929#endif
Peter Maydellc727f472011-01-06 11:05:10 +00007930#if defined(CONFIG_SYNC_FILE_RANGE)
7931#if defined(TARGET_NR_sync_file_range)
7932 case TARGET_NR_sync_file_range:
7933#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03007934#if defined(TARGET_MIPS)
7935 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7936 target_offset64(arg5, arg6), arg7));
7937#else
Peter Maydellc727f472011-01-06 11:05:10 +00007938 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
7939 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03007940#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00007941#else
7942 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
7943#endif
7944 break;
7945#endif
7946#if defined(TARGET_NR_sync_file_range2)
7947 case TARGET_NR_sync_file_range2:
7948 /* This is like sync_file_range but the arguments are reordered */
7949#if TARGET_ABI_BITS == 32
7950 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
7951 target_offset64(arg5, arg6), arg2));
7952#else
7953 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
7954#endif
7955 break;
7956#endif
7957#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00007958#if defined(CONFIG_EPOLL)
7959#if defined(TARGET_NR_epoll_create)
7960 case TARGET_NR_epoll_create:
7961 ret = get_errno(epoll_create(arg1));
7962 break;
7963#endif
7964#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
7965 case TARGET_NR_epoll_create1:
7966 ret = get_errno(epoll_create1(arg1));
7967 break;
7968#endif
7969#if defined(TARGET_NR_epoll_ctl)
7970 case TARGET_NR_epoll_ctl:
7971 {
7972 struct epoll_event ep;
7973 struct epoll_event *epp = 0;
7974 if (arg4) {
7975 struct target_epoll_event *target_ep;
7976 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
7977 goto efault;
7978 }
7979 ep.events = tswap32(target_ep->events);
7980 /* The epoll_data_t union is just opaque data to the kernel,
7981 * so we transfer all 64 bits across and need not worry what
7982 * actual data type it is.
7983 */
7984 ep.data.u64 = tswap64(target_ep->data.u64);
7985 unlock_user_struct(target_ep, arg4, 0);
7986 epp = &ep;
7987 }
7988 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
7989 break;
7990 }
7991#endif
7992
7993#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
7994#define IMPLEMENT_EPOLL_PWAIT
7995#endif
7996#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
7997#if defined(TARGET_NR_epoll_wait)
7998 case TARGET_NR_epoll_wait:
7999#endif
8000#if defined(IMPLEMENT_EPOLL_PWAIT)
8001 case TARGET_NR_epoll_pwait:
8002#endif
8003 {
8004 struct target_epoll_event *target_ep;
8005 struct epoll_event *ep;
8006 int epfd = arg1;
8007 int maxevents = arg3;
8008 int timeout = arg4;
8009
8010 target_ep = lock_user(VERIFY_WRITE, arg2,
8011 maxevents * sizeof(struct target_epoll_event), 1);
8012 if (!target_ep) {
8013 goto efault;
8014 }
8015
8016 ep = alloca(maxevents * sizeof(struct epoll_event));
8017
8018 switch (num) {
8019#if defined(IMPLEMENT_EPOLL_PWAIT)
8020 case TARGET_NR_epoll_pwait:
8021 {
8022 target_sigset_t *target_set;
8023 sigset_t _set, *set = &_set;
8024
8025 if (arg5) {
8026 target_set = lock_user(VERIFY_READ, arg5,
8027 sizeof(target_sigset_t), 1);
8028 if (!target_set) {
8029 unlock_user(target_ep, arg2, 0);
8030 goto efault;
8031 }
8032 target_to_host_sigset(set, target_set);
8033 unlock_user(target_set, arg5, 0);
8034 } else {
8035 set = NULL;
8036 }
8037
8038 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8039 break;
8040 }
8041#endif
8042#if defined(TARGET_NR_epoll_wait)
8043 case TARGET_NR_epoll_wait:
8044 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8045 break;
8046#endif
8047 default:
8048 ret = -TARGET_ENOSYS;
8049 }
8050 if (!is_error(ret)) {
8051 int i;
8052 for (i = 0; i < ret; i++) {
8053 target_ep[i].events = tswap32(ep[i].events);
8054 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8055 }
8056 }
8057 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8058 break;
8059 }
8060#endif
8061#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008062#ifdef TARGET_NR_prlimit64
8063 case TARGET_NR_prlimit64:
8064 {
8065 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8066 struct target_rlimit64 *target_rnew, *target_rold;
8067 struct host_rlimit64 rnew, rold, *rnewp = 0;
8068 if (arg3) {
8069 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8070 goto efault;
8071 }
8072 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8073 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8074 unlock_user_struct(target_rnew, arg3, 0);
8075 rnewp = &rnew;
8076 }
8077
8078 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8079 if (!is_error(ret) && arg4) {
8080 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8081 goto efault;
8082 }
8083 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8084 target_rold->rlim_max = tswap64(rold.rlim_max);
8085 unlock_user_struct(target_rold, arg4, 1);
8086 }
8087 break;
8088 }
8089#endif
bellard31e31b82003-02-18 22:55:36 +00008090 default:
8091 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00008092 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00008093#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 +00008094 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00008095#endif
ths0da46a62007-10-20 20:23:07 +00008096 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00008097 break;
8098 }
bellard579a97f2007-11-11 14:26:47 +00008099fail:
bellardc573ff62004-01-04 15:51:36 +00008100#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00008101 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00008102#endif
thsb92c47c2007-11-01 00:07:38 +00008103 if(do_strace)
8104 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00008105 return ret;
bellard579a97f2007-11-11 14:26:47 +00008106efault:
8107 ret = -TARGET_EFAULT;
8108 goto fail;
bellard31e31b82003-02-18 22:55:36 +00008109}