blob: ee82a2da4ef73fb35e70e73bffbaeb3bef9f9d53 [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>
John Spencerc56dc772012-12-10 07:59:46 +010031#include <grp.h>
bellard31e31b82003-02-18 22:55:36 +000032#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000033#include <sys/ipc.h>
34#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/stat.h>
38#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010039#include <sys/file.h>
40#include <sys/fsuid.h>
41#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000042#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/resource.h>
44#include <sys/mman.h>
45#include <sys/swap.h>
46#include <signal.h>
47#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020048#ifdef __ia64__
49int __clone2(int (*fn)(void *), void *child_stack_base,
50 size_t stack_size, int flags, void *arg, ...);
51#endif
bellard31e31b82003-02-18 22:55:36 +000052#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000053#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000054#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000055#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000056#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000057#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000058#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000059#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000060#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000061#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000062#include <sys/utsname.h>
bellard72f03902003-02-18 23:33:18 +000063//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000064#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000065#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020066#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000067#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020068#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020069#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000070#include <sys/gmon.h>
71#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030072#ifdef CONFIG_EVENTFD
73#include <sys/eventfd.h>
74#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000075#ifdef CONFIG_EPOLL
76#include <sys/epoll.h>
77#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070078#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010079#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070080#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000081#ifdef CONFIG_SENDFILE
82#include <sys/sendfile.h>
83#endif
bellard31e31b82003-02-18 22:55:36 +000084
85#define termios host_termios
86#define winsize host_winsize
87#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000088#define sgttyb host_sgttyb /* same as target */
89#define tchars host_tchars /* same as target */
90#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000091
92#include <linux/termios.h>
93#include <linux/unistd.h>
94#include <linux/utsname.h>
95#include <linux/cdrom.h>
96#include <linux/hdreg.h>
97#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000098#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000099#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300100#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000101#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000102#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000103#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200104#include <linux/fb.h>
105#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100106#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000107#include <linux/reboot.h>
pbrookd7e40362008-05-23 16:06:43 +0000108#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100109#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000110
bellard3ef693a2003-03-23 20:17:16 +0000111#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000112
Juan Quintela2f7bb872009-07-27 16:13:24 +0200113#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +0000114#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
115 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
116#else
117/* XXX: Hardcode the above values. */
118#define CLONE_NPTL_FLAGS2 0
pbrook30813ce2008-06-02 15:45:44 +0000119#endif
120
bellard72f03902003-02-18 23:33:18 +0000121//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000122
bellard1a9353d2003-03-16 20:28:50 +0000123//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000124#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
125#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000126
bellard70a194b2003-08-11 22:20:16 +0000127
bellard70a194b2003-08-11 22:20:16 +0000128#undef _syscall0
129#undef _syscall1
130#undef _syscall2
131#undef _syscall3
132#undef _syscall4
133#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000134#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000155static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000156{ \
157 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000158}
159
bellard83fcb512006-06-14 13:37:16 +0000160#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000161static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000162{ \
163 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000164}
165
bellard83fcb512006-06-14 13:37:16 +0000166#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000169{ \
170 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000171}
bellard83fcb512006-06-14 13:37:16 +0000172
173
174#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
175 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000176static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
177 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000178{ \
179 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
180}
181
bellard70a194b2003-08-11 22:20:16 +0000182
bellard31e31b82003-02-18 22:55:36 +0000183#define __NR_sys_uname __NR_uname
ths92a34c12007-09-24 09:27:49 +0000184#define __NR_sys_faccessat __NR_faccessat
ths814d7972007-09-24 09:26:51 +0000185#define __NR_sys_fchmodat __NR_fchmodat
thsccfa72b2007-09-24 09:23:34 +0000186#define __NR_sys_fchownat __NR_fchownat
balrog6a24a772008-09-20 02:23:36 +0000187#define __NR_sys_fstatat64 __NR_fstatat64
balrogac8a6552008-09-20 02:25:39 +0000188#define __NR_sys_futimesat __NR_futimesat
bellard72f03902003-02-18 23:33:18 +0000189#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000190#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000191#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000192#define __NR_sys_getpriority __NR_getpriority
ths64f0ce42007-09-24 09:25:06 +0000193#define __NR_sys_linkat __NR_linkat
ths4472ad02007-09-24 09:22:32 +0000194#define __NR_sys_mkdirat __NR_mkdirat
ths75ac37a2007-09-24 09:23:05 +0000195#define __NR_sys_mknodat __NR_mknodat
aurel329d33b762009-04-08 23:07:05 +0000196#define __NR_sys_newfstatat __NR_newfstatat
ths82424832007-09-24 09:21:55 +0000197#define __NR_sys_openat __NR_openat
ths5e0ccb12007-09-24 09:26:10 +0000198#define __NR_sys_readlinkat __NR_readlinkat
ths722183f2007-09-24 09:24:37 +0000199#define __NR_sys_renameat __NR_renameat
bellard66fb9762003-03-23 01:06:05 +0000200#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
thsf0b62432007-09-24 09:25:40 +0000201#define __NR_sys_symlinkat __NR_symlinkat
ths7494b0f2007-02-11 18:26:53 +0000202#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000203#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000204#define __NR_sys_tkill __NR_tkill
ths8170f562007-09-24 09:24:11 +0000205#define __NR_sys_unlinkat __NR_unlinkat
ths9007f0e2007-09-25 17:50:37 +0000206#define __NR_sys_utimensat __NR_utimensat
pbrookbd0c5662008-05-29 14:34:11 +0000207#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000208#define __NR_sys_inotify_init __NR_inotify_init
209#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
210#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000211
Alexander Graf42a39fb2011-04-15 17:32:45 +0200212#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
213 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000214#define __NR__llseek __NR_lseek
215#endif
216
bellard72f03902003-02-18 23:33:18 +0000217#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000218_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000219#else
ths0da46a62007-10-20 20:23:07 +0000220/* This is a replacement for the host gettid() and must return a host
221 errno. */
bellard72f03902003-02-18 23:33:18 +0000222static int gettid(void) {
223 return -ENOSYS;
224}
225#endif
aurel323b3f24a2009-04-15 16:12:13 +0000226_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
aurel323b3f24a2009-04-15 16:12:13 +0000227#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
228_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
229#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700230#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000231_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
232 loff_t *, res, uint, wh);
233#endif
234_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
235_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
236#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
237_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
238#endif
239#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
240_syscall2(int,sys_tkill,int,tid,int,sig)
241#endif
242#ifdef __NR_exit_group
243_syscall1(int,exit_group,int,error_code)
244#endif
245#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
246_syscall1(int,set_tid_address,int *,tidptr)
247#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +0200248#if defined(CONFIG_USE_NPTL)
aurel323b3f24a2009-04-15 16:12:13 +0000249#if defined(TARGET_NR_futex) && defined(__NR_futex)
250_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
251 const struct timespec *,timeout,int *,uaddr2,int,val3)
252#endif
253#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500254#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
255_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
256 unsigned long *, user_mask_ptr);
257#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
258_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
259 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200260_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
261 void *, arg);
aurel323b3f24a2009-04-15 16:12:13 +0000262
263static bitmask_transtbl fcntl_flags_tbl[] = {
264 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
265 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
266 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
267 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
268 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
269 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
270 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
271 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700272 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000273 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
274 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
275 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
276 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000277#if defined(O_DIRECT)
278 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
279#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700280#if defined(O_NOATIME)
281 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
282#endif
283#if defined(O_CLOEXEC)
284 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
285#endif
286#if defined(O_PATH)
287 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
288#endif
289 /* Don't terminate the list prematurely on 64-bit host+guest. */
290#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
291 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
292#endif
aurel323b3f24a2009-04-15 16:12:13 +0000293 { 0, 0, 0, 0 }
294};
295
296#define COPY_UTSNAME_FIELD(dest, src) \
297 do { \
298 /* __NEW_UTS_LEN doesn't include terminating null */ \
299 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
300 (dest)[__NEW_UTS_LEN] = '\0'; \
301 } while (0)
302
303static int sys_uname(struct new_utsname *buf)
304{
305 struct utsname uts_buf;
306
307 if (uname(&uts_buf) < 0)
308 return (-1);
309
310 /*
311 * Just in case these have some differences, we
312 * translate utsname to new_utsname (which is the
313 * struct linux kernel uses).
314 */
315
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200316 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000317 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
318 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
319 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
320 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
321 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
322#ifdef _GNU_SOURCE
323 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
324#endif
325 return (0);
326
327#undef COPY_UTSNAME_FIELD
328}
329
330static int sys_getcwd1(char *buf, size_t size)
331{
332 if (getcwd(buf, size) == NULL) {
333 /* getcwd() sets errno */
334 return (-1);
335 }
aurel32aaf4ad32009-04-16 14:17:14 +0000336 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000337}
338
339#ifdef CONFIG_ATFILE
340/*
341 * Host system seems to have atfile syscall stubs available. We
342 * now enable them one by one as specified by target syscall_nr.h.
343 */
344
345#ifdef TARGET_NR_faccessat
aurel32465c9f02009-04-19 08:52:17 +0000346static int sys_faccessat(int dirfd, const char *pathname, int mode)
aurel323b3f24a2009-04-15 16:12:13 +0000347{
aurel32465c9f02009-04-19 08:52:17 +0000348 return (faccessat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000349}
350#endif
351#ifdef TARGET_NR_fchmodat
aurel32465c9f02009-04-19 08:52:17 +0000352static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000353{
aurel32465c9f02009-04-19 08:52:17 +0000354 return (fchmodat(dirfd, pathname, mode, 0));
aurel323b3f24a2009-04-15 16:12:13 +0000355}
356#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300357#if defined(TARGET_NR_fchownat)
aurel323b3f24a2009-04-15 16:12:13 +0000358static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
359 gid_t group, int flags)
360{
361 return (fchownat(dirfd, pathname, owner, group, flags));
362}
363#endif
364#ifdef __NR_fstatat64
365static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
366 int flags)
367{
368 return (fstatat(dirfd, pathname, buf, flags));
369}
370#endif
371#ifdef __NR_newfstatat
372static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
373 int flags)
374{
375 return (fstatat(dirfd, pathname, buf, flags));
376}
377#endif
378#ifdef TARGET_NR_futimesat
379static int sys_futimesat(int dirfd, const char *pathname,
380 const struct timeval times[2])
381{
382 return (futimesat(dirfd, pathname, times));
383}
384#endif
385#ifdef TARGET_NR_linkat
386static int sys_linkat(int olddirfd, const char *oldpath,
387 int newdirfd, const char *newpath, int flags)
388{
389 return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
390}
391#endif
392#ifdef TARGET_NR_mkdirat
393static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
394{
395 return (mkdirat(dirfd, pathname, mode));
396}
397#endif
398#ifdef TARGET_NR_mknodat
399static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
400 dev_t dev)
401{
402 return (mknodat(dirfd, pathname, mode, dev));
403}
404#endif
405#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200406static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000407{
408 /*
409 * open(2) has extra parameter 'mode' when called with
410 * flag O_CREAT.
411 */
412 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000413 return (openat(dirfd, pathname, flags, mode));
414 }
415 return (openat(dirfd, pathname, flags));
416}
417#endif
418#ifdef TARGET_NR_readlinkat
419static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
420{
421 return (readlinkat(dirfd, pathname, buf, bufsiz));
422}
423#endif
424#ifdef TARGET_NR_renameat
425static int sys_renameat(int olddirfd, const char *oldpath,
426 int newdirfd, const char *newpath)
427{
428 return (renameat(olddirfd, oldpath, newdirfd, newpath));
429}
430#endif
431#ifdef TARGET_NR_symlinkat
432static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
433{
434 return (symlinkat(oldpath, newdirfd, newpath));
435}
436#endif
437#ifdef TARGET_NR_unlinkat
438static int sys_unlinkat(int dirfd, const char *pathname, int flags)
439{
440 return (unlinkat(dirfd, pathname, flags));
441}
442#endif
aurel323b3f24a2009-04-15 16:12:13 +0000443#else /* !CONFIG_ATFILE */
444
445/*
446 * Try direct syscalls instead
447 */
ths92a34c12007-09-24 09:27:49 +0000448#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
aurel32465c9f02009-04-19 08:52:17 +0000449_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
ths92a34c12007-09-24 09:27:49 +0000450#endif
ths814d7972007-09-24 09:26:51 +0000451#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
aurel32465c9f02009-04-19 08:52:17 +0000452_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
ths814d7972007-09-24 09:26:51 +0000453#endif
Riku Voipio0c866a72011-04-18 15:23:06 +0300454#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +0000455_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
456 uid_t,owner,gid_t,group,int,flags)
457#endif
aurel329d33b762009-04-08 23:07:05 +0000458#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
459 defined(__NR_fstatat64)
balrog6a24a772008-09-20 02:23:36 +0000460_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
461 struct stat *,buf,int,flags)
462#endif
balrogac8a6552008-09-20 02:25:39 +0000463#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
464_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
465 const struct timeval *,times)
466#endif
aurel323b3f24a2009-04-15 16:12:13 +0000467#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
468 defined(__NR_newfstatat)
469_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
470 struct stat *,buf,int,flags)
blueswir18fcd3692008-08-17 20:26:25 +0000471#endif
ths64f0ce42007-09-24 09:25:06 +0000472#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
473_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
aurel323b3f24a2009-04-15 16:12:13 +0000474 int,newdirfd,const char *,newpath,int,flags)
ths64f0ce42007-09-24 09:25:06 +0000475#endif
ths4472ad02007-09-24 09:22:32 +0000476#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
477_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
478#endif
ths75ac37a2007-09-24 09:23:05 +0000479#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
480_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
481 mode_t,mode,dev_t,dev)
482#endif
ths82424832007-09-24 09:21:55 +0000483#if defined(TARGET_NR_openat) && defined(__NR_openat)
484_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
485#endif
ths5e0ccb12007-09-24 09:26:10 +0000486#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
487_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
488 char *,buf,size_t,bufsize)
489#endif
ths722183f2007-09-24 09:24:37 +0000490#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
491_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
492 int,newdirfd,const char *,newpath)
493#endif
thsb51eaa82007-09-25 16:09:22 +0000494#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +0000495_syscall3(int,sys_symlinkat,const char *,oldpath,
496 int,newdirfd,const char *,newpath)
497#endif
ths8170f562007-09-24 09:24:11 +0000498#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
499_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
500#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300501
502#endif /* CONFIG_ATFILE */
503
504#ifdef CONFIG_UTIMENSAT
505static int sys_utimensat(int dirfd, const char *pathname,
506 const struct timespec times[2], int flags)
507{
508 if (pathname == NULL)
509 return futimens(dirfd, times);
510 else
511 return utimensat(dirfd, pathname, times, flags);
512}
513#else
ths9007f0e2007-09-25 17:50:37 +0000514#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
515_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
516 const struct timespec *,tsp,int,flags)
517#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300518#endif /* CONFIG_UTIMENSAT */
aurel323b3f24a2009-04-15 16:12:13 +0000519
520#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000521#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000522
aurel3239b59762008-10-01 21:46:50 +0000523#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000524static int sys_inotify_init(void)
525{
526 return (inotify_init());
527}
aurel3239b59762008-10-01 21:46:50 +0000528#endif
529#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000530static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
531{
532 return (inotify_add_watch(fd, pathname, mask));
533}
aurel3239b59762008-10-01 21:46:50 +0000534#endif
535#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000536static int sys_inotify_rm_watch(int fd, int32_t wd)
537{
aurel328690e422009-04-17 13:50:32 +0000538 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000539}
aurel3239b59762008-10-01 21:46:50 +0000540#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000541#ifdef CONFIG_INOTIFY1
542#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
543static int sys_inotify_init1(int flags)
544{
545 return (inotify_init1(flags));
546}
547#endif
548#endif
aurel323b3f24a2009-04-15 16:12:13 +0000549#else
550/* Userspace can usually survive runtime without inotify */
551#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000552#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000553#undef TARGET_NR_inotify_add_watch
554#undef TARGET_NR_inotify_rm_watch
555#endif /* CONFIG_INOTIFY */
556
Mike Frysingerd8035d42011-02-07 01:05:51 -0500557#if defined(TARGET_NR_ppoll)
558#ifndef __NR_ppoll
559# define __NR_ppoll -1
560#endif
561#define __NR_sys_ppoll __NR_ppoll
562_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
563 struct timespec *, timeout, const __sigset_t *, sigmask,
564 size_t, sigsetsize)
565#endif
bellard66fb9762003-03-23 01:06:05 +0000566
Mike Frysinger055e0902011-06-03 17:01:49 -0400567#if defined(TARGET_NR_pselect6)
568#ifndef __NR_pselect6
569# define __NR_pselect6 -1
570#endif
571#define __NR_sys_pselect6 __NR_pselect6
572_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
573 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
574#endif
575
Peter Maydell163a05a2011-06-27 17:44:52 +0100576#if defined(TARGET_NR_prlimit64)
577#ifndef __NR_prlimit64
578# define __NR_prlimit64 -1
579#endif
580#define __NR_sys_prlimit64 __NR_prlimit64
581/* The glibc rlimit structure may not be that used by the underlying syscall */
582struct host_rlimit64 {
583 uint64_t rlim_cur;
584 uint64_t rlim_max;
585};
586_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
587 const struct host_rlimit64 *, new_limit,
588 struct host_rlimit64 *, old_limit)
589#endif
590
Riku Voipio48e515d2011-07-12 15:40:51 +0300591/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000592#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300593static inline int regpairs_aligned(void *cpu_env) {
594 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
595}
596#elif defined(TARGET_MIPS)
597static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000598#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
599/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
600 * of registers which translates to the same as ARM/MIPS, because we start with
601 * r3 as arg1 */
602static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300603#else
604static inline int regpairs_aligned(void *cpu_env) { return 0; }
605#endif
606
thsb92c47c2007-11-01 00:07:38 +0000607#define ERRNO_TABLE_SIZE 1200
608
609/* target_to_host_errno_table[] is initialized from
610 * host_to_target_errno_table[] in syscall_init(). */
611static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
612};
613
ths637947f2007-06-01 12:09:19 +0000614/*
thsfe8f0962007-07-12 10:59:21 +0000615 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000616 * minus the errnos that are not actually generic to all archs.
617 */
thsb92c47c2007-11-01 00:07:38 +0000618static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000619 [EIDRM] = TARGET_EIDRM,
620 [ECHRNG] = TARGET_ECHRNG,
621 [EL2NSYNC] = TARGET_EL2NSYNC,
622 [EL3HLT] = TARGET_EL3HLT,
623 [EL3RST] = TARGET_EL3RST,
624 [ELNRNG] = TARGET_ELNRNG,
625 [EUNATCH] = TARGET_EUNATCH,
626 [ENOCSI] = TARGET_ENOCSI,
627 [EL2HLT] = TARGET_EL2HLT,
628 [EDEADLK] = TARGET_EDEADLK,
629 [ENOLCK] = TARGET_ENOLCK,
630 [EBADE] = TARGET_EBADE,
631 [EBADR] = TARGET_EBADR,
632 [EXFULL] = TARGET_EXFULL,
633 [ENOANO] = TARGET_ENOANO,
634 [EBADRQC] = TARGET_EBADRQC,
635 [EBADSLT] = TARGET_EBADSLT,
636 [EBFONT] = TARGET_EBFONT,
637 [ENOSTR] = TARGET_ENOSTR,
638 [ENODATA] = TARGET_ENODATA,
639 [ETIME] = TARGET_ETIME,
640 [ENOSR] = TARGET_ENOSR,
641 [ENONET] = TARGET_ENONET,
642 [ENOPKG] = TARGET_ENOPKG,
643 [EREMOTE] = TARGET_EREMOTE,
644 [ENOLINK] = TARGET_ENOLINK,
645 [EADV] = TARGET_EADV,
646 [ESRMNT] = TARGET_ESRMNT,
647 [ECOMM] = TARGET_ECOMM,
648 [EPROTO] = TARGET_EPROTO,
649 [EDOTDOT] = TARGET_EDOTDOT,
650 [EMULTIHOP] = TARGET_EMULTIHOP,
651 [EBADMSG] = TARGET_EBADMSG,
652 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
653 [EOVERFLOW] = TARGET_EOVERFLOW,
654 [ENOTUNIQ] = TARGET_ENOTUNIQ,
655 [EBADFD] = TARGET_EBADFD,
656 [EREMCHG] = TARGET_EREMCHG,
657 [ELIBACC] = TARGET_ELIBACC,
658 [ELIBBAD] = TARGET_ELIBBAD,
659 [ELIBSCN] = TARGET_ELIBSCN,
660 [ELIBMAX] = TARGET_ELIBMAX,
661 [ELIBEXEC] = TARGET_ELIBEXEC,
662 [EILSEQ] = TARGET_EILSEQ,
663 [ENOSYS] = TARGET_ENOSYS,
664 [ELOOP] = TARGET_ELOOP,
665 [ERESTART] = TARGET_ERESTART,
666 [ESTRPIPE] = TARGET_ESTRPIPE,
667 [ENOTEMPTY] = TARGET_ENOTEMPTY,
668 [EUSERS] = TARGET_EUSERS,
669 [ENOTSOCK] = TARGET_ENOTSOCK,
670 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
671 [EMSGSIZE] = TARGET_EMSGSIZE,
672 [EPROTOTYPE] = TARGET_EPROTOTYPE,
673 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
674 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
675 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
676 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
677 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
678 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
679 [EADDRINUSE] = TARGET_EADDRINUSE,
680 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
681 [ENETDOWN] = TARGET_ENETDOWN,
682 [ENETUNREACH] = TARGET_ENETUNREACH,
683 [ENETRESET] = TARGET_ENETRESET,
684 [ECONNABORTED] = TARGET_ECONNABORTED,
685 [ECONNRESET] = TARGET_ECONNRESET,
686 [ENOBUFS] = TARGET_ENOBUFS,
687 [EISCONN] = TARGET_EISCONN,
688 [ENOTCONN] = TARGET_ENOTCONN,
689 [EUCLEAN] = TARGET_EUCLEAN,
690 [ENOTNAM] = TARGET_ENOTNAM,
691 [ENAVAIL] = TARGET_ENAVAIL,
692 [EISNAM] = TARGET_EISNAM,
693 [EREMOTEIO] = TARGET_EREMOTEIO,
694 [ESHUTDOWN] = TARGET_ESHUTDOWN,
695 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
696 [ETIMEDOUT] = TARGET_ETIMEDOUT,
697 [ECONNREFUSED] = TARGET_ECONNREFUSED,
698 [EHOSTDOWN] = TARGET_EHOSTDOWN,
699 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
700 [EALREADY] = TARGET_EALREADY,
701 [EINPROGRESS] = TARGET_EINPROGRESS,
702 [ESTALE] = TARGET_ESTALE,
703 [ECANCELED] = TARGET_ECANCELED,
704 [ENOMEDIUM] = TARGET_ENOMEDIUM,
705 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000706#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000707 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000708#endif
709#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000710 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000711#endif
712#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000713 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000714#endif
715#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000716 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000717#endif
718#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000719 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000720#endif
721#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000722 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000723#endif
thsb92c47c2007-11-01 00:07:38 +0000724};
ths637947f2007-06-01 12:09:19 +0000725
726static inline int host_to_target_errno(int err)
727{
728 if(host_to_target_errno_table[err])
729 return host_to_target_errno_table[err];
730 return err;
731}
732
thsb92c47c2007-11-01 00:07:38 +0000733static inline int target_to_host_errno(int err)
734{
735 if (target_to_host_errno_table[err])
736 return target_to_host_errno_table[err];
737 return err;
738}
739
blueswir1992f48a2007-10-14 16:27:31 +0000740static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000741{
742 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000743 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000744 else
745 return ret;
746}
747
blueswir1992f48a2007-10-14 16:27:31 +0000748static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000749{
blueswir1992f48a2007-10-14 16:27:31 +0000750 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000751}
752
thsb92c47c2007-11-01 00:07:38 +0000753char *target_strerror(int err)
754{
Alexander Graf962b2892011-11-21 12:04:07 +0100755 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
756 return NULL;
757 }
thsb92c47c2007-11-01 00:07:38 +0000758 return strerror(target_to_host_errno(err));
759}
760
blueswir1992f48a2007-10-14 16:27:31 +0000761static abi_ulong target_brk;
762static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000763static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000764
blueswir1992f48a2007-10-14 16:27:31 +0000765void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000766{
blueswir14c1de732007-07-07 20:45:44 +0000767 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000768 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000769}
770
vincent4d1de872011-06-14 21:56:33 +0000771//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
772#define DEBUGF_BRK(message, args...)
773
ths0da46a62007-10-20 20:23:07 +0000774/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000775abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000776{
blueswir1992f48a2007-10-14 16:27:31 +0000777 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000778 int new_alloc_size;
779
Paul Brook3a0c6c42012-02-09 19:04:27 +0000780 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000781
vincent4d1de872011-06-14 21:56:33 +0000782 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000783 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000784 return target_brk;
785 }
786 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000787 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
788 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000789 return target_brk;
790 }
bellard31e31b82003-02-18 22:55:36 +0000791
vincent4d1de872011-06-14 21:56:33 +0000792 /* If the new brk is less than the highest page reserved to the
793 * target heap allocation, set it and we're almost done... */
794 if (new_brk <= brk_page) {
795 /* Heap contents are initialized to zero, as for anonymous
796 * mapped pages. */
797 if (new_brk > target_brk) {
798 memset(g2h(target_brk), 0, new_brk - target_brk);
799 }
bellard31e31b82003-02-18 22:55:36 +0000800 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000801 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000802 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000803 }
804
Peter Maydell00faf082011-04-18 16:34:24 +0100805 /* We need to allocate more memory after the brk... Note that
806 * we don't use MAP_FIXED because that will map over the top of
807 * any existing mapping (like the one with the host libc or qemu
808 * itself); instead we treat "mapped but at wrong address" as
809 * a failure and unmap again.
810 */
vincent4d1de872011-06-14 21:56:33 +0000811 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000812 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000813 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100814 MAP_ANON|MAP_PRIVATE, 0, 0));
815
816 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200817 /* Heap contents are initialized to zero, as for anonymous
818 * mapped pages. Technically the new pages are already
819 * initialized to zero since they *are* anonymous mapped
820 * pages, however we have to take care with the contents that
821 * come from the remaining part of the previous page: it may
822 * contains garbage data due to a previous heap usage (grown
823 * then shrunken). */
824 memset(g2h(target_brk), 0, brk_page - target_brk);
825
Peter Maydell00faf082011-04-18 16:34:24 +0100826 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000827 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000828 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
829 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100830 return target_brk;
831 } else if (mapped_addr != -1) {
832 /* Mapped but at wrong address, meaning there wasn't actually
833 * enough space for this brk.
834 */
835 target_munmap(mapped_addr, new_alloc_size);
836 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000837 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000838 }
839 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000840 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100841 }
balrog7ab240a2008-04-26 12:17:34 +0000842
Richard Henderson7dd46c02010-05-03 10:07:49 -0700843#if defined(TARGET_ALPHA)
844 /* We (partially) emulate OSF/1 on Alpha, which requires we
845 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100846 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700847#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100848 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000849 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000850}
851
ths26edcf42007-12-09 02:25:24 +0000852static inline abi_long copy_from_user_fdset(fd_set *fds,
853 abi_ulong target_fds_addr,
854 int n)
bellard31e31b82003-02-18 22:55:36 +0000855{
ths26edcf42007-12-09 02:25:24 +0000856 int i, nw, j, k;
857 abi_ulong b, *target_fds;
858
859 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
860 if (!(target_fds = lock_user(VERIFY_READ,
861 target_fds_addr,
862 sizeof(abi_ulong) * nw,
863 1)))
864 return -TARGET_EFAULT;
865
866 FD_ZERO(fds);
867 k = 0;
868 for (i = 0; i < nw; i++) {
869 /* grab the abi_ulong */
870 __get_user(b, &target_fds[i]);
871 for (j = 0; j < TARGET_ABI_BITS; j++) {
872 /* check the bit inside the abi_ulong */
873 if ((b >> j) & 1)
874 FD_SET(k, fds);
875 k++;
bellard31e31b82003-02-18 22:55:36 +0000876 }
bellard31e31b82003-02-18 22:55:36 +0000877 }
ths26edcf42007-12-09 02:25:24 +0000878
879 unlock_user(target_fds, target_fds_addr, 0);
880
881 return 0;
bellard31e31b82003-02-18 22:55:36 +0000882}
883
Mike Frysinger055e0902011-06-03 17:01:49 -0400884static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
885 abi_ulong target_fds_addr,
886 int n)
887{
888 if (target_fds_addr) {
889 if (copy_from_user_fdset(fds, target_fds_addr, n))
890 return -TARGET_EFAULT;
891 *fds_ptr = fds;
892 } else {
893 *fds_ptr = NULL;
894 }
895 return 0;
896}
897
ths26edcf42007-12-09 02:25:24 +0000898static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
899 const fd_set *fds,
900 int n)
bellard31e31b82003-02-18 22:55:36 +0000901{
bellard31e31b82003-02-18 22:55:36 +0000902 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000903 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000904 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000905
ths26edcf42007-12-09 02:25:24 +0000906 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
907 if (!(target_fds = lock_user(VERIFY_WRITE,
908 target_fds_addr,
909 sizeof(abi_ulong) * nw,
910 0)))
911 return -TARGET_EFAULT;
912
913 k = 0;
914 for (i = 0; i < nw; i++) {
915 v = 0;
916 for (j = 0; j < TARGET_ABI_BITS; j++) {
917 v |= ((FD_ISSET(k, fds) != 0) << j);
918 k++;
bellard31e31b82003-02-18 22:55:36 +0000919 }
ths26edcf42007-12-09 02:25:24 +0000920 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000921 }
ths26edcf42007-12-09 02:25:24 +0000922
923 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
924
925 return 0;
bellard31e31b82003-02-18 22:55:36 +0000926}
927
bellardc596ed12003-07-13 17:32:31 +0000928#if defined(__alpha__)
929#define HOST_HZ 1024
930#else
931#define HOST_HZ 100
932#endif
933
blueswir1992f48a2007-10-14 16:27:31 +0000934static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000935{
936#if HOST_HZ == TARGET_HZ
937 return ticks;
938#else
939 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
940#endif
941}
942
bellard579a97f2007-11-11 14:26:47 +0000943static inline abi_long host_to_target_rusage(abi_ulong target_addr,
944 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000945{
pbrook53a59602006-03-25 19:31:22 +0000946 struct target_rusage *target_rusage;
947
bellard579a97f2007-11-11 14:26:47 +0000948 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
949 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200950 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
951 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
952 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
953 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
954 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
955 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
956 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
957 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
958 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
959 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
960 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
961 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
962 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
963 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
964 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
965 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
966 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
967 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000968 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000969
970 return 0;
bellardb4091862003-05-16 15:39:34 +0000971}
972
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200973static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900974{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200975 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300976 rlim_t result;
977
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200978 target_rlim_swap = tswapal(target_rlim);
979 if (target_rlim_swap == TARGET_RLIM_INFINITY)
980 return RLIM_INFINITY;
981
982 result = target_rlim_swap;
983 if (target_rlim_swap != (rlim_t)result)
984 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300985
986 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900987}
988
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200989static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900990{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200991 abi_ulong target_rlim_swap;
992 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300993
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200994 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300995 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900996 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300997 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200998 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300999
1000 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001001}
1002
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001003static inline int target_to_host_resource(int code)
1004{
1005 switch (code) {
1006 case TARGET_RLIMIT_AS:
1007 return RLIMIT_AS;
1008 case TARGET_RLIMIT_CORE:
1009 return RLIMIT_CORE;
1010 case TARGET_RLIMIT_CPU:
1011 return RLIMIT_CPU;
1012 case TARGET_RLIMIT_DATA:
1013 return RLIMIT_DATA;
1014 case TARGET_RLIMIT_FSIZE:
1015 return RLIMIT_FSIZE;
1016 case TARGET_RLIMIT_LOCKS:
1017 return RLIMIT_LOCKS;
1018 case TARGET_RLIMIT_MEMLOCK:
1019 return RLIMIT_MEMLOCK;
1020 case TARGET_RLIMIT_MSGQUEUE:
1021 return RLIMIT_MSGQUEUE;
1022 case TARGET_RLIMIT_NICE:
1023 return RLIMIT_NICE;
1024 case TARGET_RLIMIT_NOFILE:
1025 return RLIMIT_NOFILE;
1026 case TARGET_RLIMIT_NPROC:
1027 return RLIMIT_NPROC;
1028 case TARGET_RLIMIT_RSS:
1029 return RLIMIT_RSS;
1030 case TARGET_RLIMIT_RTPRIO:
1031 return RLIMIT_RTPRIO;
1032 case TARGET_RLIMIT_SIGPENDING:
1033 return RLIMIT_SIGPENDING;
1034 case TARGET_RLIMIT_STACK:
1035 return RLIMIT_STACK;
1036 default:
1037 return code;
1038 }
1039}
1040
ths788f5ec2007-12-09 02:37:05 +00001041static inline abi_long copy_from_user_timeval(struct timeval *tv,
1042 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001043{
pbrook53a59602006-03-25 19:31:22 +00001044 struct target_timeval *target_tv;
1045
ths788f5ec2007-12-09 02:37:05 +00001046 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001047 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001048
1049 __get_user(tv->tv_sec, &target_tv->tv_sec);
1050 __get_user(tv->tv_usec, &target_tv->tv_usec);
1051
1052 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001053
1054 return 0;
bellard31e31b82003-02-18 22:55:36 +00001055}
1056
ths788f5ec2007-12-09 02:37:05 +00001057static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1058 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001059{
pbrook53a59602006-03-25 19:31:22 +00001060 struct target_timeval *target_tv;
1061
ths788f5ec2007-12-09 02:37:05 +00001062 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001063 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001064
1065 __put_user(tv->tv_sec, &target_tv->tv_sec);
1066 __put_user(tv->tv_usec, &target_tv->tv_usec);
1067
1068 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001069
1070 return 0;
bellard31e31b82003-02-18 22:55:36 +00001071}
1072
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001073#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1074#include <mqueue.h>
1075
aurel3224e10032009-04-15 16:11:43 +00001076static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1077 abi_ulong target_mq_attr_addr)
1078{
1079 struct target_mq_attr *target_mq_attr;
1080
1081 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1082 target_mq_attr_addr, 1))
1083 return -TARGET_EFAULT;
1084
1085 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1086 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1087 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1088 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1089
1090 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1091
1092 return 0;
1093}
1094
1095static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1096 const struct mq_attr *attr)
1097{
1098 struct target_mq_attr *target_mq_attr;
1099
1100 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1101 target_mq_attr_addr, 0))
1102 return -TARGET_EFAULT;
1103
1104 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1105 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1106 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1107 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1108
1109 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1110
1111 return 0;
1112}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001113#endif
bellard31e31b82003-02-18 22:55:36 +00001114
Mike Frysinger055e0902011-06-03 17:01:49 -04001115#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001116/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001117static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001118 abi_ulong rfd_addr, abi_ulong wfd_addr,
1119 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001120{
1121 fd_set rfds, wfds, efds;
1122 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1123 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001124 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001125
Mike Frysinger055e0902011-06-03 17:01:49 -04001126 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1127 if (ret) {
1128 return ret;
pbrook53a59602006-03-25 19:31:22 +00001129 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001130 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1131 if (ret) {
1132 return ret;
pbrook53a59602006-03-25 19:31:22 +00001133 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001134 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1135 if (ret) {
1136 return ret;
pbrook53a59602006-03-25 19:31:22 +00001137 }
ths3b46e622007-09-17 08:09:54 +00001138
ths26edcf42007-12-09 02:25:24 +00001139 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001140 if (copy_from_user_timeval(&tv, target_tv_addr))
1141 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001142 tv_ptr = &tv;
1143 } else {
1144 tv_ptr = NULL;
1145 }
ths26edcf42007-12-09 02:25:24 +00001146
bellard31e31b82003-02-18 22:55:36 +00001147 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001148
ths26edcf42007-12-09 02:25:24 +00001149 if (!is_error(ret)) {
1150 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1151 return -TARGET_EFAULT;
1152 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1153 return -TARGET_EFAULT;
1154 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1155 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001156
ths788f5ec2007-12-09 02:37:05 +00001157 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1158 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001159 }
bellard579a97f2007-11-11 14:26:47 +00001160
bellard31e31b82003-02-18 22:55:36 +00001161 return ret;
1162}
Mike Frysinger055e0902011-06-03 17:01:49 -04001163#endif
bellard31e31b82003-02-18 22:55:36 +00001164
Riku Voipio099d6b02009-05-05 12:10:04 +03001165static abi_long do_pipe2(int host_pipe[], int flags)
1166{
1167#ifdef CONFIG_PIPE2
1168 return pipe2(host_pipe, flags);
1169#else
1170 return -ENOSYS;
1171#endif
1172}
1173
Richard Hendersonfb41a662010-05-03 10:07:52 -07001174static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1175 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001176{
1177 int host_pipe[2];
1178 abi_long ret;
1179 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1180
1181 if (is_error(ret))
1182 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001183
1184 /* Several targets have special calling conventions for the original
1185 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1186 if (!is_pipe2) {
1187#if defined(TARGET_ALPHA)
1188 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1189 return host_pipe[0];
1190#elif defined(TARGET_MIPS)
1191 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1192 return host_pipe[0];
1193#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001194 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001195 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001196#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001197 }
1198
Riku Voipio099d6b02009-05-05 12:10:04 +03001199 if (put_user_s32(host_pipe[0], pipedes)
1200 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1201 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001202 return get_errno(ret);
1203}
1204
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001205static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1206 abi_ulong target_addr,
1207 socklen_t len)
1208{
1209 struct target_ip_mreqn *target_smreqn;
1210
1211 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1212 if (!target_smreqn)
1213 return -TARGET_EFAULT;
1214 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1215 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1216 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001217 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001218 unlock_user(target_smreqn, target_addr, 0);
1219
1220 return 0;
1221}
1222
bellard579a97f2007-11-11 14:26:47 +00001223static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1224 abi_ulong target_addr,
1225 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001226{
aurel32607175e2009-04-15 16:11:59 +00001227 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1228 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001229 struct target_sockaddr *target_saddr;
1230
bellard579a97f2007-11-11 14:26:47 +00001231 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1232 if (!target_saddr)
1233 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001234
1235 sa_family = tswap16(target_saddr->sa_family);
1236
1237 /* Oops. The caller might send a incomplete sun_path; sun_path
1238 * must be terminated by \0 (see the manual page), but
1239 * unfortunately it is quite common to specify sockaddr_un
1240 * length as "strlen(x->sun_path)" while it should be
1241 * "strlen(...) + 1". We'll fix that here if needed.
1242 * Linux kernel has a similar feature.
1243 */
1244
1245 if (sa_family == AF_UNIX) {
1246 if (len < unix_maxlen && len > 0) {
1247 char *cp = (char*)target_saddr;
1248
1249 if ( cp[len-1] && !cp[len] )
1250 len++;
1251 }
1252 if (len > unix_maxlen)
1253 len = unix_maxlen;
1254 }
1255
pbrook53a59602006-03-25 19:31:22 +00001256 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001257 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001258 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001259
1260 return 0;
bellard7854b052003-03-29 17:22:23 +00001261}
1262
bellard579a97f2007-11-11 14:26:47 +00001263static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1264 struct sockaddr *addr,
1265 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001266{
pbrook53a59602006-03-25 19:31:22 +00001267 struct target_sockaddr *target_saddr;
1268
bellard579a97f2007-11-11 14:26:47 +00001269 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1270 if (!target_saddr)
1271 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001272 memcpy(target_saddr, addr, len);
1273 target_saddr->sa_family = tswap16(addr->sa_family);
1274 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001275
1276 return 0;
bellard7854b052003-03-29 17:22:23 +00001277}
1278
bellard5a4a8982007-11-11 17:39:18 +00001279static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1280 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001281{
1282 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001283 abi_long msg_controllen;
1284 abi_ulong target_cmsg_addr;
1285 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001286 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001287
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001288 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001289 if (msg_controllen < sizeof (struct target_cmsghdr))
1290 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001291 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001292 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1293 if (!target_cmsg)
1294 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001295
1296 while (cmsg && target_cmsg) {
1297 void *data = CMSG_DATA(cmsg);
1298 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1299
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001300 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001301 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1302
1303 space += CMSG_SPACE(len);
1304 if (space > msgh->msg_controllen) {
1305 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001306 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001307 break;
1308 }
1309
1310 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1311 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1312 cmsg->cmsg_len = CMSG_LEN(len);
1313
bellard3532fa72006-06-24 15:06:03 +00001314 if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001315 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1316 memcpy(data, target_data, len);
1317 } else {
1318 int *fd = (int *)data;
1319 int *target_fd = (int *)target_data;
1320 int i, numfds = len / sizeof(int);
1321
1322 for (i = 0; i < numfds; i++)
1323 fd[i] = tswap32(target_fd[i]);
1324 }
1325
1326 cmsg = CMSG_NXTHDR(msgh, cmsg);
1327 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1328 }
bellard5a4a8982007-11-11 17:39:18 +00001329 unlock_user(target_cmsg, target_cmsg_addr, 0);
1330 the_end:
bellard7854b052003-03-29 17:22:23 +00001331 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001332 return 0;
bellard7854b052003-03-29 17:22:23 +00001333}
1334
bellard5a4a8982007-11-11 17:39:18 +00001335static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1336 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001337{
1338 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001339 abi_long msg_controllen;
1340 abi_ulong target_cmsg_addr;
1341 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001342 socklen_t space = 0;
1343
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001344 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001345 if (msg_controllen < sizeof (struct target_cmsghdr))
1346 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001347 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001348 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1349 if (!target_cmsg)
1350 return -TARGET_EFAULT;
1351
bellard7854b052003-03-29 17:22:23 +00001352 while (cmsg && target_cmsg) {
1353 void *data = CMSG_DATA(cmsg);
1354 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1355
1356 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1357
1358 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001359 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001360 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001361 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001362 break;
1363 }
1364
1365 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1366 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001367 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001368
Jing Huangaebf5bc2012-07-24 14:01:42 +00001369 if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1370 (cmsg->cmsg_type == SCM_RIGHTS)) {
bellard7854b052003-03-29 17:22:23 +00001371 int *fd = (int *)data;
1372 int *target_fd = (int *)target_data;
1373 int i, numfds = len / sizeof(int);
1374
1375 for (i = 0; i < numfds; i++)
1376 target_fd[i] = tswap32(fd[i]);
Jing Huangaebf5bc2012-07-24 14:01:42 +00001377 } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
1378 (cmsg->cmsg_type == SO_TIMESTAMP) &&
1379 (len == sizeof(struct timeval))) {
1380 /* copy struct timeval to target */
1381 struct timeval *tv = (struct timeval *)data;
1382 struct target_timeval *target_tv =
1383 (struct target_timeval *)target_data;
1384
1385 target_tv->tv_sec = tswapal(tv->tv_sec);
1386 target_tv->tv_usec = tswapal(tv->tv_usec);
1387 } else {
1388 gemu_log("Unsupported ancillary data: %d/%d\n",
1389 cmsg->cmsg_level, cmsg->cmsg_type);
1390 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001391 }
1392
1393 cmsg = CMSG_NXTHDR(msgh, cmsg);
1394 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1395 }
bellard5a4a8982007-11-11 17:39:18 +00001396 unlock_user(target_cmsg, target_cmsg_addr, space);
1397 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001398 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001399 return 0;
bellard7854b052003-03-29 17:22:23 +00001400}
1401
ths0da46a62007-10-20 20:23:07 +00001402/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001403static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001404 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001405{
blueswir1992f48a2007-10-14 16:27:31 +00001406 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001407 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001408 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001409 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001410
bellard8853f862004-02-22 14:57:26 +00001411 switch(level) {
1412 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001413 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001414 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001415 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001416
bellard2f619692007-11-16 10:46:05 +00001417 if (get_user_u32(val, optval_addr))
1418 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001419 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1420 break;
1421 case SOL_IP:
1422 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001423 case IP_TOS:
1424 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001425 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001426 case IP_ROUTER_ALERT:
1427 case IP_RECVOPTS:
1428 case IP_RETOPTS:
1429 case IP_PKTINFO:
1430 case IP_MTU_DISCOVER:
1431 case IP_RECVERR:
1432 case IP_RECVTOS:
1433#ifdef IP_FREEBIND
1434 case IP_FREEBIND:
1435#endif
1436 case IP_MULTICAST_TTL:
1437 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001438 val = 0;
1439 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001440 if (get_user_u32(val, optval_addr))
1441 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001442 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001443 if (get_user_u8(val, optval_addr))
1444 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001445 }
1446 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1447 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001448 case IP_ADD_MEMBERSHIP:
1449 case IP_DROP_MEMBERSHIP:
1450 if (optlen < sizeof (struct target_ip_mreq) ||
1451 optlen > sizeof (struct target_ip_mreqn))
1452 return -TARGET_EINVAL;
1453
1454 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1455 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1456 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1457 break;
1458
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001459 case IP_BLOCK_SOURCE:
1460 case IP_UNBLOCK_SOURCE:
1461 case IP_ADD_SOURCE_MEMBERSHIP:
1462 case IP_DROP_SOURCE_MEMBERSHIP:
1463 if (optlen != sizeof (struct target_ip_mreq_source))
1464 return -TARGET_EINVAL;
1465
1466 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1467 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1468 unlock_user (ip_mreq_source, optval_addr, 0);
1469 break;
1470
bellard8853f862004-02-22 14:57:26 +00001471 default:
1472 goto unimplemented;
1473 }
1474 break;
Jing Huang920394d2012-07-24 13:59:23 +00001475 case SOL_RAW:
1476 switch (optname) {
1477 case ICMP_FILTER:
1478 /* struct icmp_filter takes an u32 value */
1479 if (optlen < sizeof(uint32_t)) {
1480 return -TARGET_EINVAL;
1481 }
1482
1483 if (get_user_u32(val, optval_addr)) {
1484 return -TARGET_EFAULT;
1485 }
1486 ret = get_errno(setsockopt(sockfd, level, optname,
1487 &val, sizeof(val)));
1488 break;
1489
1490 default:
1491 goto unimplemented;
1492 }
1493 break;
bellard3532fa72006-06-24 15:06:03 +00001494 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001495 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001496 case TARGET_SO_RCVTIMEO:
1497 {
1498 struct timeval tv;
1499
1500 optname = SO_RCVTIMEO;
1501
1502set_timeout:
1503 if (optlen != sizeof(struct target_timeval)) {
1504 return -TARGET_EINVAL;
1505 }
1506
1507 if (copy_from_user_timeval(&tv, optval_addr)) {
1508 return -TARGET_EFAULT;
1509 }
1510
1511 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1512 &tv, sizeof(tv)));
1513 return ret;
1514 }
1515 case TARGET_SO_SNDTIMEO:
1516 optname = SO_SNDTIMEO;
1517 goto set_timeout;
bellard8853f862004-02-22 14:57:26 +00001518 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001519 case TARGET_SO_DEBUG:
1520 optname = SO_DEBUG;
1521 break;
1522 case TARGET_SO_REUSEADDR:
1523 optname = SO_REUSEADDR;
1524 break;
1525 case TARGET_SO_TYPE:
1526 optname = SO_TYPE;
1527 break;
1528 case TARGET_SO_ERROR:
1529 optname = SO_ERROR;
1530 break;
1531 case TARGET_SO_DONTROUTE:
1532 optname = SO_DONTROUTE;
1533 break;
1534 case TARGET_SO_BROADCAST:
1535 optname = SO_BROADCAST;
1536 break;
1537 case TARGET_SO_SNDBUF:
1538 optname = SO_SNDBUF;
1539 break;
1540 case TARGET_SO_RCVBUF:
1541 optname = SO_RCVBUF;
1542 break;
1543 case TARGET_SO_KEEPALIVE:
1544 optname = SO_KEEPALIVE;
1545 break;
1546 case TARGET_SO_OOBINLINE:
1547 optname = SO_OOBINLINE;
1548 break;
1549 case TARGET_SO_NO_CHECK:
1550 optname = SO_NO_CHECK;
1551 break;
1552 case TARGET_SO_PRIORITY:
1553 optname = SO_PRIORITY;
1554 break;
bellard5e83e8e2005-03-01 22:32:06 +00001555#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001556 case TARGET_SO_BSDCOMPAT:
1557 optname = SO_BSDCOMPAT;
1558 break;
bellard5e83e8e2005-03-01 22:32:06 +00001559#endif
bellard3532fa72006-06-24 15:06:03 +00001560 case TARGET_SO_PASSCRED:
1561 optname = SO_PASSCRED;
1562 break;
1563 case TARGET_SO_TIMESTAMP:
1564 optname = SO_TIMESTAMP;
1565 break;
1566 case TARGET_SO_RCVLOWAT:
1567 optname = SO_RCVLOWAT;
1568 break;
bellard8853f862004-02-22 14:57:26 +00001569 break;
1570 default:
1571 goto unimplemented;
1572 }
bellard3532fa72006-06-24 15:06:03 +00001573 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001574 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001575
bellard2f619692007-11-16 10:46:05 +00001576 if (get_user_u32(val, optval_addr))
1577 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001578 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001579 break;
bellard7854b052003-03-29 17:22:23 +00001580 default:
bellard8853f862004-02-22 14:57:26 +00001581 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001582 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001583 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001584 }
bellard8853f862004-02-22 14:57:26 +00001585 return ret;
bellard7854b052003-03-29 17:22:23 +00001586}
1587
ths0da46a62007-10-20 20:23:07 +00001588/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001589static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001590 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001591{
blueswir1992f48a2007-10-14 16:27:31 +00001592 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001593 int len, val;
1594 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001595
1596 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001597 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001598 level = SOL_SOCKET;
1599 switch (optname) {
1600 /* These don't just return a single integer */
1601 case TARGET_SO_LINGER:
1602 case TARGET_SO_RCVTIMEO:
1603 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001604 case TARGET_SO_PEERNAME:
1605 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001606 case TARGET_SO_PEERCRED: {
1607 struct ucred cr;
1608 socklen_t crlen;
1609 struct target_ucred *tcr;
1610
1611 if (get_user_u32(len, optlen)) {
1612 return -TARGET_EFAULT;
1613 }
1614 if (len < 0) {
1615 return -TARGET_EINVAL;
1616 }
1617
1618 crlen = sizeof(cr);
1619 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1620 &cr, &crlen));
1621 if (ret < 0) {
1622 return ret;
1623 }
1624 if (len > crlen) {
1625 len = crlen;
1626 }
1627 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1628 return -TARGET_EFAULT;
1629 }
1630 __put_user(cr.pid, &tcr->pid);
1631 __put_user(cr.uid, &tcr->uid);
1632 __put_user(cr.gid, &tcr->gid);
1633 unlock_user_struct(tcr, optval_addr, 1);
1634 if (put_user_u32(len, optlen)) {
1635 return -TARGET_EFAULT;
1636 }
1637 break;
1638 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001639 /* Options with 'int' argument. */
1640 case TARGET_SO_DEBUG:
1641 optname = SO_DEBUG;
1642 goto int_case;
1643 case TARGET_SO_REUSEADDR:
1644 optname = SO_REUSEADDR;
1645 goto int_case;
1646 case TARGET_SO_TYPE:
1647 optname = SO_TYPE;
1648 goto int_case;
1649 case TARGET_SO_ERROR:
1650 optname = SO_ERROR;
1651 goto int_case;
1652 case TARGET_SO_DONTROUTE:
1653 optname = SO_DONTROUTE;
1654 goto int_case;
1655 case TARGET_SO_BROADCAST:
1656 optname = SO_BROADCAST;
1657 goto int_case;
1658 case TARGET_SO_SNDBUF:
1659 optname = SO_SNDBUF;
1660 goto int_case;
1661 case TARGET_SO_RCVBUF:
1662 optname = SO_RCVBUF;
1663 goto int_case;
1664 case TARGET_SO_KEEPALIVE:
1665 optname = SO_KEEPALIVE;
1666 goto int_case;
1667 case TARGET_SO_OOBINLINE:
1668 optname = SO_OOBINLINE;
1669 goto int_case;
1670 case TARGET_SO_NO_CHECK:
1671 optname = SO_NO_CHECK;
1672 goto int_case;
1673 case TARGET_SO_PRIORITY:
1674 optname = SO_PRIORITY;
1675 goto int_case;
1676#ifdef SO_BSDCOMPAT
1677 case TARGET_SO_BSDCOMPAT:
1678 optname = SO_BSDCOMPAT;
1679 goto int_case;
1680#endif
1681 case TARGET_SO_PASSCRED:
1682 optname = SO_PASSCRED;
1683 goto int_case;
1684 case TARGET_SO_TIMESTAMP:
1685 optname = SO_TIMESTAMP;
1686 goto int_case;
1687 case TARGET_SO_RCVLOWAT:
1688 optname = SO_RCVLOWAT;
1689 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001690 default:
bellard2efbe912005-07-23 15:10:20 +00001691 goto int_case;
1692 }
1693 break;
1694 case SOL_TCP:
1695 /* TCP options all take an 'int' value. */
1696 int_case:
bellard2f619692007-11-16 10:46:05 +00001697 if (get_user_u32(len, optlen))
1698 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001699 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001700 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001701 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001702 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1703 if (ret < 0)
1704 return ret;
bellard2efbe912005-07-23 15:10:20 +00001705 if (len > lv)
1706 len = lv;
bellard2f619692007-11-16 10:46:05 +00001707 if (len == 4) {
1708 if (put_user_u32(val, optval_addr))
1709 return -TARGET_EFAULT;
1710 } else {
1711 if (put_user_u8(val, optval_addr))
1712 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001713 }
bellard2f619692007-11-16 10:46:05 +00001714 if (put_user_u32(len, optlen))
1715 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001716 break;
1717 case SOL_IP:
1718 switch(optname) {
1719 case IP_TOS:
1720 case IP_TTL:
1721 case IP_HDRINCL:
1722 case IP_ROUTER_ALERT:
1723 case IP_RECVOPTS:
1724 case IP_RETOPTS:
1725 case IP_PKTINFO:
1726 case IP_MTU_DISCOVER:
1727 case IP_RECVERR:
1728 case IP_RECVTOS:
1729#ifdef IP_FREEBIND
1730 case IP_FREEBIND:
1731#endif
1732 case IP_MULTICAST_TTL:
1733 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001734 if (get_user_u32(len, optlen))
1735 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001736 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001737 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001738 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001739 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1740 if (ret < 0)
1741 return ret;
bellard2efbe912005-07-23 15:10:20 +00001742 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001743 len = 1;
bellard2f619692007-11-16 10:46:05 +00001744 if (put_user_u32(len, optlen)
1745 || put_user_u8(val, optval_addr))
1746 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001747 } else {
bellard2efbe912005-07-23 15:10:20 +00001748 if (len > sizeof(int))
1749 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001750 if (put_user_u32(len, optlen)
1751 || put_user_u32(val, optval_addr))
1752 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001753 }
bellard8853f862004-02-22 14:57:26 +00001754 break;
bellard2efbe912005-07-23 15:10:20 +00001755 default:
thsc02f4992007-12-18 02:39:59 +00001756 ret = -TARGET_ENOPROTOOPT;
1757 break;
bellard8853f862004-02-22 14:57:26 +00001758 }
1759 break;
1760 default:
1761 unimplemented:
1762 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1763 level, optname);
thsc02f4992007-12-18 02:39:59 +00001764 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001765 break;
1766 }
1767 return ret;
bellard7854b052003-03-29 17:22:23 +00001768}
1769
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001770static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1771 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001772{
1773 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001774 struct iovec *vec;
1775 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001776 int i;
pbrook53a59602006-03-25 19:31:22 +00001777
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001778 if (count == 0) {
1779 errno = 0;
1780 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001781 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001782 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001783 errno = EINVAL;
1784 return NULL;
1785 }
1786
1787 vec = calloc(count, sizeof(struct iovec));
1788 if (vec == NULL) {
1789 errno = ENOMEM;
1790 return NULL;
1791 }
1792
1793 target_vec = lock_user(VERIFY_READ, target_addr,
1794 count * sizeof(struct target_iovec), 1);
1795 if (target_vec == NULL) {
1796 errno = EFAULT;
1797 goto fail2;
1798 }
1799
1800 /* ??? If host page size > target page size, this will result in a
1801 value larger than what we can actually support. */
1802 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1803 total_len = 0;
1804
1805 for (i = 0; i < count; i++) {
1806 abi_ulong base = tswapal(target_vec[i].iov_base);
1807 abi_long len = tswapal(target_vec[i].iov_len);
1808
1809 if (len < 0) {
1810 errno = EINVAL;
1811 goto fail;
1812 } else if (len == 0) {
1813 /* Zero length pointer is ignored. */
1814 vec[i].iov_base = 0;
1815 } else {
1816 vec[i].iov_base = lock_user(type, base, len, copy);
1817 if (!vec[i].iov_base) {
1818 errno = EFAULT;
1819 goto fail;
1820 }
1821 if (len > max_len - total_len) {
1822 len = max_len - total_len;
1823 }
1824 }
1825 vec[i].iov_len = len;
1826 total_len += len;
1827 }
1828
1829 unlock_user(target_vec, target_addr, 0);
1830 return vec;
1831
1832 fail:
1833 free(vec);
1834 fail2:
1835 unlock_user(target_vec, target_addr, 0);
1836 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001837}
1838
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001839static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1840 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001841{
1842 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001843 int i;
1844
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001845 target_vec = lock_user(VERIFY_READ, target_addr,
1846 count * sizeof(struct target_iovec), 1);
1847 if (target_vec) {
1848 for (i = 0; i < count; i++) {
1849 abi_ulong base = tswapal(target_vec[i].iov_base);
1850 abi_long len = tswapal(target_vec[i].iov_base);
1851 if (len < 0) {
1852 break;
1853 }
balrogd732dcb2008-10-28 10:21:03 +00001854 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1855 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001856 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001857 }
bellard579a97f2007-11-11 14:26:47 +00001858
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001859 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001860}
1861
ths0da46a62007-10-20 20:23:07 +00001862/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001863static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001864{
1865#if defined(TARGET_MIPS)
1866 switch(type) {
1867 case TARGET_SOCK_DGRAM:
1868 type = SOCK_DGRAM;
1869 break;
1870 case TARGET_SOCK_STREAM:
1871 type = SOCK_STREAM;
1872 break;
1873 case TARGET_SOCK_RAW:
1874 type = SOCK_RAW;
1875 break;
1876 case TARGET_SOCK_RDM:
1877 type = SOCK_RDM;
1878 break;
1879 case TARGET_SOCK_SEQPACKET:
1880 type = SOCK_SEQPACKET;
1881 break;
1882 case TARGET_SOCK_PACKET:
1883 type = SOCK_PACKET;
1884 break;
1885 }
1886#endif
balrog12bc92a2007-10-30 21:06:14 +00001887 if (domain == PF_NETLINK)
1888 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
bellard3532fa72006-06-24 15:06:03 +00001889 return get_errno(socket(domain, type, protocol));
1890}
1891
ths0da46a62007-10-20 20:23:07 +00001892/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001893static abi_long do_bind(int sockfd, abi_ulong target_addr,
1894 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001895{
aurel328f7aeaf2009-01-30 19:47:57 +00001896 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001897 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001898
Blue Swirl38724252010-09-18 05:53:14 +00001899 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001900 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001901 }
aurel328f7aeaf2009-01-30 19:47:57 +00001902
aurel32607175e2009-04-15 16:11:59 +00001903 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001904
Arnaud Patard917507b2009-06-19 10:44:45 +03001905 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1906 if (ret)
1907 return ret;
1908
bellard3532fa72006-06-24 15:06:03 +00001909 return get_errno(bind(sockfd, addr, addrlen));
1910}
1911
ths0da46a62007-10-20 20:23:07 +00001912/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001913static abi_long do_connect(int sockfd, abi_ulong target_addr,
1914 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001915{
aurel328f7aeaf2009-01-30 19:47:57 +00001916 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001917 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001918
Blue Swirl38724252010-09-18 05:53:14 +00001919 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001920 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001921 }
aurel328f7aeaf2009-01-30 19:47:57 +00001922
1923 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001924
Arnaud Patard917507b2009-06-19 10:44:45 +03001925 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1926 if (ret)
1927 return ret;
1928
bellard3532fa72006-06-24 15:06:03 +00001929 return get_errno(connect(sockfd, addr, addrlen));
1930}
1931
ths0da46a62007-10-20 20:23:07 +00001932/* do_sendrecvmsg() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001933static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1934 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001935{
balrog6de645c2008-10-28 10:26:29 +00001936 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001937 struct target_msghdr *msgp;
1938 struct msghdr msg;
1939 int count;
1940 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001941 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001942
bellard579a97f2007-11-11 14:26:47 +00001943 /* FIXME */
1944 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1945 msgp,
1946 target_msg,
1947 send ? 1 : 0))
1948 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001949 if (msgp->msg_name) {
1950 msg.msg_namelen = tswap32(msgp->msg_namelen);
1951 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001952 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001953 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001954 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001955 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001956 }
bellard3532fa72006-06-24 15:06:03 +00001957 } else {
1958 msg.msg_name = NULL;
1959 msg.msg_namelen = 0;
1960 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001961 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001962 msg.msg_control = alloca(msg.msg_controllen);
1963 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001964
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001965 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001966 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001967 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1968 target_vec, count, send);
1969 if (vec == NULL) {
1970 ret = -host_to_target_errno(errno);
1971 goto out2;
1972 }
bellard3532fa72006-06-24 15:06:03 +00001973 msg.msg_iovlen = count;
1974 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001975
bellard3532fa72006-06-24 15:06:03 +00001976 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001977 ret = target_to_host_cmsg(&msg, msgp);
1978 if (ret == 0)
1979 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001980 } else {
1981 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001982 if (!is_error(ret)) {
1983 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001984 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001985 if (!is_error(ret)) {
1986 msgp->msg_namelen = tswap32(msg.msg_namelen);
1987 if (msg.msg_name != NULL) {
1988 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1989 msg.msg_name, msg.msg_namelen);
1990 if (ret) {
1991 goto out;
1992 }
1993 }
1994
balrog6de645c2008-10-28 10:26:29 +00001995 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001996 }
balrog6de645c2008-10-28 10:26:29 +00001997 }
bellard3532fa72006-06-24 15:06:03 +00001998 }
Jing Huangca619062012-07-24 13:58:02 +00001999
2000out:
bellard3532fa72006-06-24 15:06:03 +00002001 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002002out2:
bellard579a97f2007-11-11 14:26:47 +00002003 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002004 return ret;
2005}
2006
Peter Maydella94b4982013-02-08 04:35:04 +00002007/* If we don't have a system accept4() then just call accept.
2008 * The callsites to do_accept4() will ensure that they don't
2009 * pass a non-zero flags argument in this config.
2010 */
2011#ifndef CONFIG_ACCEPT4
2012static inline int accept4(int sockfd, struct sockaddr *addr,
2013 socklen_t *addrlen, int flags)
2014{
2015 assert(flags == 0);
2016 return accept(sockfd, addr, addrlen);
2017}
2018#endif
2019
2020/* do_accept4() Must return target values and target errnos. */
2021static abi_long do_accept4(int fd, abi_ulong target_addr,
2022 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002023{
bellard2f619692007-11-16 10:46:05 +00002024 socklen_t addrlen;
2025 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002026 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002027
Peter Maydella94b4982013-02-08 04:35:04 +00002028 if (target_addr == 0) {
2029 return get_errno(accept4(fd, NULL, NULL, flags));
2030 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002031
2032 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002033 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002034 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002035
Blue Swirl38724252010-09-18 05:53:14 +00002036 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002037 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002038 }
aurel328f7aeaf2009-01-30 19:47:57 +00002039
Arnaud Patard917507b2009-06-19 10:44:45 +03002040 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2041 return -TARGET_EINVAL;
2042
bellard2f619692007-11-16 10:46:05 +00002043 addr = alloca(addrlen);
2044
Peter Maydella94b4982013-02-08 04:35:04 +00002045 ret = get_errno(accept4(fd, addr, &addrlen, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002046 if (!is_error(ret)) {
2047 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002048 if (put_user_u32(addrlen, target_addrlen_addr))
2049 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002050 }
2051 return ret;
2052}
2053
ths0da46a62007-10-20 20:23:07 +00002054/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002055static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002056 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002057{
bellard2f619692007-11-16 10:46:05 +00002058 socklen_t addrlen;
2059 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002060 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002061
bellard2f619692007-11-16 10:46:05 +00002062 if (get_user_u32(addrlen, target_addrlen_addr))
2063 return -TARGET_EFAULT;
2064
Blue Swirl38724252010-09-18 05:53:14 +00002065 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002066 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002067 }
aurel328f7aeaf2009-01-30 19:47:57 +00002068
Arnaud Patard917507b2009-06-19 10:44:45 +03002069 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2070 return -TARGET_EFAULT;
2071
bellard2f619692007-11-16 10:46:05 +00002072 addr = alloca(addrlen);
2073
pbrook1be9e1d2006-11-19 15:26:04 +00002074 ret = get_errno(getpeername(fd, addr, &addrlen));
2075 if (!is_error(ret)) {
2076 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002077 if (put_user_u32(addrlen, target_addrlen_addr))
2078 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002079 }
2080 return ret;
2081}
2082
ths0da46a62007-10-20 20:23:07 +00002083/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002084static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002085 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002086{
bellard2f619692007-11-16 10:46:05 +00002087 socklen_t addrlen;
2088 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002089 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002090
bellard2f619692007-11-16 10:46:05 +00002091 if (get_user_u32(addrlen, target_addrlen_addr))
2092 return -TARGET_EFAULT;
2093
Blue Swirl38724252010-09-18 05:53:14 +00002094 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002095 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002096 }
aurel328f7aeaf2009-01-30 19:47:57 +00002097
Arnaud Patard917507b2009-06-19 10:44:45 +03002098 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2099 return -TARGET_EFAULT;
2100
bellard2f619692007-11-16 10:46:05 +00002101 addr = alloca(addrlen);
2102
pbrook1be9e1d2006-11-19 15:26:04 +00002103 ret = get_errno(getsockname(fd, addr, &addrlen));
2104 if (!is_error(ret)) {
2105 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002106 if (put_user_u32(addrlen, target_addrlen_addr))
2107 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002108 }
2109 return ret;
2110}
2111
ths0da46a62007-10-20 20:23:07 +00002112/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002113static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002114 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002115{
2116 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002117 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002118
2119 ret = get_errno(socketpair(domain, type, protocol, tab));
2120 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002121 if (put_user_s32(tab[0], target_tab_addr)
2122 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2123 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002124 }
2125 return ret;
2126}
2127
ths0da46a62007-10-20 20:23:07 +00002128/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002129static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2130 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002131{
2132 void *addr;
2133 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002134 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002135
Blue Swirl38724252010-09-18 05:53:14 +00002136 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002137 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002138 }
aurel328f7aeaf2009-01-30 19:47:57 +00002139
bellard579a97f2007-11-11 14:26:47 +00002140 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2141 if (!host_msg)
2142 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002143 if (target_addr) {
2144 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002145 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2146 if (ret) {
2147 unlock_user(host_msg, msg, 0);
2148 return ret;
2149 }
pbrook1be9e1d2006-11-19 15:26:04 +00002150 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2151 } else {
2152 ret = get_errno(send(fd, host_msg, len, flags));
2153 }
2154 unlock_user(host_msg, msg, 0);
2155 return ret;
2156}
2157
ths0da46a62007-10-20 20:23:07 +00002158/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002159static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2160 abi_ulong target_addr,
2161 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002162{
2163 socklen_t addrlen;
2164 void *addr;
2165 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002166 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002167
bellard579a97f2007-11-11 14:26:47 +00002168 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2169 if (!host_msg)
2170 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002171 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002172 if (get_user_u32(addrlen, target_addrlen)) {
2173 ret = -TARGET_EFAULT;
2174 goto fail;
2175 }
Blue Swirl38724252010-09-18 05:53:14 +00002176 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002177 ret = -TARGET_EINVAL;
2178 goto fail;
2179 }
pbrook1be9e1d2006-11-19 15:26:04 +00002180 addr = alloca(addrlen);
2181 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2182 } else {
2183 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002184 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002185 }
2186 if (!is_error(ret)) {
2187 if (target_addr) {
2188 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002189 if (put_user_u32(addrlen, target_addrlen)) {
2190 ret = -TARGET_EFAULT;
2191 goto fail;
2192 }
pbrook1be9e1d2006-11-19 15:26:04 +00002193 }
2194 unlock_user(host_msg, msg, len);
2195 } else {
bellard2f619692007-11-16 10:46:05 +00002196fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002197 unlock_user(host_msg, msg, 0);
2198 }
2199 return ret;
2200}
2201
j_mayer32407102007-09-26 23:01:49 +00002202#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002203/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002204static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002205{
blueswir1992f48a2007-10-14 16:27:31 +00002206 abi_long ret;
2207 const int n = sizeof(abi_ulong);
bellard31e31b82003-02-18 22:55:36 +00002208
2209 switch(num) {
2210 case SOCKOP_socket:
bellard7854b052003-03-29 17:22:23 +00002211 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002212 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002213
Ulrich Hecht98818182009-07-03 17:09:28 +02002214 if (get_user_ual(domain, vptr)
2215 || get_user_ual(type, vptr + n)
2216 || get_user_ual(protocol, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002217 return -TARGET_EFAULT;
2218
bellard3532fa72006-06-24 15:06:03 +00002219 ret = do_socket(domain, type, protocol);
bellard7854b052003-03-29 17:22:23 +00002220 }
bellard31e31b82003-02-18 22:55:36 +00002221 break;
2222 case SOCKOP_bind:
bellard7854b052003-03-29 17:22:23 +00002223 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002224 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002225 abi_ulong target_addr;
2226 socklen_t addrlen;
2227
Ulrich Hecht98818182009-07-03 17:09:28 +02002228 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002229 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002230 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002231 return -TARGET_EFAULT;
2232
bellard3532fa72006-06-24 15:06:03 +00002233 ret = do_bind(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002234 }
bellard31e31b82003-02-18 22:55:36 +00002235 break;
2236 case SOCKOP_connect:
bellard7854b052003-03-29 17:22:23 +00002237 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002238 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002239 abi_ulong target_addr;
2240 socklen_t addrlen;
2241
Ulrich Hecht98818182009-07-03 17:09:28 +02002242 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002243 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002244 || get_user_ual(addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002245 return -TARGET_EFAULT;
2246
bellard3532fa72006-06-24 15:06:03 +00002247 ret = do_connect(sockfd, target_addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002248 }
bellard31e31b82003-02-18 22:55:36 +00002249 break;
2250 case SOCKOP_listen:
bellard7854b052003-03-29 17:22:23 +00002251 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002252 abi_ulong sockfd, backlog;
bellard2f619692007-11-16 10:46:05 +00002253
Ulrich Hecht98818182009-07-03 17:09:28 +02002254 if (get_user_ual(sockfd, vptr)
2255 || get_user_ual(backlog, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002256 return -TARGET_EFAULT;
2257
bellard7854b052003-03-29 17:22:23 +00002258 ret = get_errno(listen(sockfd, backlog));
2259 }
bellard31e31b82003-02-18 22:55:36 +00002260 break;
2261 case SOCKOP_accept:
2262 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002263 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002264 abi_ulong target_addr, target_addrlen;
2265
Ulrich Hecht98818182009-07-03 17:09:28 +02002266 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002267 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002268 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002269 return -TARGET_EFAULT;
2270
Peter Maydella94b4982013-02-08 04:35:04 +00002271 ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
bellard31e31b82003-02-18 22:55:36 +00002272 }
2273 break;
2274 case SOCKOP_getsockname:
2275 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002276 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002277 abi_ulong target_addr, target_addrlen;
2278
Ulrich Hecht98818182009-07-03 17:09:28 +02002279 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002280 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002281 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002282 return -TARGET_EFAULT;
2283
pbrook1be9e1d2006-11-19 15:26:04 +00002284 ret = do_getsockname(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002285 }
2286 break;
2287 case SOCKOP_getpeername:
2288 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002289 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002290 abi_ulong target_addr, target_addrlen;
2291
Ulrich Hecht98818182009-07-03 17:09:28 +02002292 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002293 || get_user_ual(target_addr, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002294 || get_user_ual(target_addrlen, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002295 return -TARGET_EFAULT;
2296
pbrook1be9e1d2006-11-19 15:26:04 +00002297 ret = do_getpeername(sockfd, target_addr, target_addrlen);
bellard31e31b82003-02-18 22:55:36 +00002298 }
2299 break;
2300 case SOCKOP_socketpair:
2301 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002302 abi_ulong domain, type, protocol;
bellard2f619692007-11-16 10:46:05 +00002303 abi_ulong tab;
2304
Ulrich Hecht98818182009-07-03 17:09:28 +02002305 if (get_user_ual(domain, vptr)
2306 || get_user_ual(type, vptr + n)
2307 || get_user_ual(protocol, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002308 || get_user_ual(tab, vptr + 3 * n))
2309 return -TARGET_EFAULT;
2310
pbrook1be9e1d2006-11-19 15:26:04 +00002311 ret = do_socketpair(domain, type, protocol, tab);
bellard31e31b82003-02-18 22:55:36 +00002312 }
2313 break;
2314 case SOCKOP_send:
bellard7854b052003-03-29 17:22:23 +00002315 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002316 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002317 abi_ulong msg;
2318 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002319 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002320
Ulrich Hecht98818182009-07-03 17:09:28 +02002321 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002322 || get_user_ual(msg, vptr + n)
2323 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002324 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002325 return -TARGET_EFAULT;
2326
pbrook1be9e1d2006-11-19 15:26:04 +00002327 ret = do_sendto(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002328 }
bellard31e31b82003-02-18 22:55:36 +00002329 break;
2330 case SOCKOP_recv:
bellard7854b052003-03-29 17:22:23 +00002331 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002332 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002333 abi_ulong msg;
2334 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002335 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002336
Ulrich Hecht98818182009-07-03 17:09:28 +02002337 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002338 || get_user_ual(msg, vptr + n)
2339 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002340 || get_user_ual(flags, vptr + 3 * n))
bellard2f619692007-11-16 10:46:05 +00002341 return -TARGET_EFAULT;
2342
pbrook1be9e1d2006-11-19 15:26:04 +00002343 ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
bellard7854b052003-03-29 17:22:23 +00002344 }
bellard31e31b82003-02-18 22:55:36 +00002345 break;
2346 case SOCKOP_sendto:
bellard7854b052003-03-29 17:22:23 +00002347 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002348 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002349 abi_ulong msg;
2350 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002351 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002352 abi_ulong addr;
2353 socklen_t addrlen;
2354
Ulrich Hecht98818182009-07-03 17:09:28 +02002355 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002356 || get_user_ual(msg, vptr + n)
2357 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002358 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002359 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002360 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002361 return -TARGET_EFAULT;
2362
pbrook1be9e1d2006-11-19 15:26:04 +00002363 ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
bellard7854b052003-03-29 17:22:23 +00002364 }
bellard31e31b82003-02-18 22:55:36 +00002365 break;
2366 case SOCKOP_recvfrom:
2367 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002368 abi_ulong sockfd;
bellard2f619692007-11-16 10:46:05 +00002369 abi_ulong msg;
2370 size_t len;
Ulrich Hecht98818182009-07-03 17:09:28 +02002371 abi_ulong flags;
bellard2f619692007-11-16 10:46:05 +00002372 abi_ulong addr;
2373 socklen_t addrlen;
2374
Ulrich Hecht98818182009-07-03 17:09:28 +02002375 if (get_user_ual(sockfd, vptr)
bellard2f619692007-11-16 10:46:05 +00002376 || get_user_ual(msg, vptr + n)
2377 || get_user_ual(len, vptr + 2 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002378 || get_user_ual(flags, vptr + 3 * n)
bellard2f619692007-11-16 10:46:05 +00002379 || get_user_ual(addr, vptr + 4 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002380 || get_user_ual(addrlen, vptr + 5 * n))
bellard2f619692007-11-16 10:46:05 +00002381 return -TARGET_EFAULT;
2382
pbrook1be9e1d2006-11-19 15:26:04 +00002383 ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
bellard31e31b82003-02-18 22:55:36 +00002384 }
2385 break;
2386 case SOCKOP_shutdown:
bellard7854b052003-03-29 17:22:23 +00002387 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002388 abi_ulong sockfd, how;
bellard2f619692007-11-16 10:46:05 +00002389
Ulrich Hecht98818182009-07-03 17:09:28 +02002390 if (get_user_ual(sockfd, vptr)
2391 || get_user_ual(how, vptr + n))
bellard2f619692007-11-16 10:46:05 +00002392 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002393
2394 ret = get_errno(shutdown(sockfd, how));
2395 }
bellard31e31b82003-02-18 22:55:36 +00002396 break;
2397 case SOCKOP_sendmsg:
2398 case SOCKOP_recvmsg:
bellard1a9353d2003-03-16 20:28:50 +00002399 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002400 abi_ulong fd;
blueswir1992f48a2007-10-14 16:27:31 +00002401 abi_ulong target_msg;
Ulrich Hecht98818182009-07-03 17:09:28 +02002402 abi_ulong flags;
bellard1a9353d2003-03-16 20:28:50 +00002403
Ulrich Hecht98818182009-07-03 17:09:28 +02002404 if (get_user_ual(fd, vptr)
bellard2f619692007-11-16 10:46:05 +00002405 || get_user_ual(target_msg, vptr + n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002406 || get_user_ual(flags, vptr + 2 * n))
bellard2f619692007-11-16 10:46:05 +00002407 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002408
ths5fafdf22007-09-16 21:08:06 +00002409 ret = do_sendrecvmsg(fd, target_msg, flags,
bellard3532fa72006-06-24 15:06:03 +00002410 (num == SOCKOP_sendmsg));
bellard1a9353d2003-03-16 20:28:50 +00002411 }
2412 break;
bellard31e31b82003-02-18 22:55:36 +00002413 case SOCKOP_setsockopt:
bellard7854b052003-03-29 17:22:23 +00002414 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002415 abi_ulong sockfd;
2416 abi_ulong level;
2417 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002418 abi_ulong optval;
2419 socklen_t optlen;
2420
Ulrich Hecht98818182009-07-03 17:09:28 +02002421 if (get_user_ual(sockfd, vptr)
2422 || get_user_ual(level, vptr + n)
2423 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002424 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002425 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002426 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00002427
2428 ret = do_setsockopt(sockfd, level, optname, optval, optlen);
2429 }
2430 break;
bellard31e31b82003-02-18 22:55:36 +00002431 case SOCKOP_getsockopt:
bellard7854b052003-03-29 17:22:23 +00002432 {
Ulrich Hecht98818182009-07-03 17:09:28 +02002433 abi_ulong sockfd;
2434 abi_ulong level;
2435 abi_ulong optname;
bellard2f619692007-11-16 10:46:05 +00002436 abi_ulong optval;
2437 socklen_t optlen;
bellard7854b052003-03-29 17:22:23 +00002438
Ulrich Hecht98818182009-07-03 17:09:28 +02002439 if (get_user_ual(sockfd, vptr)
2440 || get_user_ual(level, vptr + n)
2441 || get_user_ual(optname, vptr + 2 * n)
bellard2f619692007-11-16 10:46:05 +00002442 || get_user_ual(optval, vptr + 3 * n)
Ulrich Hecht98818182009-07-03 17:09:28 +02002443 || get_user_ual(optlen, vptr + 4 * n))
bellard2f619692007-11-16 10:46:05 +00002444 return -TARGET_EFAULT;
2445
2446 ret = do_getsockopt(sockfd, level, optname, optval, optlen);
bellard7854b052003-03-29 17:22:23 +00002447 }
2448 break;
bellard31e31b82003-02-18 22:55:36 +00002449 default:
2450 gemu_log("Unsupported socketcall: %d\n", num);
ths0da46a62007-10-20 20:23:07 +00002451 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002452 break;
2453 }
2454 return ret;
2455}
j_mayer32407102007-09-26 23:01:49 +00002456#endif
bellard31e31b82003-02-18 22:55:36 +00002457
bellard8853f862004-02-22 14:57:26 +00002458#define N_SHM_REGIONS 32
2459
2460static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002461 abi_ulong start;
2462 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002463} shm_regions[N_SHM_REGIONS];
2464
ths3eb6b042007-06-03 14:26:27 +00002465struct target_ipc_perm
2466{
blueswir1992f48a2007-10-14 16:27:31 +00002467 abi_long __key;
2468 abi_ulong uid;
2469 abi_ulong gid;
2470 abi_ulong cuid;
2471 abi_ulong cgid;
ths3eb6b042007-06-03 14:26:27 +00002472 unsigned short int mode;
2473 unsigned short int __pad1;
2474 unsigned short int __seq;
2475 unsigned short int __pad2;
blueswir1992f48a2007-10-14 16:27:31 +00002476 abi_ulong __unused1;
2477 abi_ulong __unused2;
ths3eb6b042007-06-03 14:26:27 +00002478};
2479
2480struct target_semid_ds
2481{
2482 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002483 abi_ulong sem_otime;
2484 abi_ulong __unused1;
2485 abi_ulong sem_ctime;
2486 abi_ulong __unused2;
2487 abi_ulong sem_nsems;
2488 abi_ulong __unused3;
2489 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002490};
2491
bellard579a97f2007-11-11 14:26:47 +00002492static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2493 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002494{
2495 struct target_ipc_perm *target_ip;
2496 struct target_semid_ds *target_sd;
2497
bellard579a97f2007-11-11 14:26:47 +00002498 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2499 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002500 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002501 host_ip->__key = tswapal(target_ip->__key);
2502 host_ip->uid = tswapal(target_ip->uid);
2503 host_ip->gid = tswapal(target_ip->gid);
2504 host_ip->cuid = tswapal(target_ip->cuid);
2505 host_ip->cgid = tswapal(target_ip->cgid);
2506 host_ip->mode = tswap16(target_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002507 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002508 return 0;
ths3eb6b042007-06-03 14:26:27 +00002509}
2510
bellard579a97f2007-11-11 14:26:47 +00002511static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2512 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002513{
2514 struct target_ipc_perm *target_ip;
2515 struct target_semid_ds *target_sd;
2516
bellard579a97f2007-11-11 14:26:47 +00002517 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2518 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002519 target_ip = &(target_sd->sem_perm);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002520 target_ip->__key = tswapal(host_ip->__key);
2521 target_ip->uid = tswapal(host_ip->uid);
2522 target_ip->gid = tswapal(host_ip->gid);
2523 target_ip->cuid = tswapal(host_ip->cuid);
2524 target_ip->cgid = tswapal(host_ip->cgid);
2525 target_ip->mode = tswap16(host_ip->mode);
ths3eb6b042007-06-03 14:26:27 +00002526 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002527 return 0;
ths3eb6b042007-06-03 14:26:27 +00002528}
2529
bellard579a97f2007-11-11 14:26:47 +00002530static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2531 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002532{
2533 struct target_semid_ds *target_sd;
2534
bellard579a97f2007-11-11 14:26:47 +00002535 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2536 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002537 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2538 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002539 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2540 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2541 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002542 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002543 return 0;
ths3eb6b042007-06-03 14:26:27 +00002544}
2545
bellard579a97f2007-11-11 14:26:47 +00002546static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2547 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002548{
2549 struct target_semid_ds *target_sd;
2550
bellard579a97f2007-11-11 14:26:47 +00002551 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2552 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002553 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002554 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002555 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2556 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2557 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002558 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002559 return 0;
ths3eb6b042007-06-03 14:26:27 +00002560}
2561
aurel32e5289082009-04-18 16:16:12 +00002562struct target_seminfo {
2563 int semmap;
2564 int semmni;
2565 int semmns;
2566 int semmnu;
2567 int semmsl;
2568 int semopm;
2569 int semume;
2570 int semusz;
2571 int semvmx;
2572 int semaem;
2573};
2574
2575static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2576 struct seminfo *host_seminfo)
2577{
2578 struct target_seminfo *target_seminfo;
2579 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2580 return -TARGET_EFAULT;
2581 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2582 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2583 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2584 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2585 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2586 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2587 __put_user(host_seminfo->semume, &target_seminfo->semume);
2588 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2589 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2590 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2591 unlock_user_struct(target_seminfo, target_addr, 1);
2592 return 0;
2593}
2594
thsfa294812007-02-02 22:05:00 +00002595union semun {
2596 int val;
ths3eb6b042007-06-03 14:26:27 +00002597 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002598 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002599 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002600};
2601
ths3eb6b042007-06-03 14:26:27 +00002602union target_semun {
2603 int val;
aurel32e5289082009-04-18 16:16:12 +00002604 abi_ulong buf;
2605 abi_ulong array;
2606 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002607};
2608
aurel32e5289082009-04-18 16:16:12 +00002609static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2610 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002611{
aurel32e5289082009-04-18 16:16:12 +00002612 int nsems;
2613 unsigned short *array;
2614 union semun semun;
2615 struct semid_ds semid_ds;
2616 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002617
aurel32e5289082009-04-18 16:16:12 +00002618 semun.buf = &semid_ds;
2619
2620 ret = semctl(semid, 0, IPC_STAT, semun);
2621 if (ret == -1)
2622 return get_errno(ret);
2623
2624 nsems = semid_ds.sem_nsems;
2625
2626 *host_array = malloc(nsems*sizeof(unsigned short));
2627 array = lock_user(VERIFY_READ, target_addr,
2628 nsems*sizeof(unsigned short), 1);
2629 if (!array)
2630 return -TARGET_EFAULT;
2631
2632 for(i=0; i<nsems; i++) {
2633 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002634 }
aurel32e5289082009-04-18 16:16:12 +00002635 unlock_user(array, target_addr, 0);
2636
bellard579a97f2007-11-11 14:26:47 +00002637 return 0;
ths3eb6b042007-06-03 14:26:27 +00002638}
2639
aurel32e5289082009-04-18 16:16:12 +00002640static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2641 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002642{
aurel32e5289082009-04-18 16:16:12 +00002643 int nsems;
2644 unsigned short *array;
2645 union semun semun;
2646 struct semid_ds semid_ds;
2647 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002648
aurel32e5289082009-04-18 16:16:12 +00002649 semun.buf = &semid_ds;
2650
2651 ret = semctl(semid, 0, IPC_STAT, semun);
2652 if (ret == -1)
2653 return get_errno(ret);
2654
2655 nsems = semid_ds.sem_nsems;
2656
2657 array = lock_user(VERIFY_WRITE, target_addr,
2658 nsems*sizeof(unsigned short), 0);
2659 if (!array)
2660 return -TARGET_EFAULT;
2661
2662 for(i=0; i<nsems; i++) {
2663 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002664 }
aurel32e5289082009-04-18 16:16:12 +00002665 free(*host_array);
2666 unlock_user(array, target_addr, 1);
2667
bellard579a97f2007-11-11 14:26:47 +00002668 return 0;
ths3eb6b042007-06-03 14:26:27 +00002669}
2670
aurel32e5289082009-04-18 16:16:12 +00002671static inline abi_long do_semctl(int semid, int semnum, int cmd,
2672 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002673{
2674 union semun arg;
2675 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302676 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002677 struct seminfo seminfo;
2678 abi_long ret = -TARGET_EINVAL;
2679 abi_long err;
2680 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002681
2682 switch( cmd ) {
2683 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002684 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002685 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002686 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002687 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002688 break;
2689 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002690 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002691 err = target_to_host_semarray(semid, &array, target_su.array);
2692 if (err)
2693 return err;
2694 arg.array = array;
2695 ret = get_errno(semctl(semid, semnum, cmd, arg));
2696 err = host_to_target_semarray(semid, target_su.array, &array);
2697 if (err)
2698 return err;
ths3eb6b042007-06-03 14:26:27 +00002699 break;
2700 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002701 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002702 case SEM_STAT:
2703 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2704 if (err)
2705 return err;
2706 arg.buf = &dsarg;
2707 ret = get_errno(semctl(semid, semnum, cmd, arg));
2708 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2709 if (err)
2710 return err;
ths3eb6b042007-06-03 14:26:27 +00002711 break;
aurel32e5289082009-04-18 16:16:12 +00002712 case IPC_INFO:
2713 case SEM_INFO:
2714 arg.__buf = &seminfo;
2715 ret = get_errno(semctl(semid, semnum, cmd, arg));
2716 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2717 if (err)
2718 return err;
2719 break;
2720 case IPC_RMID:
2721 case GETPID:
2722 case GETNCNT:
2723 case GETZCNT:
2724 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2725 break;
ths3eb6b042007-06-03 14:26:27 +00002726 }
2727
2728 return ret;
2729}
2730
aurel32e5289082009-04-18 16:16:12 +00002731struct target_sembuf {
2732 unsigned short sem_num;
2733 short sem_op;
2734 short sem_flg;
2735};
2736
2737static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2738 abi_ulong target_addr,
2739 unsigned nsops)
2740{
2741 struct target_sembuf *target_sembuf;
2742 int i;
2743
2744 target_sembuf = lock_user(VERIFY_READ, target_addr,
2745 nsops*sizeof(struct target_sembuf), 1);
2746 if (!target_sembuf)
2747 return -TARGET_EFAULT;
2748
2749 for(i=0; i<nsops; i++) {
2750 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2751 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2752 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2753 }
2754
2755 unlock_user(target_sembuf, target_addr, 0);
2756
2757 return 0;
2758}
2759
2760static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2761{
2762 struct sembuf sops[nsops];
2763
2764 if (target_to_host_sembuf(sops, ptr, nsops))
2765 return -TARGET_EFAULT;
2766
2767 return semop(semid, sops, nsops);
2768}
2769
ths1bc012f2007-06-03 14:27:49 +00002770struct target_msqid_ds
2771{
aurel321c54ff92008-10-13 21:08:44 +00002772 struct target_ipc_perm msg_perm;
2773 abi_ulong msg_stime;
2774#if TARGET_ABI_BITS == 32
2775 abi_ulong __unused1;
2776#endif
2777 abi_ulong msg_rtime;
2778#if TARGET_ABI_BITS == 32
2779 abi_ulong __unused2;
2780#endif
2781 abi_ulong msg_ctime;
2782#if TARGET_ABI_BITS == 32
2783 abi_ulong __unused3;
2784#endif
2785 abi_ulong __msg_cbytes;
2786 abi_ulong msg_qnum;
2787 abi_ulong msg_qbytes;
2788 abi_ulong msg_lspid;
2789 abi_ulong msg_lrpid;
2790 abi_ulong __unused4;
2791 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002792};
2793
bellard579a97f2007-11-11 14:26:47 +00002794static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2795 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002796{
2797 struct target_msqid_ds *target_md;
2798
bellard579a97f2007-11-11 14:26:47 +00002799 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2800 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002801 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2802 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002803 host_md->msg_stime = tswapal(target_md->msg_stime);
2804 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2805 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2806 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2807 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2808 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2809 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2810 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002811 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002812 return 0;
ths1bc012f2007-06-03 14:27:49 +00002813}
2814
bellard579a97f2007-11-11 14:26:47 +00002815static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2816 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002817{
2818 struct target_msqid_ds *target_md;
2819
bellard579a97f2007-11-11 14:26:47 +00002820 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2821 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002822 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2823 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002824 target_md->msg_stime = tswapal(host_md->msg_stime);
2825 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2826 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2827 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2828 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2829 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2830 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2831 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002832 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002833 return 0;
ths1bc012f2007-06-03 14:27:49 +00002834}
2835
aurel321c54ff92008-10-13 21:08:44 +00002836struct target_msginfo {
2837 int msgpool;
2838 int msgmap;
2839 int msgmax;
2840 int msgmnb;
2841 int msgmni;
2842 int msgssz;
2843 int msgtql;
2844 unsigned short int msgseg;
2845};
2846
2847static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2848 struct msginfo *host_msginfo)
2849{
2850 struct target_msginfo *target_msginfo;
2851 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2852 return -TARGET_EFAULT;
2853 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2854 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2855 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2856 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2857 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2858 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2859 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2860 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2861 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002862 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002863}
2864
2865static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002866{
2867 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002868 struct msginfo msginfo;
2869 abi_long ret = -TARGET_EINVAL;
2870
2871 cmd &= 0xff;
2872
2873 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002874 case IPC_STAT:
2875 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002876 case MSG_STAT:
2877 if (target_to_host_msqid_ds(&dsarg,ptr))
2878 return -TARGET_EFAULT;
2879 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2880 if (host_to_target_msqid_ds(ptr,&dsarg))
2881 return -TARGET_EFAULT;
2882 break;
2883 case IPC_RMID:
2884 ret = get_errno(msgctl(msgid, cmd, NULL));
2885 break;
2886 case IPC_INFO:
2887 case MSG_INFO:
2888 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2889 if (host_to_target_msginfo(ptr, &msginfo))
2890 return -TARGET_EFAULT;
2891 break;
ths1bc012f2007-06-03 14:27:49 +00002892 }
aurel321c54ff92008-10-13 21:08:44 +00002893
ths1bc012f2007-06-03 14:27:49 +00002894 return ret;
2895}
2896
2897struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002898 abi_long mtype;
2899 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002900};
2901
blueswir1992f48a2007-10-14 16:27:31 +00002902static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2903 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002904{
2905 struct target_msgbuf *target_mb;
2906 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002907 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002908
bellard579a97f2007-11-11 14:26:47 +00002909 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2910 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002911 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002912 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002913 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002914 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2915 free(host_mb);
2916 unlock_user_struct(target_mb, msgp, 0);
2917
2918 return ret;
2919}
2920
blueswir1992f48a2007-10-14 16:27:31 +00002921static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002922 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002923 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002924{
2925 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002926 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002927 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002928 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002929
bellard579a97f2007-11-11 14:26:47 +00002930 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2931 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002932
Jim Meyering0d07fe42012-08-22 13:55:53 +02002933 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002934 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002935
bellard579a97f2007-11-11 14:26:47 +00002936 if (ret > 0) {
2937 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2938 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2939 if (!target_mtext) {
2940 ret = -TARGET_EFAULT;
2941 goto end;
2942 }
aurel321c54ff92008-10-13 21:08:44 +00002943 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002944 unlock_user(target_mtext, target_mtext_addr, ret);
2945 }
aurel321c54ff92008-10-13 21:08:44 +00002946
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002947 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002948
bellard579a97f2007-11-11 14:26:47 +00002949end:
2950 if (target_mb)
2951 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002952 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002953 return ret;
2954}
2955
Riku Voipio88a8c982009-04-03 10:42:00 +03002956struct target_shmid_ds
2957{
2958 struct target_ipc_perm shm_perm;
2959 abi_ulong shm_segsz;
2960 abi_ulong shm_atime;
2961#if TARGET_ABI_BITS == 32
2962 abi_ulong __unused1;
2963#endif
2964 abi_ulong shm_dtime;
2965#if TARGET_ABI_BITS == 32
2966 abi_ulong __unused2;
2967#endif
2968 abi_ulong shm_ctime;
2969#if TARGET_ABI_BITS == 32
2970 abi_ulong __unused3;
2971#endif
2972 int shm_cpid;
2973 int shm_lpid;
2974 abi_ulong shm_nattch;
2975 unsigned long int __unused4;
2976 unsigned long int __unused5;
2977};
2978
2979static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2980 abi_ulong target_addr)
2981{
2982 struct target_shmid_ds *target_sd;
2983
2984 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2985 return -TARGET_EFAULT;
2986 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2987 return -TARGET_EFAULT;
2988 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2989 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2990 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2991 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2992 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2993 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2994 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2995 unlock_user_struct(target_sd, target_addr, 0);
2996 return 0;
2997}
2998
2999static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3000 struct shmid_ds *host_sd)
3001{
3002 struct target_shmid_ds *target_sd;
3003
3004 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3005 return -TARGET_EFAULT;
3006 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3007 return -TARGET_EFAULT;
3008 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3009 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3010 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3011 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3012 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3013 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3014 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3015 unlock_user_struct(target_sd, target_addr, 1);
3016 return 0;
3017}
3018
3019struct target_shminfo {
3020 abi_ulong shmmax;
3021 abi_ulong shmmin;
3022 abi_ulong shmmni;
3023 abi_ulong shmseg;
3024 abi_ulong shmall;
3025};
3026
3027static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3028 struct shminfo *host_shminfo)
3029{
3030 struct target_shminfo *target_shminfo;
3031 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3032 return -TARGET_EFAULT;
3033 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3034 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3035 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3036 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3037 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3038 unlock_user_struct(target_shminfo, target_addr, 1);
3039 return 0;
3040}
3041
3042struct target_shm_info {
3043 int used_ids;
3044 abi_ulong shm_tot;
3045 abi_ulong shm_rss;
3046 abi_ulong shm_swp;
3047 abi_ulong swap_attempts;
3048 abi_ulong swap_successes;
3049};
3050
3051static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3052 struct shm_info *host_shm_info)
3053{
3054 struct target_shm_info *target_shm_info;
3055 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3056 return -TARGET_EFAULT;
3057 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3058 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3059 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3060 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3061 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3062 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3063 unlock_user_struct(target_shm_info, target_addr, 1);
3064 return 0;
3065}
3066
3067static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3068{
3069 struct shmid_ds dsarg;
3070 struct shminfo shminfo;
3071 struct shm_info shm_info;
3072 abi_long ret = -TARGET_EINVAL;
3073
3074 cmd &= 0xff;
3075
3076 switch(cmd) {
3077 case IPC_STAT:
3078 case IPC_SET:
3079 case SHM_STAT:
3080 if (target_to_host_shmid_ds(&dsarg, buf))
3081 return -TARGET_EFAULT;
3082 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3083 if (host_to_target_shmid_ds(buf, &dsarg))
3084 return -TARGET_EFAULT;
3085 break;
3086 case IPC_INFO:
3087 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3088 if (host_to_target_shminfo(buf, &shminfo))
3089 return -TARGET_EFAULT;
3090 break;
3091 case SHM_INFO:
3092 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3093 if (host_to_target_shm_info(buf, &shm_info))
3094 return -TARGET_EFAULT;
3095 break;
3096 case IPC_RMID:
3097 case SHM_LOCK:
3098 case SHM_UNLOCK:
3099 ret = get_errno(shmctl(shmid, cmd, NULL));
3100 break;
3101 }
3102
3103 return ret;
3104}
3105
3106static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3107{
3108 abi_long raddr;
3109 void *host_raddr;
3110 struct shmid_ds shm_info;
3111 int i,ret;
3112
3113 /* find out the length of the shared memory segment */
3114 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3115 if (is_error(ret)) {
3116 /* can't get length, bail out */
3117 return ret;
3118 }
3119
3120 mmap_lock();
3121
3122 if (shmaddr)
3123 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3124 else {
3125 abi_ulong mmap_start;
3126
3127 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3128
3129 if (mmap_start == -1) {
3130 errno = ENOMEM;
3131 host_raddr = (void *)-1;
3132 } else
3133 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3134 }
3135
3136 if (host_raddr == (void *)-1) {
3137 mmap_unlock();
3138 return get_errno((long)host_raddr);
3139 }
3140 raddr=h2g((unsigned long)host_raddr);
3141
3142 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3143 PAGE_VALID | PAGE_READ |
3144 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3145
3146 for (i = 0; i < N_SHM_REGIONS; i++) {
3147 if (shm_regions[i].start == 0) {
3148 shm_regions[i].start = raddr;
3149 shm_regions[i].size = shm_info.shm_segsz;
3150 break;
3151 }
3152 }
3153
3154 mmap_unlock();
3155 return raddr;
3156
3157}
3158
3159static inline abi_long do_shmdt(abi_ulong shmaddr)
3160{
3161 int i;
3162
3163 for (i = 0; i < N_SHM_REGIONS; ++i) {
3164 if (shm_regions[i].start == shmaddr) {
3165 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003166 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003167 break;
3168 }
3169 }
3170
3171 return get_errno(shmdt(g2h(shmaddr)));
3172}
3173
aurel321c54ff92008-10-13 21:08:44 +00003174#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003175/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003176/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003177static abi_long do_ipc(unsigned int call, int first,
3178 int second, int third,
3179 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003180{
3181 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003182 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003183
3184 version = call >> 16;
3185 call &= 0xffff;
3186
3187 switch (call) {
thsfa294812007-02-02 22:05:00 +00003188 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003189 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003190 break;
3191
3192 case IPCOP_semget:
3193 ret = get_errno(semget(first, second, third));
3194 break;
3195
3196 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003197 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003198 break;
thsd96372e2007-02-02 22:05:44 +00003199
aurel321c54ff92008-10-13 21:08:44 +00003200 case IPCOP_msgget:
3201 ret = get_errno(msgget(first, second));
3202 break;
thsd96372e2007-02-02 22:05:44 +00003203
aurel321c54ff92008-10-13 21:08:44 +00003204 case IPCOP_msgsnd:
3205 ret = do_msgsnd(first, ptr, second, third);
3206 break;
thsd96372e2007-02-02 22:05:44 +00003207
aurel321c54ff92008-10-13 21:08:44 +00003208 case IPCOP_msgctl:
3209 ret = do_msgctl(first, second, ptr);
3210 break;
thsd96372e2007-02-02 22:05:44 +00003211
aurel321c54ff92008-10-13 21:08:44 +00003212 case IPCOP_msgrcv:
3213 switch (version) {
3214 case 0:
3215 {
3216 struct target_ipc_kludge {
3217 abi_long msgp;
3218 abi_long msgtyp;
3219 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003220
aurel321c54ff92008-10-13 21:08:44 +00003221 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3222 ret = -TARGET_EFAULT;
3223 break;
ths1bc012f2007-06-03 14:27:49 +00003224 }
aurel321c54ff92008-10-13 21:08:44 +00003225
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003226 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003227
3228 unlock_user_struct(tmp, ptr, 0);
3229 break;
3230 }
3231 default:
3232 ret = do_msgrcv(first, ptr, second, fifth, third);
3233 }
3234 break;
thsd96372e2007-02-02 22:05:44 +00003235
bellard8853f862004-02-22 14:57:26 +00003236 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003237 switch (version) {
3238 default:
bellard5a4a8982007-11-11 17:39:18 +00003239 {
3240 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003241 raddr = do_shmat(first, ptr, second);
3242 if (is_error(raddr))
3243 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003244 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003245 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003246 break;
3247 }
3248 case 1:
3249 ret = -TARGET_EINVAL;
3250 break;
bellard5a4a8982007-11-11 17:39:18 +00003251 }
bellard8853f862004-02-22 14:57:26 +00003252 break;
3253 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003254 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003255 break;
3256
3257 case IPCOP_shmget:
3258 /* IPC_* flag values are the same on all linux platforms */
3259 ret = get_errno(shmget(first, second, third));
3260 break;
3261
3262 /* IPC_* and SHM_* command values are the same on all linux platforms */
3263 case IPCOP_shmctl:
Riku Voipio88a8c982009-04-03 10:42:00 +03003264 ret = do_shmctl(first, second, third);
bellard8853f862004-02-22 14:57:26 +00003265 break;
3266 default:
j_mayer32407102007-09-26 23:01:49 +00003267 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003268 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003269 break;
3270 }
3271 return ret;
3272}
j_mayer32407102007-09-26 23:01:49 +00003273#endif
bellard8853f862004-02-22 14:57:26 +00003274
bellard31e31b82003-02-18 22:55:36 +00003275/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003276
Blue Swirl001faf32009-05-13 17:53:17 +00003277#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003278#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3279enum {
3280#include "syscall_types.h"
3281};
3282#undef STRUCT
3283#undef STRUCT_SPECIAL
3284
Blue Swirl001faf32009-05-13 17:53:17 +00003285#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003286#define STRUCT_SPECIAL(name)
3287#include "syscall_types.h"
3288#undef STRUCT
3289#undef STRUCT_SPECIAL
3290
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003291typedef struct IOCTLEntry IOCTLEntry;
3292
3293typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3294 int fd, abi_long cmd, abi_long arg);
3295
3296struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003297 unsigned int target_cmd;
3298 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003299 const char *name;
3300 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003301 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003302 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003303};
bellard31e31b82003-02-18 22:55:36 +00003304
3305#define IOC_R 0x0001
3306#define IOC_W 0x0002
3307#define IOC_RW (IOC_R | IOC_W)
3308
3309#define MAX_STRUCT_SIZE 4096
3310
Peter Maydelldace20d2011-01-10 13:11:24 +00003311#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003312/* So fiemap access checks don't overflow on 32 bit systems.
3313 * This is very slightly smaller than the limit imposed by
3314 * the underlying kernel.
3315 */
3316#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3317 / sizeof(struct fiemap_extent))
3318
3319static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3320 int fd, abi_long cmd, abi_long arg)
3321{
3322 /* The parameter for this ioctl is a struct fiemap followed
3323 * by an array of struct fiemap_extent whose size is set
3324 * in fiemap->fm_extent_count. The array is filled in by the
3325 * ioctl.
3326 */
3327 int target_size_in, target_size_out;
3328 struct fiemap *fm;
3329 const argtype *arg_type = ie->arg_type;
3330 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3331 void *argptr, *p;
3332 abi_long ret;
3333 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3334 uint32_t outbufsz;
3335 int free_fm = 0;
3336
3337 assert(arg_type[0] == TYPE_PTR);
3338 assert(ie->access == IOC_RW);
3339 arg_type++;
3340 target_size_in = thunk_type_size(arg_type, 0);
3341 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3342 if (!argptr) {
3343 return -TARGET_EFAULT;
3344 }
3345 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3346 unlock_user(argptr, arg, 0);
3347 fm = (struct fiemap *)buf_temp;
3348 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3349 return -TARGET_EINVAL;
3350 }
3351
3352 outbufsz = sizeof (*fm) +
3353 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3354
3355 if (outbufsz > MAX_STRUCT_SIZE) {
3356 /* We can't fit all the extents into the fixed size buffer.
3357 * Allocate one that is large enough and use it instead.
3358 */
3359 fm = malloc(outbufsz);
3360 if (!fm) {
3361 return -TARGET_ENOMEM;
3362 }
3363 memcpy(fm, buf_temp, sizeof(struct fiemap));
3364 free_fm = 1;
3365 }
3366 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3367 if (!is_error(ret)) {
3368 target_size_out = target_size_in;
3369 /* An extent_count of 0 means we were only counting the extents
3370 * so there are no structs to copy
3371 */
3372 if (fm->fm_extent_count != 0) {
3373 target_size_out += fm->fm_mapped_extents * extent_size;
3374 }
3375 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3376 if (!argptr) {
3377 ret = -TARGET_EFAULT;
3378 } else {
3379 /* Convert the struct fiemap */
3380 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3381 if (fm->fm_extent_count != 0) {
3382 p = argptr + target_size_in;
3383 /* ...and then all the struct fiemap_extents */
3384 for (i = 0; i < fm->fm_mapped_extents; i++) {
3385 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3386 THUNK_TARGET);
3387 p += extent_size;
3388 }
3389 }
3390 unlock_user(argptr, arg, target_size_out);
3391 }
3392 }
3393 if (free_fm) {
3394 free(fm);
3395 }
3396 return ret;
3397}
Peter Maydelldace20d2011-01-10 13:11:24 +00003398#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003399
Laurent Vivier059c2f22011-03-30 00:12:12 +02003400static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3401 int fd, abi_long cmd, abi_long arg)
3402{
3403 const argtype *arg_type = ie->arg_type;
3404 int target_size;
3405 void *argptr;
3406 int ret;
3407 struct ifconf *host_ifconf;
3408 uint32_t outbufsz;
3409 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3410 int target_ifreq_size;
3411 int nb_ifreq;
3412 int free_buf = 0;
3413 int i;
3414 int target_ifc_len;
3415 abi_long target_ifc_buf;
3416 int host_ifc_len;
3417 char *host_ifc_buf;
3418
3419 assert(arg_type[0] == TYPE_PTR);
3420 assert(ie->access == IOC_RW);
3421
3422 arg_type++;
3423 target_size = thunk_type_size(arg_type, 0);
3424
3425 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3426 if (!argptr)
3427 return -TARGET_EFAULT;
3428 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3429 unlock_user(argptr, arg, 0);
3430
3431 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3432 target_ifc_len = host_ifconf->ifc_len;
3433 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3434
3435 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3436 nb_ifreq = target_ifc_len / target_ifreq_size;
3437 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3438
3439 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3440 if (outbufsz > MAX_STRUCT_SIZE) {
3441 /* We can't fit all the extents into the fixed size buffer.
3442 * Allocate one that is large enough and use it instead.
3443 */
3444 host_ifconf = malloc(outbufsz);
3445 if (!host_ifconf) {
3446 return -TARGET_ENOMEM;
3447 }
3448 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3449 free_buf = 1;
3450 }
3451 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3452
3453 host_ifconf->ifc_len = host_ifc_len;
3454 host_ifconf->ifc_buf = host_ifc_buf;
3455
3456 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3457 if (!is_error(ret)) {
3458 /* convert host ifc_len to target ifc_len */
3459
3460 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3461 target_ifc_len = nb_ifreq * target_ifreq_size;
3462 host_ifconf->ifc_len = target_ifc_len;
3463
3464 /* restore target ifc_buf */
3465
3466 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3467
3468 /* copy struct ifconf to target user */
3469
3470 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3471 if (!argptr)
3472 return -TARGET_EFAULT;
3473 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3474 unlock_user(argptr, arg, target_size);
3475
3476 /* copy ifreq[] to target user */
3477
3478 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3479 for (i = 0; i < nb_ifreq ; i++) {
3480 thunk_convert(argptr + i * target_ifreq_size,
3481 host_ifc_buf + i * sizeof(struct ifreq),
3482 ifreq_arg_type, THUNK_TARGET);
3483 }
3484 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3485 }
3486
3487 if (free_buf) {
3488 free(host_ifconf);
3489 }
3490
3491 return ret;
3492}
3493
Alexander Graf56e904e2012-01-31 18:42:06 +01003494static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3495 abi_long cmd, abi_long arg)
3496{
3497 void *argptr;
3498 struct dm_ioctl *host_dm;
3499 abi_long guest_data;
3500 uint32_t guest_data_size;
3501 int target_size;
3502 const argtype *arg_type = ie->arg_type;
3503 abi_long ret;
3504 void *big_buf = NULL;
3505 char *host_data;
3506
3507 arg_type++;
3508 target_size = thunk_type_size(arg_type, 0);
3509 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3510 if (!argptr) {
3511 ret = -TARGET_EFAULT;
3512 goto out;
3513 }
3514 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3515 unlock_user(argptr, arg, 0);
3516
3517 /* buf_temp is too small, so fetch things into a bigger buffer */
3518 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3519 memcpy(big_buf, buf_temp, target_size);
3520 buf_temp = big_buf;
3521 host_dm = big_buf;
3522
3523 guest_data = arg + host_dm->data_start;
3524 if ((guest_data - arg) < 0) {
3525 ret = -EINVAL;
3526 goto out;
3527 }
3528 guest_data_size = host_dm->data_size - host_dm->data_start;
3529 host_data = (char*)host_dm + host_dm->data_start;
3530
3531 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3532 switch (ie->host_cmd) {
3533 case DM_REMOVE_ALL:
3534 case DM_LIST_DEVICES:
3535 case DM_DEV_CREATE:
3536 case DM_DEV_REMOVE:
3537 case DM_DEV_SUSPEND:
3538 case DM_DEV_STATUS:
3539 case DM_DEV_WAIT:
3540 case DM_TABLE_STATUS:
3541 case DM_TABLE_CLEAR:
3542 case DM_TABLE_DEPS:
3543 case DM_LIST_VERSIONS:
3544 /* no input data */
3545 break;
3546 case DM_DEV_RENAME:
3547 case DM_DEV_SET_GEOMETRY:
3548 /* data contains only strings */
3549 memcpy(host_data, argptr, guest_data_size);
3550 break;
3551 case DM_TARGET_MSG:
3552 memcpy(host_data, argptr, guest_data_size);
3553 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3554 break;
3555 case DM_TABLE_LOAD:
3556 {
3557 void *gspec = argptr;
3558 void *cur_data = host_data;
3559 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3560 int spec_size = thunk_type_size(arg_type, 0);
3561 int i;
3562
3563 for (i = 0; i < host_dm->target_count; i++) {
3564 struct dm_target_spec *spec = cur_data;
3565 uint32_t next;
3566 int slen;
3567
3568 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3569 slen = strlen((char*)gspec + spec_size) + 1;
3570 next = spec->next;
3571 spec->next = sizeof(*spec) + slen;
3572 strcpy((char*)&spec[1], gspec + spec_size);
3573 gspec += next;
3574 cur_data += spec->next;
3575 }
3576 break;
3577 }
3578 default:
3579 ret = -TARGET_EINVAL;
3580 goto out;
3581 }
3582 unlock_user(argptr, guest_data, 0);
3583
3584 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3585 if (!is_error(ret)) {
3586 guest_data = arg + host_dm->data_start;
3587 guest_data_size = host_dm->data_size - host_dm->data_start;
3588 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3589 switch (ie->host_cmd) {
3590 case DM_REMOVE_ALL:
3591 case DM_DEV_CREATE:
3592 case DM_DEV_REMOVE:
3593 case DM_DEV_RENAME:
3594 case DM_DEV_SUSPEND:
3595 case DM_DEV_STATUS:
3596 case DM_TABLE_LOAD:
3597 case DM_TABLE_CLEAR:
3598 case DM_TARGET_MSG:
3599 case DM_DEV_SET_GEOMETRY:
3600 /* no return data */
3601 break;
3602 case DM_LIST_DEVICES:
3603 {
3604 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3605 uint32_t remaining_data = guest_data_size;
3606 void *cur_data = argptr;
3607 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3608 int nl_size = 12; /* can't use thunk_size due to alignment */
3609
3610 while (1) {
3611 uint32_t next = nl->next;
3612 if (next) {
3613 nl->next = nl_size + (strlen(nl->name) + 1);
3614 }
3615 if (remaining_data < nl->next) {
3616 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3617 break;
3618 }
3619 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3620 strcpy(cur_data + nl_size, nl->name);
3621 cur_data += nl->next;
3622 remaining_data -= nl->next;
3623 if (!next) {
3624 break;
3625 }
3626 nl = (void*)nl + next;
3627 }
3628 break;
3629 }
3630 case DM_DEV_WAIT:
3631 case DM_TABLE_STATUS:
3632 {
3633 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3634 void *cur_data = argptr;
3635 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3636 int spec_size = thunk_type_size(arg_type, 0);
3637 int i;
3638
3639 for (i = 0; i < host_dm->target_count; i++) {
3640 uint32_t next = spec->next;
3641 int slen = strlen((char*)&spec[1]) + 1;
3642 spec->next = (cur_data - argptr) + spec_size + slen;
3643 if (guest_data_size < spec->next) {
3644 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3645 break;
3646 }
3647 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3648 strcpy(cur_data + spec_size, (char*)&spec[1]);
3649 cur_data = argptr + spec->next;
3650 spec = (void*)host_dm + host_dm->data_start + next;
3651 }
3652 break;
3653 }
3654 case DM_TABLE_DEPS:
3655 {
3656 void *hdata = (void*)host_dm + host_dm->data_start;
3657 int count = *(uint32_t*)hdata;
3658 uint64_t *hdev = hdata + 8;
3659 uint64_t *gdev = argptr + 8;
3660 int i;
3661
3662 *(uint32_t*)argptr = tswap32(count);
3663 for (i = 0; i < count; i++) {
3664 *gdev = tswap64(*hdev);
3665 gdev++;
3666 hdev++;
3667 }
3668 break;
3669 }
3670 case DM_LIST_VERSIONS:
3671 {
3672 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3673 uint32_t remaining_data = guest_data_size;
3674 void *cur_data = argptr;
3675 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3676 int vers_size = thunk_type_size(arg_type, 0);
3677
3678 while (1) {
3679 uint32_t next = vers->next;
3680 if (next) {
3681 vers->next = vers_size + (strlen(vers->name) + 1);
3682 }
3683 if (remaining_data < vers->next) {
3684 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3685 break;
3686 }
3687 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3688 strcpy(cur_data + vers_size, vers->name);
3689 cur_data += vers->next;
3690 remaining_data -= vers->next;
3691 if (!next) {
3692 break;
3693 }
3694 vers = (void*)vers + next;
3695 }
3696 break;
3697 }
3698 default:
3699 ret = -TARGET_EINVAL;
3700 goto out;
3701 }
3702 unlock_user(argptr, guest_data, guest_data_size);
3703
3704 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3705 if (!argptr) {
3706 ret = -TARGET_EFAULT;
3707 goto out;
3708 }
3709 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3710 unlock_user(argptr, arg, target_size);
3711 }
3712out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003713 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003714 return ret;
3715}
3716
blueswir19f106a72008-10-05 10:52:52 +00003717static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003718#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003719 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3720#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3721 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003722#include "ioctls.h"
3723 { 0, 0, },
3724};
3725
pbrook53a59602006-03-25 19:31:22 +00003726/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003727/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003728static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003729{
3730 const IOCTLEntry *ie;
3731 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003732 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003733 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003734 int target_size;
3735 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003736
3737 ie = ioctl_entries;
3738 for(;;) {
3739 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003740 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003741 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003742 }
3743 if (ie->target_cmd == cmd)
3744 break;
3745 ie++;
3746 }
3747 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003748#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003749 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003750#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003751 if (ie->do_ioctl) {
3752 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3753 }
3754
bellard31e31b82003-02-18 22:55:36 +00003755 switch(arg_type[0]) {
3756 case TYPE_NULL:
3757 /* no argument */
3758 ret = get_errno(ioctl(fd, ie->host_cmd));
3759 break;
3760 case TYPE_PTRVOID:
3761 case TYPE_INT:
3762 /* int argment */
3763 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3764 break;
3765 case TYPE_PTR:
3766 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003767 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003768 switch(ie->access) {
3769 case IOC_R:
3770 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3771 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003772 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3773 if (!argptr)
3774 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003775 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3776 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003777 }
3778 break;
3779 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003780 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3781 if (!argptr)
3782 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003783 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3784 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003785 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3786 break;
3787 default:
3788 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003789 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3790 if (!argptr)
3791 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003792 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3793 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003794 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3795 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003796 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3797 if (!argptr)
3798 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003799 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3800 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003801 }
3802 break;
3803 }
3804 break;
3805 default:
j_mayer32407102007-09-26 23:01:49 +00003806 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3807 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003808 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003809 break;
3810 }
3811 return ret;
3812}
3813
blueswir1b39bc502008-10-05 10:51:10 +00003814static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003815 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3816 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3817 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3818 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3819 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3820 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3821 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3822 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3823 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3824 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3825 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3826 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3827 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3828 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3829 { 0, 0, 0, 0 }
3830};
3831
blueswir1b39bc502008-10-05 10:51:10 +00003832static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003833 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3834 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3835 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3836 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3837 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3838 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3839 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3840 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3841 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3842 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3843 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3844 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3845 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3846 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3847 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3848 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3849 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3850 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3851 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3852 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3853 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3854 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3855 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3856 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3857 { 0, 0, 0, 0 }
3858};
3859
blueswir1b39bc502008-10-05 10:51:10 +00003860static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003861 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3862 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3863 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3864 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3865 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3866 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3867 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3868 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3869 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3870 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3871 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3872 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3873 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3874 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3875 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3876 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3877 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3878 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3879 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3880 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3881 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3882 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3883 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3884 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3885 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3886 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3887 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3888 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3889 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3890 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3891 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3892 { 0, 0, 0, 0 }
3893};
3894
blueswir1b39bc502008-10-05 10:51:10 +00003895static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003896 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3897 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3898 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3899 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3900 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3901 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3902 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3903 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3904 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3905 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3906 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3907 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3908 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3909 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3910 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3911 { 0, 0, 0, 0 }
3912};
3913
3914static void target_to_host_termios (void *dst, const void *src)
3915{
3916 struct host_termios *host = dst;
3917 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003918
ths5fafdf22007-09-16 21:08:06 +00003919 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003920 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003921 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003922 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003923 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003924 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003925 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003926 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3927 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003928
Arnaud Patard44607122009-04-21 17:39:08 +03003929 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003930 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3931 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003932 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003933 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003934 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003935 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003936 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003937 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003938 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003939 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3940 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003941 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3942 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3943 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3944 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3945 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003946 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003947}
ths3b46e622007-09-17 08:09:54 +00003948
bellard31e31b82003-02-18 22:55:36 +00003949static void host_to_target_termios (void *dst, const void *src)
3950{
3951 struct target_termios *target = dst;
3952 const struct host_termios *host = src;
3953
ths5fafdf22007-09-16 21:08:06 +00003954 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003955 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003956 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003957 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003958 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003959 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003960 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003961 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3962 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003963
Arnaud Patard44607122009-04-21 17:39:08 +03003964 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003965 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3966 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3967 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3968 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3969 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3970 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3971 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3972 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3973 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3974 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3975 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3976 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3977 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3978 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3979 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3980 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3981 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3982}
3983
blueswir18e853dc2008-10-05 10:49:32 +00003984static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003985 .convert = { host_to_target_termios, target_to_host_termios },
3986 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3987 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3988};
3989
bellard5286db72003-06-05 00:57:30 +00003990static bitmask_transtbl mmap_flags_tbl[] = {
3991 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3992 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3993 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3994 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3995 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3996 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3997 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3998 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3999 { 0, 0, 0, 0 }
4000};
4001
bellard2ab83ea2003-06-15 19:56:46 +00004002#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004003
4004/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004005static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004006
bellard03acab62007-11-11 14:57:14 +00004007static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004008{
4009 int size;
pbrook53a59602006-03-25 19:31:22 +00004010 void *p;
bellard6dbad632003-03-16 18:05:05 +00004011
4012 if (!ldt_table)
4013 return 0;
4014 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4015 if (size > bytecount)
4016 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004017 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4018 if (!p)
bellard03acab62007-11-11 14:57:14 +00004019 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004020 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004021 memcpy(p, ldt_table, size);
4022 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004023 return size;
4024}
4025
4026/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004027static abi_long write_ldt(CPUX86State *env,
4028 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004029{
4030 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004031 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004032 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004033 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004034 uint32_t *lp, entry_1, entry_2;
4035
4036 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004037 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004038 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004039 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004040 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004041 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004042 ldt_info.limit = tswap32(target_ldt_info->limit);
4043 ldt_info.flags = tswap32(target_ldt_info->flags);
4044 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004045
bellard6dbad632003-03-16 18:05:05 +00004046 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004047 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004048 seg_32bit = ldt_info.flags & 1;
4049 contents = (ldt_info.flags >> 1) & 3;
4050 read_exec_only = (ldt_info.flags >> 3) & 1;
4051 limit_in_pages = (ldt_info.flags >> 4) & 1;
4052 seg_not_present = (ldt_info.flags >> 5) & 1;
4053 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004054#ifdef TARGET_ABI32
4055 lm = 0;
4056#else
4057 lm = (ldt_info.flags >> 7) & 1;
4058#endif
bellard6dbad632003-03-16 18:05:05 +00004059 if (contents == 3) {
4060 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004061 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004062 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004063 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004064 }
4065 /* allocate the LDT */
4066 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004067 env->ldt.base = target_mmap(0,
4068 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4069 PROT_READ|PROT_WRITE,
4070 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4071 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004072 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004073 memset(g2h(env->ldt.base), 0,
4074 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004075 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004076 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004077 }
4078
4079 /* NOTE: same code as Linux kernel */
4080 /* Allow LDTs to be cleared by the user. */
4081 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4082 if (oldmode ||
4083 (contents == 0 &&
4084 read_exec_only == 1 &&
4085 seg_32bit == 0 &&
4086 limit_in_pages == 0 &&
4087 seg_not_present == 1 &&
4088 useable == 0 )) {
4089 entry_1 = 0;
4090 entry_2 = 0;
4091 goto install;
4092 }
4093 }
ths3b46e622007-09-17 08:09:54 +00004094
bellard6dbad632003-03-16 18:05:05 +00004095 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4096 (ldt_info.limit & 0x0ffff);
4097 entry_2 = (ldt_info.base_addr & 0xff000000) |
4098 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4099 (ldt_info.limit & 0xf0000) |
4100 ((read_exec_only ^ 1) << 9) |
4101 (contents << 10) |
4102 ((seg_not_present ^ 1) << 15) |
4103 (seg_32bit << 22) |
4104 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004105 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004106 0x7000;
4107 if (!oldmode)
4108 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004109
bellard6dbad632003-03-16 18:05:05 +00004110 /* Install the new entry ... */
4111install:
4112 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4113 lp[0] = tswap32(entry_1);
4114 lp[1] = tswap32(entry_2);
4115 return 0;
4116}
4117
4118/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004119static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4120 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004121{
bellard03acab62007-11-11 14:57:14 +00004122 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004123
bellard6dbad632003-03-16 18:05:05 +00004124 switch (func) {
4125 case 0:
4126 ret = read_ldt(ptr, bytecount);
4127 break;
4128 case 1:
4129 ret = write_ldt(env, ptr, bytecount, 1);
4130 break;
4131 case 0x11:
4132 ret = write_ldt(env, ptr, bytecount, 0);
4133 break;
bellard03acab62007-11-11 14:57:14 +00004134 default:
4135 ret = -TARGET_ENOSYS;
4136 break;
bellard6dbad632003-03-16 18:05:05 +00004137 }
4138 return ret;
4139}
bellard1b6b0292003-03-22 17:31:38 +00004140
blueswir14583f582008-08-24 10:35:55 +00004141#if defined(TARGET_I386) && defined(TARGET_ABI32)
blueswir18fcd3692008-08-17 20:26:25 +00004142static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004143{
4144 uint64_t *gdt_table = g2h(env->gdt.base);
4145 struct target_modify_ldt_ldt_s ldt_info;
4146 struct target_modify_ldt_ldt_s *target_ldt_info;
4147 int seg_32bit, contents, read_exec_only, limit_in_pages;
4148 int seg_not_present, useable, lm;
4149 uint32_t *lp, entry_1, entry_2;
4150 int i;
4151
4152 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4153 if (!target_ldt_info)
4154 return -TARGET_EFAULT;
4155 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004156 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004157 ldt_info.limit = tswap32(target_ldt_info->limit);
4158 ldt_info.flags = tswap32(target_ldt_info->flags);
4159 if (ldt_info.entry_number == -1) {
4160 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4161 if (gdt_table[i] == 0) {
4162 ldt_info.entry_number = i;
4163 target_ldt_info->entry_number = tswap32(i);
4164 break;
4165 }
4166 }
4167 }
4168 unlock_user_struct(target_ldt_info, ptr, 1);
4169
4170 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4171 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4172 return -TARGET_EINVAL;
4173 seg_32bit = ldt_info.flags & 1;
4174 contents = (ldt_info.flags >> 1) & 3;
4175 read_exec_only = (ldt_info.flags >> 3) & 1;
4176 limit_in_pages = (ldt_info.flags >> 4) & 1;
4177 seg_not_present = (ldt_info.flags >> 5) & 1;
4178 useable = (ldt_info.flags >> 6) & 1;
4179#ifdef TARGET_ABI32
4180 lm = 0;
4181#else
4182 lm = (ldt_info.flags >> 7) & 1;
4183#endif
4184
4185 if (contents == 3) {
4186 if (seg_not_present == 0)
4187 return -TARGET_EINVAL;
4188 }
4189
4190 /* NOTE: same code as Linux kernel */
4191 /* Allow LDTs to be cleared by the user. */
4192 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4193 if ((contents == 0 &&
4194 read_exec_only == 1 &&
4195 seg_32bit == 0 &&
4196 limit_in_pages == 0 &&
4197 seg_not_present == 1 &&
4198 useable == 0 )) {
4199 entry_1 = 0;
4200 entry_2 = 0;
4201 goto install;
4202 }
4203 }
4204
4205 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4206 (ldt_info.limit & 0x0ffff);
4207 entry_2 = (ldt_info.base_addr & 0xff000000) |
4208 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4209 (ldt_info.limit & 0xf0000) |
4210 ((read_exec_only ^ 1) << 9) |
4211 (contents << 10) |
4212 ((seg_not_present ^ 1) << 15) |
4213 (seg_32bit << 22) |
4214 (limit_in_pages << 23) |
4215 (useable << 20) |
4216 (lm << 21) |
4217 0x7000;
4218
4219 /* Install the new entry ... */
4220install:
4221 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4222 lp[0] = tswap32(entry_1);
4223 lp[1] = tswap32(entry_2);
4224 return 0;
4225}
4226
blueswir18fcd3692008-08-17 20:26:25 +00004227static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004228{
4229 struct target_modify_ldt_ldt_s *target_ldt_info;
4230 uint64_t *gdt_table = g2h(env->gdt.base);
4231 uint32_t base_addr, limit, flags;
4232 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4233 int seg_not_present, useable, lm;
4234 uint32_t *lp, entry_1, entry_2;
4235
4236 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4237 if (!target_ldt_info)
4238 return -TARGET_EFAULT;
4239 idx = tswap32(target_ldt_info->entry_number);
4240 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4241 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4242 unlock_user_struct(target_ldt_info, ptr, 1);
4243 return -TARGET_EINVAL;
4244 }
4245 lp = (uint32_t *)(gdt_table + idx);
4246 entry_1 = tswap32(lp[0]);
4247 entry_2 = tswap32(lp[1]);
4248
4249 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4250 contents = (entry_2 >> 10) & 3;
4251 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4252 seg_32bit = (entry_2 >> 22) & 1;
4253 limit_in_pages = (entry_2 >> 23) & 1;
4254 useable = (entry_2 >> 20) & 1;
4255#ifdef TARGET_ABI32
4256 lm = 0;
4257#else
4258 lm = (entry_2 >> 21) & 1;
4259#endif
4260 flags = (seg_32bit << 0) | (contents << 1) |
4261 (read_exec_only << 3) | (limit_in_pages << 4) |
4262 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4263 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4264 base_addr = (entry_1 >> 16) |
4265 (entry_2 & 0xff000000) |
4266 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004267 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004268 target_ldt_info->limit = tswap32(limit);
4269 target_ldt_info->flags = tswap32(flags);
4270 unlock_user_struct(target_ldt_info, ptr, 1);
4271 return 0;
4272}
blueswir14583f582008-08-24 10:35:55 +00004273#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004274
bellardd2fd1af2007-11-14 18:08:56 +00004275#ifndef TARGET_ABI32
blueswir18fcd3692008-08-17 20:26:25 +00004276static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004277{
Juan Quintela1add8692011-06-16 17:37:09 +01004278 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004279 abi_ulong val;
4280 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004281
bellardd2fd1af2007-11-14 18:08:56 +00004282 switch(code) {
4283 case TARGET_ARCH_SET_GS:
4284 case TARGET_ARCH_SET_FS:
4285 if (code == TARGET_ARCH_SET_GS)
4286 idx = R_GS;
4287 else
4288 idx = R_FS;
4289 cpu_x86_load_seg(env, idx, 0);
4290 env->segs[idx].base = addr;
4291 break;
4292 case TARGET_ARCH_GET_GS:
4293 case TARGET_ARCH_GET_FS:
4294 if (code == TARGET_ARCH_GET_GS)
4295 idx = R_GS;
4296 else
4297 idx = R_FS;
4298 val = env->segs[idx].base;
4299 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004300 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004301 break;
4302 default:
4303 ret = -TARGET_EINVAL;
4304 break;
4305 }
Juan Quintela1add8692011-06-16 17:37:09 +01004306 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004307}
4308#endif
4309
bellard2ab83ea2003-06-15 19:56:46 +00004310#endif /* defined(TARGET_I386) */
4311
Riku Voipio05098a92011-03-04 15:27:29 +02004312#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004313
Riku Voipio05098a92011-03-04 15:27:29 +02004314#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004315
4316static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4317typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004318 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004319 pthread_mutex_t mutex;
4320 pthread_cond_t cond;
4321 pthread_t thread;
4322 uint32_t tid;
4323 abi_ulong child_tidptr;
4324 abi_ulong parent_tidptr;
4325 sigset_t sigmask;
4326} new_thread_info;
4327
4328static void *clone_func(void *arg)
4329{
4330 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004331 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004332 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004333 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004334
4335 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004336 cpu = ENV_GET_CPU(env);
pbrookd865bab2008-06-07 22:12:17 +00004337 thread_env = env;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004338 ts = (TaskState *)thread_env->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004339 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004340 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004341 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004342 if (info->child_tidptr)
4343 put_user_u32(info->tid, info->child_tidptr);
4344 if (info->parent_tidptr)
4345 put_user_u32(info->tid, info->parent_tidptr);
4346 /* Enable signals. */
4347 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4348 /* Signal to the parent that we're ready. */
4349 pthread_mutex_lock(&info->mutex);
4350 pthread_cond_broadcast(&info->cond);
4351 pthread_mutex_unlock(&info->mutex);
4352 /* Wait until the parent has finshed initializing the tls state. */
4353 pthread_mutex_lock(&clone_lock);
4354 pthread_mutex_unlock(&clone_lock);
4355 cpu_loop(env);
4356 /* never exits */
4357 return NULL;
4358}
4359#else
bellard1b6b0292003-03-22 17:31:38 +00004360
4361static int clone_func(void *arg)
4362{
Andreas Färber9349b4f2012-03-14 01:38:32 +01004363 CPUArchState *env = arg;
bellard1b6b0292003-03-22 17:31:38 +00004364 cpu_loop(env);
4365 /* never exits */
4366 return 0;
4367}
pbrookd865bab2008-06-07 22:12:17 +00004368#endif
bellard1b6b0292003-03-22 17:31:38 +00004369
ths0da46a62007-10-20 20:23:07 +00004370/* do_fork() Must return host values and target errnos (unlike most
4371 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004372static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004373 abi_ulong parent_tidptr, target_ulong newtls,
4374 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004375{
4376 int ret;
bellard5cd43932003-03-29 16:54:36 +00004377 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004378 CPUArchState *new_env;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004379#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004380 unsigned int nptl_flags;
4381 sigset_t sigmask;
Riku Voipio91907492010-11-26 16:21:34 +02004382#else
4383 uint8_t *new_stack;
pbrookd865bab2008-06-07 22:12:17 +00004384#endif
ths3b46e622007-09-17 08:09:54 +00004385
balrog436d1242008-09-21 02:39:45 +00004386 /* Emulate vfork() with fork() */
4387 if (flags & CLONE_VFORK)
4388 flags &= ~(CLONE_VFORK | CLONE_VM);
4389
bellard1b6b0292003-03-22 17:31:38 +00004390 if (flags & CLONE_VM) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004391 TaskState *parent_ts = (TaskState *)env->opaque;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004392#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004393 new_thread_info info;
4394 pthread_attr_t attr;
pbrookbd0c5662008-05-29 14:34:11 +00004395#endif
Anthony Liguori7267c092011-08-20 22:09:37 -05004396 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004397 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004398 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004399 new_env = cpu_copy(env);
Blue Swirlb4558d72009-11-07 16:34:12 +00004400#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
Andreas Färberff18b762012-05-05 14:47:34 +02004401 cpu_reset(ENV_GET_CPU(new_env));
Blue Swirlb4558d72009-11-07 16:34:12 +00004402#endif
pbrook6e68e072008-05-30 17:22:15 +00004403 /* Init regs that differ from the parent. */
4404 cpu_clone_regs(new_env, newsp);
bellard5cd43932003-03-29 16:54:36 +00004405 new_env->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004406 ts->bprm = parent_ts->bprm;
4407 ts->info = parent_ts->info;
Juan Quintela2f7bb872009-07-27 16:13:24 +02004408#if defined(CONFIG_USE_NPTL)
pbrookd865bab2008-06-07 22:12:17 +00004409 nptl_flags = flags;
4410 flags &= ~CLONE_NPTL_FLAGS2;
4411
pbrookc2764712009-03-07 15:24:59 +00004412 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4413 ts->child_tidptr = child_tidptr;
4414 }
4415
pbrookd865bab2008-06-07 22:12:17 +00004416 if (nptl_flags & CLONE_SETTLS)
4417 cpu_set_tls (new_env, newtls);
4418
4419 /* Grab a mutex so that thread setup appears atomic. */
4420 pthread_mutex_lock(&clone_lock);
4421
4422 memset(&info, 0, sizeof(info));
4423 pthread_mutex_init(&info.mutex, NULL);
4424 pthread_mutex_lock(&info.mutex);
4425 pthread_cond_init(&info.cond, NULL);
4426 info.env = new_env;
4427 if (nptl_flags & CLONE_CHILD_SETTID)
4428 info.child_tidptr = child_tidptr;
4429 if (nptl_flags & CLONE_PARENT_SETTID)
4430 info.parent_tidptr = parent_tidptr;
4431
4432 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004433 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4434 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004435 /* It is not safe to deliver signals until the child has finished
4436 initializing, so temporarily block all signals. */
4437 sigfillset(&sigmask);
4438 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4439
4440 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004441 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004442
4443 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4444 pthread_attr_destroy(&attr);
4445 if (ret == 0) {
4446 /* Wait for the child to initialize. */
4447 pthread_cond_wait(&info.cond, &info.mutex);
4448 ret = info.tid;
4449 if (flags & CLONE_PARENT_SETTID)
4450 put_user_u32(ret, parent_tidptr);
4451 } else {
4452 ret = -1;
4453 }
4454 pthread_mutex_unlock(&info.mutex);
4455 pthread_cond_destroy(&info.cond);
4456 pthread_mutex_destroy(&info.mutex);
4457 pthread_mutex_unlock(&clone_lock);
4458#else
4459 if (flags & CLONE_NPTL_FLAGS2)
4460 return -EINVAL;
4461 /* This is probably going to die very quickly, but do it anyway. */
Anthony Liguori7267c092011-08-20 22:09:37 -05004462 new_stack = g_malloc0 (NEW_STACK_SIZE);
bellard27725c12003-04-29 21:08:18 +00004463#ifdef __ia64__
Aurelien Jarno60e99242010-03-29 02:12:51 +02004464 ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
bellard27725c12003-04-29 21:08:18 +00004465#else
4466 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
4467#endif
pbrookd865bab2008-06-07 22:12:17 +00004468#endif
bellard1b6b0292003-03-22 17:31:38 +00004469 } else {
4470 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004471 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004472 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004473 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004474 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004475 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004476 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004477 cpu_clone_regs(env, newsp);
4478 fork_end(1);
Juan Quintela2f7bb872009-07-27 16:13:24 +02004479#if defined(CONFIG_USE_NPTL)
aurel322b1319c2008-12-18 22:44:04 +00004480 /* There is a race condition here. The parent process could
4481 theoretically read the TID in the child process before the child
4482 tid is set. This would require using either ptrace
4483 (not implemented) or having *_tidptr to point at a shared memory
4484 mapping. We can't repeat the spinlock hack used above because
4485 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004486 if (flags & CLONE_CHILD_SETTID)
4487 put_user_u32(gettid(), child_tidptr);
4488 if (flags & CLONE_PARENT_SETTID)
4489 put_user_u32(gettid(), parent_tidptr);
4490 ts = (TaskState *)env->opaque;
4491 if (flags & CLONE_SETTLS)
4492 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004493 if (flags & CLONE_CHILD_CLEARTID)
4494 ts->child_tidptr = child_tidptr;
aurel322b1319c2008-12-18 22:44:04 +00004495#endif
pbrookd865bab2008-06-07 22:12:17 +00004496 } else {
4497 fork_end(0);
4498 }
bellard1b6b0292003-03-22 17:31:38 +00004499 }
4500 return ret;
4501}
4502
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004503/* warning : doesn't handle linux specific flags... */
4504static int target_to_host_fcntl_cmd(int cmd)
4505{
4506 switch(cmd) {
4507 case TARGET_F_DUPFD:
4508 case TARGET_F_GETFD:
4509 case TARGET_F_SETFD:
4510 case TARGET_F_GETFL:
4511 case TARGET_F_SETFL:
4512 return cmd;
4513 case TARGET_F_GETLK:
4514 return F_GETLK;
4515 case TARGET_F_SETLK:
4516 return F_SETLK;
4517 case TARGET_F_SETLKW:
4518 return F_SETLKW;
4519 case TARGET_F_GETOWN:
4520 return F_GETOWN;
4521 case TARGET_F_SETOWN:
4522 return F_SETOWN;
4523 case TARGET_F_GETSIG:
4524 return F_GETSIG;
4525 case TARGET_F_SETSIG:
4526 return F_SETSIG;
4527#if TARGET_ABI_BITS == 32
4528 case TARGET_F_GETLK64:
4529 return F_GETLK64;
4530 case TARGET_F_SETLK64:
4531 return F_SETLK64;
4532 case TARGET_F_SETLKW64:
4533 return F_SETLKW64;
4534#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004535 case TARGET_F_SETLEASE:
4536 return F_SETLEASE;
4537 case TARGET_F_GETLEASE:
4538 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004539#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004540 case TARGET_F_DUPFD_CLOEXEC:
4541 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004542#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004543 case TARGET_F_NOTIFY:
4544 return F_NOTIFY;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004545 default:
4546 return -TARGET_EINVAL;
4547 }
4548 return -TARGET_EINVAL;
4549}
4550
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004551#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4552static const bitmask_transtbl flock_tbl[] = {
4553 TRANSTBL_CONVERT(F_RDLCK),
4554 TRANSTBL_CONVERT(F_WRLCK),
4555 TRANSTBL_CONVERT(F_UNLCK),
4556 TRANSTBL_CONVERT(F_EXLCK),
4557 TRANSTBL_CONVERT(F_SHLCK),
4558 { 0, 0, 0, 0 }
4559};
4560
blueswir1992f48a2007-10-14 16:27:31 +00004561static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004562{
4563 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004564 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004565 struct flock64 fl64;
4566 struct target_flock64 *target_fl64;
blueswir1992f48a2007-10-14 16:27:31 +00004567 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004568 int host_cmd = target_to_host_fcntl_cmd(cmd);
4569
4570 if (host_cmd == -TARGET_EINVAL)
4571 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004572
bellard7775e9e2003-05-14 22:46:48 +00004573 switch(cmd) {
4574 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004575 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4576 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004577 fl.l_type =
4578 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004579 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004580 fl.l_start = tswapal(target_fl->l_start);
4581 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004582 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004583 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004584 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004585 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004586 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4587 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004588 target_fl->l_type =
4589 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004590 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004591 target_fl->l_start = tswapal(fl.l_start);
4592 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004593 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004594 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004595 }
4596 break;
ths3b46e622007-09-17 08:09:54 +00004597
bellard7775e9e2003-05-14 22:46:48 +00004598 case TARGET_F_SETLK:
4599 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004600 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4601 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004602 fl.l_type =
4603 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004604 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004605 fl.l_start = tswapal(target_fl->l_start);
4606 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004607 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004608 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004609 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004610 break;
ths3b46e622007-09-17 08:09:54 +00004611
bellard7775e9e2003-05-14 22:46:48 +00004612 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004613 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4614 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004615 fl64.l_type =
4616 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004617 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004618 fl64.l_start = tswap64(target_fl64->l_start);
4619 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004620 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004621 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004622 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004623 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004624 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4625 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004626 target_fl64->l_type =
4627 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004628 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004629 target_fl64->l_start = tswap64(fl64.l_start);
4630 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004631 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004632 unlock_user_struct(target_fl64, arg, 1);
4633 }
bellard9ee1fa22007-11-11 15:11:19 +00004634 break;
bellard7775e9e2003-05-14 22:46:48 +00004635 case TARGET_F_SETLK64:
4636 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004637 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4638 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004639 fl64.l_type =
4640 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004641 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004642 fl64.l_start = tswap64(target_fl64->l_start);
4643 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004644 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004645 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004646 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004647 break;
4648
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004649 case TARGET_F_GETFL:
4650 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004651 if (ret >= 0) {
4652 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4653 }
bellardffa65c32004-01-04 23:57:22 +00004654 break;
4655
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004656 case TARGET_F_SETFL:
4657 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4658 break;
4659
4660 case TARGET_F_SETOWN:
4661 case TARGET_F_GETOWN:
4662 case TARGET_F_SETSIG:
4663 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004664 case TARGET_F_SETLEASE:
4665 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004666 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004667 break;
4668
bellard7775e9e2003-05-14 22:46:48 +00004669 default:
bellard9ee1fa22007-11-11 15:11:19 +00004670 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004671 break;
4672 }
4673 return ret;
4674}
4675
bellard67867302003-11-23 17:05:30 +00004676#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004677
bellard67867302003-11-23 17:05:30 +00004678static inline int high2lowuid(int uid)
4679{
4680 if (uid > 65535)
4681 return 65534;
4682 else
4683 return uid;
4684}
4685
4686static inline int high2lowgid(int gid)
4687{
4688 if (gid > 65535)
4689 return 65534;
4690 else
4691 return gid;
4692}
4693
4694static inline int low2highuid(int uid)
4695{
4696 if ((int16_t)uid == -1)
4697 return -1;
4698 else
4699 return uid;
4700}
4701
4702static inline int low2highgid(int gid)
4703{
4704 if ((int16_t)gid == -1)
4705 return -1;
4706 else
4707 return gid;
4708}
Riku Voipio0c866a72011-04-18 15:23:06 +03004709static inline int tswapid(int id)
4710{
4711 return tswap16(id);
4712}
4713#else /* !USE_UID16 */
4714static inline int high2lowuid(int uid)
4715{
4716 return uid;
4717}
4718static inline int high2lowgid(int gid)
4719{
4720 return gid;
4721}
4722static inline int low2highuid(int uid)
4723{
4724 return uid;
4725}
4726static inline int low2highgid(int gid)
4727{
4728 return gid;
4729}
4730static inline int tswapid(int id)
4731{
4732 return tswap32(id);
4733}
bellard67867302003-11-23 17:05:30 +00004734#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004735
bellard31e31b82003-02-18 22:55:36 +00004736void syscall_init(void)
4737{
bellard2ab83ea2003-06-15 19:56:46 +00004738 IOCTLEntry *ie;
4739 const argtype *arg_type;
4740 int size;
thsb92c47c2007-11-01 00:07:38 +00004741 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004742
Blue Swirl001faf32009-05-13 17:53:17 +00004743#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004744#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004745#include "syscall_types.h"
4746#undef STRUCT
4747#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004748
Peter Maydelldd6e9572012-07-23 08:07:22 +00004749 /* Build target_to_host_errno_table[] table from
4750 * host_to_target_errno_table[]. */
4751 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4752 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4753 }
4754
bellard2ab83ea2003-06-15 19:56:46 +00004755 /* we patch the ioctl size if necessary. We rely on the fact that
4756 no ioctl has all the bits at '1' in the size field */
4757 ie = ioctl_entries;
4758 while (ie->target_cmd != 0) {
4759 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4760 TARGET_IOC_SIZEMASK) {
4761 arg_type = ie->arg_type;
4762 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004763 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004764 ie->target_cmd);
4765 exit(1);
4766 }
4767 arg_type++;
4768 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004769 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004770 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4771 (size << TARGET_IOC_SIZESHIFT);
4772 }
thsb92c47c2007-11-01 00:07:38 +00004773
bellard2ab83ea2003-06-15 19:56:46 +00004774 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004775#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4776 (defined(__x86_64__) && defined(TARGET_X86_64))
4777 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4778 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4779 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004780 }
4781#endif
4782 ie++;
4783 }
bellard31e31b82003-02-18 22:55:36 +00004784}
bellardc573ff62004-01-04 15:51:36 +00004785
blueswir1992f48a2007-10-14 16:27:31 +00004786#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004787static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4788{
thsaf325d32008-06-10 15:29:15 +00004789#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004790 return ((uint64_t)word0 << 32) | word1;
4791#else
4792 return ((uint64_t)word1 << 32) | word0;
4793#endif
4794}
blueswir1992f48a2007-10-14 16:27:31 +00004795#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004796static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4797{
4798 return word0;
4799}
blueswir1992f48a2007-10-14 16:27:31 +00004800#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004801
4802#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004803static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4804 abi_long arg2,
4805 abi_long arg3,
4806 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004807{
Riku Voipio48e515d2011-07-12 15:40:51 +03004808 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004809 arg2 = arg3;
4810 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004811 }
pbrookce4defa2006-02-09 16:49:55 +00004812 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4813}
4814#endif
4815
4816#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004817static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4818 abi_long arg2,
4819 abi_long arg3,
4820 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004821{
Riku Voipio48e515d2011-07-12 15:40:51 +03004822 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004823 arg2 = arg3;
4824 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004825 }
pbrookce4defa2006-02-09 16:49:55 +00004826 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4827}
4828#endif
4829
bellard579a97f2007-11-11 14:26:47 +00004830static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4831 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004832{
4833 struct target_timespec *target_ts;
4834
bellard579a97f2007-11-11 14:26:47 +00004835 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4836 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004837 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4838 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004839 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004840 return 0;
pbrook53a59602006-03-25 19:31:22 +00004841}
4842
bellard579a97f2007-11-11 14:26:47 +00004843static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4844 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004845{
4846 struct target_timespec *target_ts;
4847
bellard579a97f2007-11-11 14:26:47 +00004848 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4849 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004850 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4851 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004852 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004853 return 0;
pbrook53a59602006-03-25 19:31:22 +00004854}
4855
aurel329d33b762009-04-08 23:07:05 +00004856#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004857static inline abi_long host_to_target_stat64(void *cpu_env,
4858 abi_ulong target_addr,
4859 struct stat *host_st)
4860{
4861#ifdef TARGET_ARM
4862 if (((CPUARMState *)cpu_env)->eabi) {
4863 struct target_eabi_stat64 *target_st;
4864
4865 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4866 return -TARGET_EFAULT;
4867 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4868 __put_user(host_st->st_dev, &target_st->st_dev);
4869 __put_user(host_st->st_ino, &target_st->st_ino);
4870#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4871 __put_user(host_st->st_ino, &target_st->__st_ino);
4872#endif
4873 __put_user(host_st->st_mode, &target_st->st_mode);
4874 __put_user(host_st->st_nlink, &target_st->st_nlink);
4875 __put_user(host_st->st_uid, &target_st->st_uid);
4876 __put_user(host_st->st_gid, &target_st->st_gid);
4877 __put_user(host_st->st_rdev, &target_st->st_rdev);
4878 __put_user(host_st->st_size, &target_st->st_size);
4879 __put_user(host_st->st_blksize, &target_st->st_blksize);
4880 __put_user(host_st->st_blocks, &target_st->st_blocks);
4881 __put_user(host_st->st_atime, &target_st->target_st_atime);
4882 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4883 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4884 unlock_user_struct(target_st, target_addr, 1);
4885 } else
4886#endif
4887 {
Richard Hendersoned18c5c2010-04-26 10:27:22 -07004888#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
aurel329d33b762009-04-08 23:07:05 +00004889 struct target_stat *target_st;
4890#else
balrog6a24a772008-09-20 02:23:36 +00004891 struct target_stat64 *target_st;
aurel329d33b762009-04-08 23:07:05 +00004892#endif
balrog6a24a772008-09-20 02:23:36 +00004893
4894 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4895 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004896 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004897 __put_user(host_st->st_dev, &target_st->st_dev);
4898 __put_user(host_st->st_ino, &target_st->st_ino);
4899#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4900 __put_user(host_st->st_ino, &target_st->__st_ino);
4901#endif
4902 __put_user(host_st->st_mode, &target_st->st_mode);
4903 __put_user(host_st->st_nlink, &target_st->st_nlink);
4904 __put_user(host_st->st_uid, &target_st->st_uid);
4905 __put_user(host_st->st_gid, &target_st->st_gid);
4906 __put_user(host_st->st_rdev, &target_st->st_rdev);
4907 /* XXX: better use of kernel struct */
4908 __put_user(host_st->st_size, &target_st->st_size);
4909 __put_user(host_st->st_blksize, &target_st->st_blksize);
4910 __put_user(host_st->st_blocks, &target_st->st_blocks);
4911 __put_user(host_st->st_atime, &target_st->target_st_atime);
4912 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4913 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4914 unlock_user_struct(target_st, target_addr, 1);
4915 }
4916
4917 return 0;
4918}
4919#endif
4920
Juan Quintela2f7bb872009-07-27 16:13:24 +02004921#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00004922/* ??? Using host futex calls even when target atomic operations
4923 are not really atomic probably breaks things. However implementing
4924 futexes locally would make futexes shared between multiple processes
4925 tricky. However they're probably useless because guest atomic
4926 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004927static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4928 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004929{
4930 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004931 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004932
4933 /* ??? We assume FUTEX_* constants are the same on both host
4934 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004935#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004936 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004937#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004938 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004939#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004940 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004941 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004942 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004943 if (timeout) {
4944 pts = &ts;
4945 target_to_host_timespec(pts, timeout);
4946 } else {
4947 pts = NULL;
4948 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004949 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004950 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004951 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004952 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004953 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004954 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004955 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004956 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004957 case FUTEX_WAKE_OP:
4958 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4959 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4960 But the prototype takes a `struct timespec *'; insert casts
4961 to satisfy the compiler. We do not need to tswap TIMEOUT
4962 since it's not compared to guest memory. */
4963 pts = (struct timespec *)(uintptr_t) timeout;
4964 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4965 g2h(uaddr2),
4966 (base_op == FUTEX_CMP_REQUEUE
4967 ? tswap32(val3)
4968 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004969 default:
4970 return -TARGET_ENOSYS;
4971 }
4972}
4973#endif
4974
pbrook1d9d8b52009-04-16 15:17:02 +00004975/* Map host to target signal numbers for the wait family of syscalls.
4976 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004977int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004978{
4979 if (WIFSIGNALED(status)) {
4980 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4981 }
4982 if (WIFSTOPPED(status)) {
4983 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4984 | (status & 0xff);
4985 }
4986 return status;
4987}
4988
pbrooka745ec62008-05-06 15:36:17 +00004989int get_osversion(void)
4990{
4991 static int osversion;
4992 struct new_utsname buf;
4993 const char *s;
4994 int i, n, tmp;
4995 if (osversion)
4996 return osversion;
4997 if (qemu_uname_release && *qemu_uname_release) {
4998 s = qemu_uname_release;
4999 } else {
5000 if (sys_uname(&buf))
5001 return 0;
5002 s = buf.release;
5003 }
5004 tmp = 0;
5005 for (i = 0; i < 3; i++) {
5006 n = 0;
5007 while (*s >= '0' && *s <= '9') {
5008 n *= 10;
5009 n += *s - '0';
5010 s++;
5011 }
5012 tmp = (tmp << 8) + n;
5013 if (*s == '.')
5014 s++;
5015 }
5016 osversion = tmp;
5017 return osversion;
5018}
5019
Alexander Graf36c08d42011-11-02 20:23:24 +01005020
5021static int open_self_maps(void *cpu_env, int fd)
5022{
Alexander Graf1a49ef22012-05-01 16:30:28 +01005023#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber9349b4f2012-03-14 01:38:32 +01005024 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005025#endif
5026 FILE *fp;
5027 char *line = NULL;
5028 size_t len = 0;
5029 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005030
Alexander Graf1a49ef22012-05-01 16:30:28 +01005031 fp = fopen("/proc/self/maps", "r");
5032 if (fp == NULL) {
5033 return -EACCES;
5034 }
5035
5036 while ((read = getline(&line, &len, fp)) != -1) {
5037 int fields, dev_maj, dev_min, inode;
5038 uint64_t min, max, offset;
5039 char flag_r, flag_w, flag_x, flag_p;
5040 char path[512] = "";
5041 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5042 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5043 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5044
5045 if ((fields < 10) || (fields > 11)) {
5046 continue;
5047 }
5048 if (!strncmp(path, "[stack]", 7)) {
5049 continue;
5050 }
5051 if (h2g_valid(min) && h2g_valid(max)) {
5052 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
5053 " %c%c%c%c %08" PRIx64 " %02x:%02x %d%s%s\n",
5054 h2g(min), h2g(max), flag_r, flag_w,
5055 flag_x, flag_p, offset, dev_maj, dev_min, inode,
5056 path[0] ? " " : "", path);
5057 }
5058 }
5059
5060 free(line);
5061 fclose(fp);
5062
5063#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005064 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5065 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005066 (unsigned long long)(ts->info->start_stack +
5067 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005068 (unsigned long long)0);
5069#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005070
5071 return 0;
5072}
5073
Alexander Graf480b8e72011-11-02 20:23:25 +01005074static int open_self_stat(void *cpu_env, int fd)
5075{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005076 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005077 abi_ulong start_stack = ts->info->start_stack;
5078 int i;
5079
5080 for (i = 0; i < 44; i++) {
5081 char buf[128];
5082 int len;
5083 uint64_t val = 0;
5084
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005085 if (i == 0) {
5086 /* pid */
5087 val = getpid();
5088 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5089 } else if (i == 1) {
5090 /* app name */
5091 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5092 } else if (i == 27) {
5093 /* stack bottom */
5094 val = start_stack;
5095 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5096 } else {
5097 /* for the rest, there is MasterCard */
5098 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005099 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005100
Alexander Graf480b8e72011-11-02 20:23:25 +01005101 len = strlen(buf);
5102 if (write(fd, buf, len) != len) {
5103 return -1;
5104 }
5105 }
5106
5107 return 0;
5108}
5109
Alexander Graf257450e2011-11-02 20:23:26 +01005110static int open_self_auxv(void *cpu_env, int fd)
5111{
Andreas Färber9349b4f2012-03-14 01:38:32 +01005112 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005113 abi_ulong auxv = ts->info->saved_auxv;
5114 abi_ulong len = ts->info->auxv_len;
5115 char *ptr;
5116
5117 /*
5118 * Auxiliary vector is stored in target process stack.
5119 * read in whole auxv vector and copy it to file
5120 */
5121 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5122 if (ptr != NULL) {
5123 while (len > 0) {
5124 ssize_t r;
5125 r = write(fd, ptr, len);
5126 if (r <= 0) {
5127 break;
5128 }
5129 len -= r;
5130 ptr += r;
5131 }
5132 lseek(fd, 0, SEEK_SET);
5133 unlock_user(ptr, auxv, len);
5134 }
5135
5136 return 0;
5137}
5138
Alexander Graf3be14d02011-11-02 20:23:23 +01005139static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5140{
5141 struct fake_open {
5142 const char *filename;
5143 int (*fill)(void *cpu_env, int fd);
5144 };
5145 const struct fake_open *fake_open;
5146 static const struct fake_open fakes[] = {
Alexander Graf36c08d42011-11-02 20:23:24 +01005147 { "/proc/self/maps", open_self_maps },
Alexander Graf480b8e72011-11-02 20:23:25 +01005148 { "/proc/self/stat", open_self_stat },
Alexander Graf257450e2011-11-02 20:23:26 +01005149 { "/proc/self/auxv", open_self_auxv },
Alexander Graf3be14d02011-11-02 20:23:23 +01005150 { NULL, NULL }
5151 };
5152
5153 for (fake_open = fakes; fake_open->filename; fake_open++) {
5154 if (!strncmp(pathname, fake_open->filename,
5155 strlen(fake_open->filename))) {
5156 break;
5157 }
5158 }
5159
5160 if (fake_open->filename) {
5161 const char *tmpdir;
5162 char filename[PATH_MAX];
5163 int fd, r;
5164
5165 /* create temporary file to map stat to */
5166 tmpdir = getenv("TMPDIR");
5167 if (!tmpdir)
5168 tmpdir = "/tmp";
5169 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5170 fd = mkstemp(filename);
5171 if (fd < 0) {
5172 return fd;
5173 }
5174 unlink(filename);
5175
5176 if ((r = fake_open->fill(cpu_env, fd))) {
5177 close(fd);
5178 return r;
5179 }
5180 lseek(fd, 0, SEEK_SET);
5181
5182 return fd;
5183 }
5184
5185 return get_errno(open(path(pathname), flags, mode));
5186}
5187
ths0da46a62007-10-20 20:23:07 +00005188/* do_syscall() should always have a single exit point at the end so
5189 that actions, such as logging of syscall results, can be performed.
5190 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005191abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5192 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005193 abi_long arg5, abi_long arg6, abi_long arg7,
5194 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005195{
blueswir1992f48a2007-10-14 16:27:31 +00005196 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005197 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005198 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005199 void *p;
ths3b46e622007-09-17 08:09:54 +00005200
bellard72f03902003-02-18 23:33:18 +00005201#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005202 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005203#endif
thsb92c47c2007-11-01 00:07:38 +00005204 if(do_strace)
5205 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5206
bellard31e31b82003-02-18 22:55:36 +00005207 switch(num) {
5208 case TARGET_NR_exit:
Juan Quintela2f7bb872009-07-27 16:13:24 +02005209#ifdef CONFIG_USE_NPTL
pbrookc2764712009-03-07 15:24:59 +00005210 /* In old applications this may be used to implement _exit(2).
5211 However in threaded applictions it is used for thread termination,
5212 and _exit_group is used for application termination.
5213 Do thread termination if we have more then one thread. */
5214 /* FIXME: This probably breaks if a signal arrives. We should probably
5215 be disabling signals. */
5216 if (first_cpu->next_cpu) {
Nathan Froyd1e9fa732009-06-03 11:33:08 -07005217 TaskState *ts;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005218 CPUArchState **lastp;
5219 CPUArchState *p;
pbrookc2764712009-03-07 15:24:59 +00005220
5221 cpu_list_lock();
5222 lastp = &first_cpu;
5223 p = first_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005224 while (p && p != (CPUArchState *)cpu_env) {
pbrookc2764712009-03-07 15:24:59 +00005225 lastp = &p->next_cpu;
5226 p = p->next_cpu;
5227 }
5228 /* If we didn't find the CPU for this thread then something is
5229 horribly wrong. */
5230 if (!p)
5231 abort();
5232 /* Remove the CPU from the list. */
5233 *lastp = p->next_cpu;
5234 cpu_list_unlock();
Andreas Färber9349b4f2012-03-14 01:38:32 +01005235 ts = ((CPUArchState *)cpu_env)->opaque;
pbrookc2764712009-03-07 15:24:59 +00005236 if (ts->child_tidptr) {
5237 put_user_u32(0, ts->child_tidptr);
5238 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5239 NULL, NULL, 0);
5240 }
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005241 thread_env = NULL;
Paolo Bonzini5c099532013-01-25 14:12:38 +01005242 object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
Anthony Liguori7267c092011-08-20 22:09:37 -05005243 g_free(ts);
pbrookc2764712009-03-07 15:24:59 +00005244 pthread_exit(NULL);
5245 }
5246#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +02005247#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005248 _mcleanup();
5249#endif
bellarde9009672005-04-26 20:42:36 +00005250 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005251 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005252 ret = 0; /* avoid warning */
5253 break;
5254 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005255 if (arg3 == 0)
5256 ret = 0;
5257 else {
5258 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5259 goto efault;
5260 ret = get_errno(read(arg1, p, arg3));
5261 unlock_user(p, arg2, ret);
5262 }
bellard31e31b82003-02-18 22:55:36 +00005263 break;
5264 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005265 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5266 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005267 ret = get_errno(write(arg1, p, arg3));
5268 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005269 break;
5270 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005271 if (!(p = lock_user_string(arg1)))
5272 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005273 ret = get_errno(do_open(cpu_env, p,
5274 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5275 arg3));
pbrook53a59602006-03-25 19:31:22 +00005276 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005277 break;
ths82424832007-09-24 09:21:55 +00005278#if defined(TARGET_NR_openat) && defined(__NR_openat)
5279 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005280 if (!(p = lock_user_string(arg2)))
5281 goto efault;
5282 ret = get_errno(sys_openat(arg1,
5283 path(p),
5284 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5285 arg4));
5286 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005287 break;
5288#endif
bellard31e31b82003-02-18 22:55:36 +00005289 case TARGET_NR_close:
5290 ret = get_errno(close(arg1));
5291 break;
5292 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005293 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005294 break;
5295 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005296 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005297 break;
thse5febef2007-04-01 18:31:35 +00005298#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005299 case TARGET_NR_waitpid:
5300 {
pbrook53a59602006-03-25 19:31:22 +00005301 int status;
5302 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005303 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005304 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005305 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005306 }
5307 break;
thse5febef2007-04-01 18:31:35 +00005308#endif
pbrookf0cbb612008-05-30 18:20:05 +00005309#ifdef TARGET_NR_waitid
5310 case TARGET_NR_waitid:
5311 {
5312 siginfo_t info;
5313 info.si_pid = 0;
5314 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5315 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005316 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005317 goto efault;
5318 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005319 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005320 }
5321 }
5322 break;
5323#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005324#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005325 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005326 if (!(p = lock_user_string(arg1)))
5327 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005328 ret = get_errno(creat(p, arg2));
5329 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005330 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005331#endif
bellard31e31b82003-02-18 22:55:36 +00005332 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005333 {
5334 void * p2;
5335 p = lock_user_string(arg1);
5336 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005337 if (!p || !p2)
5338 ret = -TARGET_EFAULT;
5339 else
5340 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005341 unlock_user(p2, arg2, 0);
5342 unlock_user(p, arg1, 0);
5343 }
bellard31e31b82003-02-18 22:55:36 +00005344 break;
ths64f0ce42007-09-24 09:25:06 +00005345#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
5346 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005347 {
5348 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005349 if (!arg2 || !arg4)
5350 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005351 p = lock_user_string(arg2);
5352 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005353 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005354 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005355 else
5356 ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005357 unlock_user(p, arg2, 0);
5358 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005359 }
5360 break;
5361#endif
bellard31e31b82003-02-18 22:55:36 +00005362 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005363 if (!(p = lock_user_string(arg1)))
5364 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005365 ret = get_errno(unlink(p));
5366 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005367 break;
ths8170f562007-09-24 09:24:11 +00005368#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
5369 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005370 if (!(p = lock_user_string(arg2)))
5371 goto efault;
5372 ret = get_errno(sys_unlinkat(arg1, p, arg3));
5373 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005374 break;
balrogb7d35e62007-12-12 00:40:24 +00005375#endif
bellard31e31b82003-02-18 22:55:36 +00005376 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005377 {
5378 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005379 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005380 abi_ulong gp;
5381 abi_ulong guest_argp;
5382 abi_ulong guest_envp;
5383 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005384 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005385 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005386
bellardf7341ff2003-03-30 21:00:25 +00005387 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005388 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005389 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005390 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005391 goto efault;
ths03aa1972007-12-02 06:28:08 +00005392 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005393 break;
bellard7854b052003-03-29 17:22:23 +00005394 argc++;
bellard2f619692007-11-16 10:46:05 +00005395 }
bellardf7341ff2003-03-30 21:00:25 +00005396 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005397 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005398 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005399 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005400 goto efault;
ths03aa1972007-12-02 06:28:08 +00005401 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005402 break;
bellard7854b052003-03-29 17:22:23 +00005403 envc++;
bellard2f619692007-11-16 10:46:05 +00005404 }
bellard7854b052003-03-29 17:22:23 +00005405
bellardf7341ff2003-03-30 21:00:25 +00005406 argp = alloca((argc + 1) * sizeof(void *));
5407 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005408
pbrookda94d262008-05-30 18:24:00 +00005409 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005410 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005411 if (get_user_ual(addr, gp))
5412 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005413 if (!addr)
5414 break;
bellard2f619692007-11-16 10:46:05 +00005415 if (!(*q = lock_user_string(addr)))
5416 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005417 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005418 }
bellardf7341ff2003-03-30 21:00:25 +00005419 *q = NULL;
5420
pbrookda94d262008-05-30 18:24:00 +00005421 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005422 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005423 if (get_user_ual(addr, gp))
5424 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005425 if (!addr)
5426 break;
bellard2f619692007-11-16 10:46:05 +00005427 if (!(*q = lock_user_string(addr)))
5428 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005429 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005430 }
bellardf7341ff2003-03-30 21:00:25 +00005431 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005432
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005433 /* This case will not be caught by the host's execve() if its
5434 page size is bigger than the target's. */
5435 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5436 ret = -TARGET_E2BIG;
5437 goto execve_end;
5438 }
bellard2f619692007-11-16 10:46:05 +00005439 if (!(p = lock_user_string(arg1)))
5440 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005441 ret = get_errno(execve(p, argp, envp));
5442 unlock_user(p, arg1, 0);
5443
bellard2f619692007-11-16 10:46:05 +00005444 goto execve_end;
5445
5446 execve_efault:
5447 ret = -TARGET_EFAULT;
5448
5449 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005450 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005451 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005452 if (get_user_ual(addr, gp)
5453 || !addr)
5454 break;
pbrook53a59602006-03-25 19:31:22 +00005455 unlock_user(*q, addr, 0);
5456 }
5457 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005458 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005459 if (get_user_ual(addr, gp)
5460 || !addr)
5461 break;
pbrook53a59602006-03-25 19:31:22 +00005462 unlock_user(*q, addr, 0);
5463 }
bellard7854b052003-03-29 17:22:23 +00005464 }
bellard31e31b82003-02-18 22:55:36 +00005465 break;
5466 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005467 if (!(p = lock_user_string(arg1)))
5468 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005469 ret = get_errno(chdir(p));
5470 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005471 break;
bellarda315a142005-01-30 22:59:18 +00005472#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005473 case TARGET_NR_time:
5474 {
pbrook53a59602006-03-25 19:31:22 +00005475 time_t host_time;
5476 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005477 if (!is_error(ret)
5478 && arg1
5479 && put_user_sal(host_time, arg1))
5480 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005481 }
5482 break;
bellarda315a142005-01-30 22:59:18 +00005483#endif
bellard31e31b82003-02-18 22:55:36 +00005484 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005485 if (!(p = lock_user_string(arg1)))
5486 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005487 ret = get_errno(mknod(p, arg2, arg3));
5488 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005489 break;
ths75ac37a2007-09-24 09:23:05 +00005490#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
5491 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005492 if (!(p = lock_user_string(arg2)))
5493 goto efault;
5494 ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
5495 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005496 break;
5497#endif
bellard31e31b82003-02-18 22:55:36 +00005498 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005499 if (!(p = lock_user_string(arg1)))
5500 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005501 ret = get_errno(chmod(p, arg2));
5502 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005503 break;
bellardebc05482003-09-30 21:08:41 +00005504#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005505 case TARGET_NR_break:
5506 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005507#endif
5508#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005509 case TARGET_NR_oldstat:
5510 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005511#endif
bellard31e31b82003-02-18 22:55:36 +00005512 case TARGET_NR_lseek:
5513 ret = get_errno(lseek(arg1, arg2, arg3));
5514 break;
Richard Henderson92317332010-05-03 10:07:53 -07005515#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5516 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005517 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005518 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005519 ret = get_errno(getpid());
5520 break;
Richard Henderson92317332010-05-03 10:07:53 -07005521#endif
5522#ifdef TARGET_NR_getpid
5523 case TARGET_NR_getpid:
5524 ret = get_errno(getpid());
5525 break;
5526#endif
bellard31e31b82003-02-18 22:55:36 +00005527 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005528 {
5529 /* need to look at the data field */
5530 void *p2, *p3;
5531 p = lock_user_string(arg1);
5532 p2 = lock_user_string(arg2);
5533 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005534 if (!p || !p2 || !p3)
5535 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005536 else {
bellard579a97f2007-11-11 14:26:47 +00005537 /* FIXME - arg5 should be locked, but it isn't clear how to
5538 * do that since it's not guaranteed to be a NULL-terminated
5539 * string.
5540 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005541 if ( ! arg5 )
5542 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5543 else
5544 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5545 }
bellard579a97f2007-11-11 14:26:47 +00005546 unlock_user(p, arg1, 0);
5547 unlock_user(p2, arg2, 0);
5548 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005549 break;
5550 }
thse5febef2007-04-01 18:31:35 +00005551#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005552 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005553 if (!(p = lock_user_string(arg1)))
5554 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005555 ret = get_errno(umount(p));
5556 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005557 break;
thse5febef2007-04-01 18:31:35 +00005558#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005559#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005560 case TARGET_NR_stime:
5561 {
pbrook53a59602006-03-25 19:31:22 +00005562 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005563 if (get_user_sal(host_time, arg1))
5564 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005565 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005566 }
5567 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005568#endif
bellard31e31b82003-02-18 22:55:36 +00005569 case TARGET_NR_ptrace:
5570 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005571#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005572 case TARGET_NR_alarm:
5573 ret = alarm(arg1);
5574 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005575#endif
bellardebc05482003-09-30 21:08:41 +00005576#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005577 case TARGET_NR_oldfstat:
5578 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005579#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005580#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005581 case TARGET_NR_pause:
5582 ret = get_errno(pause());
5583 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005584#endif
thse5febef2007-04-01 18:31:35 +00005585#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005586 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005587 {
pbrook53a59602006-03-25 19:31:22 +00005588 struct utimbuf tbuf, *host_tbuf;
5589 struct target_utimbuf *target_tbuf;
5590 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005591 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5592 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005593 tbuf.actime = tswapal(target_tbuf->actime);
5594 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005595 unlock_user_struct(target_tbuf, arg2, 0);
5596 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005597 } else {
pbrook53a59602006-03-25 19:31:22 +00005598 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005599 }
bellard579a97f2007-11-11 14:26:47 +00005600 if (!(p = lock_user_string(arg1)))
5601 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005602 ret = get_errno(utime(p, host_tbuf));
5603 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005604 }
5605 break;
thse5febef2007-04-01 18:31:35 +00005606#endif
bellard978a66f2004-12-06 22:58:05 +00005607 case TARGET_NR_utimes:
5608 {
bellard978a66f2004-12-06 22:58:05 +00005609 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005610 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005611 if (copy_from_user_timeval(&tv[0], arg2)
5612 || copy_from_user_timeval(&tv[1],
5613 arg2 + sizeof(struct target_timeval)))
5614 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005615 tvp = tv;
5616 } else {
5617 tvp = NULL;
5618 }
bellard579a97f2007-11-11 14:26:47 +00005619 if (!(p = lock_user_string(arg1)))
5620 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005621 ret = get_errno(utimes(p, tvp));
5622 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005623 }
5624 break;
balrogac8a6552008-09-20 02:25:39 +00005625#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
5626 case TARGET_NR_futimesat:
5627 {
5628 struct timeval *tvp, tv[2];
5629 if (arg3) {
5630 if (copy_from_user_timeval(&tv[0], arg3)
5631 || copy_from_user_timeval(&tv[1],
5632 arg3 + sizeof(struct target_timeval)))
5633 goto efault;
5634 tvp = tv;
5635 } else {
5636 tvp = NULL;
5637 }
5638 if (!(p = lock_user_string(arg2)))
5639 goto efault;
5640 ret = get_errno(sys_futimesat(arg1, path(p), tvp));
5641 unlock_user(p, arg2, 0);
5642 }
5643 break;
5644#endif
bellardebc05482003-09-30 21:08:41 +00005645#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005646 case TARGET_NR_stty:
5647 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005648#endif
5649#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005650 case TARGET_NR_gtty:
5651 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005652#endif
bellard31e31b82003-02-18 22:55:36 +00005653 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005654 if (!(p = lock_user_string(arg1)))
5655 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005656 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005657 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005658 break;
ths92a34c12007-09-24 09:27:49 +00005659#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5660 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005661 if (!(p = lock_user_string(arg2)))
5662 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00005663 ret = get_errno(sys_faccessat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005664 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005665 break;
5666#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005667#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005668 case TARGET_NR_nice:
5669 ret = get_errno(nice(arg1));
5670 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005671#endif
bellardebc05482003-09-30 21:08:41 +00005672#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005673 case TARGET_NR_ftime:
5674 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005675#endif
bellard31e31b82003-02-18 22:55:36 +00005676 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005677 sync();
5678 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005679 break;
5680 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005681 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005682 break;
5683 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005684 {
5685 void *p2;
5686 p = lock_user_string(arg1);
5687 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005688 if (!p || !p2)
5689 ret = -TARGET_EFAULT;
5690 else
5691 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005692 unlock_user(p2, arg2, 0);
5693 unlock_user(p, arg1, 0);
5694 }
bellard31e31b82003-02-18 22:55:36 +00005695 break;
ths722183f2007-09-24 09:24:37 +00005696#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
5697 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005698 {
bellard579a97f2007-11-11 14:26:47 +00005699 void *p2;
ths722183f2007-09-24 09:24:37 +00005700 p = lock_user_string(arg2);
5701 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005702 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005703 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005704 else
5705 ret = get_errno(sys_renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005706 unlock_user(p2, arg4, 0);
5707 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005708 }
5709 break;
5710#endif
bellard31e31b82003-02-18 22:55:36 +00005711 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005712 if (!(p = lock_user_string(arg1)))
5713 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005714 ret = get_errno(mkdir(p, arg2));
5715 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005716 break;
ths4472ad02007-09-24 09:22:32 +00005717#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
5718 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005719 if (!(p = lock_user_string(arg2)))
5720 goto efault;
5721 ret = get_errno(sys_mkdirat(arg1, p, arg3));
5722 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005723 break;
5724#endif
bellard31e31b82003-02-18 22:55:36 +00005725 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005726 if (!(p = lock_user_string(arg1)))
5727 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005728 ret = get_errno(rmdir(p));
5729 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005730 break;
5731 case TARGET_NR_dup:
5732 ret = get_errno(dup(arg1));
5733 break;
5734 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005735 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005736 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005737#ifdef TARGET_NR_pipe2
5738 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005739 ret = do_pipe(cpu_env, arg1,
5740 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005741 break;
5742#endif
bellard31e31b82003-02-18 22:55:36 +00005743 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005744 {
pbrook53a59602006-03-25 19:31:22 +00005745 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005746 struct tms tms;
5747 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005748 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005749 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5750 if (!tmsp)
5751 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005752 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5753 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5754 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5755 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005756 }
bellardc596ed12003-07-13 17:32:31 +00005757 if (!is_error(ret))
5758 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005759 }
5760 break;
bellardebc05482003-09-30 21:08:41 +00005761#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005762 case TARGET_NR_prof:
5763 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005764#endif
thse5febef2007-04-01 18:31:35 +00005765#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005766 case TARGET_NR_signal:
5767 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005768#endif
bellard31e31b82003-02-18 22:55:36 +00005769 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005770 if (arg1 == 0) {
5771 ret = get_errno(acct(NULL));
5772 } else {
5773 if (!(p = lock_user_string(arg1)))
5774 goto efault;
5775 ret = get_errno(acct(path(p)));
5776 unlock_user(p, arg1, 0);
5777 }
pbrook24836682006-04-16 14:14:53 +00005778 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005779#ifdef TARGET_NR_umount2 /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005780 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005781 if (!(p = lock_user_string(arg1)))
5782 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005783 ret = get_errno(umount2(p, arg2));
5784 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005785 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005786#endif
bellardebc05482003-09-30 21:08:41 +00005787#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005788 case TARGET_NR_lock:
5789 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005790#endif
bellard31e31b82003-02-18 22:55:36 +00005791 case TARGET_NR_ioctl:
5792 ret = do_ioctl(arg1, arg2, arg3);
5793 break;
5794 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005795 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005796 break;
bellardebc05482003-09-30 21:08:41 +00005797#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005798 case TARGET_NR_mpx:
5799 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005800#endif
bellard31e31b82003-02-18 22:55:36 +00005801 case TARGET_NR_setpgid:
5802 ret = get_errno(setpgid(arg1, arg2));
5803 break;
bellardebc05482003-09-30 21:08:41 +00005804#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005805 case TARGET_NR_ulimit:
5806 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005807#endif
5808#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005809 case TARGET_NR_oldolduname:
5810 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005811#endif
bellard31e31b82003-02-18 22:55:36 +00005812 case TARGET_NR_umask:
5813 ret = get_errno(umask(arg1));
5814 break;
5815 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005816 if (!(p = lock_user_string(arg1)))
5817 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005818 ret = get_errno(chroot(p));
5819 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005820 break;
5821 case TARGET_NR_ustat:
5822 goto unimplemented;
5823 case TARGET_NR_dup2:
5824 ret = get_errno(dup2(arg1, arg2));
5825 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005826#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5827 case TARGET_NR_dup3:
5828 ret = get_errno(dup3(arg1, arg2, arg3));
5829 break;
5830#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005831#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005832 case TARGET_NR_getppid:
5833 ret = get_errno(getppid());
5834 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005835#endif
bellard31e31b82003-02-18 22:55:36 +00005836 case TARGET_NR_getpgrp:
5837 ret = get_errno(getpgrp());
5838 break;
5839 case TARGET_NR_setsid:
5840 ret = get_errno(setsid());
5841 break;
thse5febef2007-04-01 18:31:35 +00005842#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005843 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005844 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005845#if defined(TARGET_ALPHA)
5846 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005847 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005848 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005849 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5850 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005851 act._sa_handler = old_act->_sa_handler;
5852 target_siginitset(&act.sa_mask, old_act->sa_mask);
5853 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005854 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005855 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005856 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005857 }
5858 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005859 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005860 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5861 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005862 old_act->_sa_handler = oact._sa_handler;
5863 old_act->sa_mask = oact.sa_mask.sig[0];
5864 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005865 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005866 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005867#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005868 struct target_sigaction act, oact, *pact, *old_act;
5869
5870 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005871 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5872 goto efault;
bellard106ec872006-06-27 21:08:10 +00005873 act._sa_handler = old_act->_sa_handler;
5874 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5875 act.sa_flags = old_act->sa_flags;
5876 unlock_user_struct(old_act, arg2, 0);
5877 pact = &act;
5878 } else {
5879 pact = NULL;
5880 }
5881
5882 ret = get_errno(do_sigaction(arg1, pact, &oact));
5883
5884 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005885 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5886 goto efault;
bellard106ec872006-06-27 21:08:10 +00005887 old_act->_sa_handler = oact._sa_handler;
5888 old_act->sa_flags = oact.sa_flags;
5889 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5890 old_act->sa_mask.sig[1] = 0;
5891 old_act->sa_mask.sig[2] = 0;
5892 old_act->sa_mask.sig[3] = 0;
5893 unlock_user_struct(old_act, arg3, 1);
5894 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005895#else
5896 struct target_old_sigaction *old_act;
5897 struct target_sigaction act, oact, *pact;
5898 if (arg2) {
5899 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5900 goto efault;
5901 act._sa_handler = old_act->_sa_handler;
5902 target_siginitset(&act.sa_mask, old_act->sa_mask);
5903 act.sa_flags = old_act->sa_flags;
5904 act.sa_restorer = old_act->sa_restorer;
5905 unlock_user_struct(old_act, arg2, 0);
5906 pact = &act;
5907 } else {
5908 pact = NULL;
5909 }
5910 ret = get_errno(do_sigaction(arg1, pact, &oact));
5911 if (!is_error(ret) && arg3) {
5912 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5913 goto efault;
5914 old_act->_sa_handler = oact._sa_handler;
5915 old_act->sa_mask = oact.sa_mask.sig[0];
5916 old_act->sa_flags = oact.sa_flags;
5917 old_act->sa_restorer = oact.sa_restorer;
5918 unlock_user_struct(old_act, arg3, 1);
5919 }
ths388bb212007-05-13 13:58:00 +00005920#endif
bellard31e31b82003-02-18 22:55:36 +00005921 }
5922 break;
thse5febef2007-04-01 18:31:35 +00005923#endif
bellard66fb9762003-03-23 01:06:05 +00005924 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005925 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005926#if defined(TARGET_ALPHA)
5927 struct target_sigaction act, oact, *pact = 0;
5928 struct target_rt_sigaction *rt_act;
5929 /* ??? arg4 == sizeof(sigset_t). */
5930 if (arg2) {
5931 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5932 goto efault;
5933 act._sa_handler = rt_act->_sa_handler;
5934 act.sa_mask = rt_act->sa_mask;
5935 act.sa_flags = rt_act->sa_flags;
5936 act.sa_restorer = arg5;
5937 unlock_user_struct(rt_act, arg2, 0);
5938 pact = &act;
5939 }
5940 ret = get_errno(do_sigaction(arg1, pact, &oact));
5941 if (!is_error(ret) && arg3) {
5942 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5943 goto efault;
5944 rt_act->_sa_handler = oact._sa_handler;
5945 rt_act->sa_mask = oact.sa_mask;
5946 rt_act->sa_flags = oact.sa_flags;
5947 unlock_user_struct(rt_act, arg3, 1);
5948 }
5949#else
pbrook53a59602006-03-25 19:31:22 +00005950 struct target_sigaction *act;
5951 struct target_sigaction *oact;
5952
bellard579a97f2007-11-11 14:26:47 +00005953 if (arg2) {
5954 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5955 goto efault;
5956 } else
pbrook53a59602006-03-25 19:31:22 +00005957 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005958 if (arg3) {
5959 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5960 ret = -TARGET_EFAULT;
5961 goto rt_sigaction_fail;
5962 }
5963 } else
pbrook53a59602006-03-25 19:31:22 +00005964 oact = NULL;
5965 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005966 rt_sigaction_fail:
5967 if (act)
pbrook53a59602006-03-25 19:31:22 +00005968 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005969 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005970 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005971#endif
pbrook53a59602006-03-25 19:31:22 +00005972 }
bellard66fb9762003-03-23 01:06:05 +00005973 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005974#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005975 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005976 {
5977 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005978 abi_ulong target_set;
bellard66fb9762003-03-23 01:06:05 +00005979 sigprocmask(0, NULL, &cur_set);
5980 host_to_target_old_sigset(&target_set, &cur_set);
5981 ret = target_set;
5982 }
5983 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005984#endif
5985#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005986 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005987 {
5988 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005989 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00005990 sigprocmask(0, NULL, &cur_set);
5991 target_to_host_old_sigset(&set, &target_set);
5992 sigorset(&set, &set, &cur_set);
5993 sigprocmask(SIG_SETMASK, &set, &oset);
5994 host_to_target_old_sigset(&target_set, &oset);
5995 ret = target_set;
5996 }
5997 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005998#endif
thse5febef2007-04-01 18:31:35 +00005999#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006000 case TARGET_NR_sigprocmask:
6001 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006002#if defined(TARGET_ALPHA)
6003 sigset_t set, oldset;
6004 abi_ulong mask;
6005 int how;
6006
6007 switch (arg1) {
6008 case TARGET_SIG_BLOCK:
6009 how = SIG_BLOCK;
6010 break;
6011 case TARGET_SIG_UNBLOCK:
6012 how = SIG_UNBLOCK;
6013 break;
6014 case TARGET_SIG_SETMASK:
6015 how = SIG_SETMASK;
6016 break;
6017 default:
6018 ret = -TARGET_EINVAL;
6019 goto fail;
6020 }
6021 mask = arg2;
6022 target_to_host_old_sigset(&set, &mask);
6023
6024 ret = get_errno(sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006025 if (!is_error(ret)) {
6026 host_to_target_old_sigset(&mask, &oldset);
6027 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006028 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006029 }
6030#else
bellard66fb9762003-03-23 01:06:05 +00006031 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006032 int how;
ths3b46e622007-09-17 08:09:54 +00006033
pbrook53a59602006-03-25 19:31:22 +00006034 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006035 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006036 case TARGET_SIG_BLOCK:
6037 how = SIG_BLOCK;
6038 break;
6039 case TARGET_SIG_UNBLOCK:
6040 how = SIG_UNBLOCK;
6041 break;
6042 case TARGET_SIG_SETMASK:
6043 how = SIG_SETMASK;
6044 break;
6045 default:
ths0da46a62007-10-20 20:23:07 +00006046 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006047 goto fail;
6048 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006049 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006050 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006051 target_to_host_old_sigset(&set, p);
6052 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006053 set_ptr = &set;
6054 } else {
6055 how = 0;
6056 set_ptr = NULL;
6057 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006058 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006059 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006060 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006061 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006062 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006063 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006064 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006065#endif
bellard66fb9762003-03-23 01:06:05 +00006066 }
6067 break;
thse5febef2007-04-01 18:31:35 +00006068#endif
bellard66fb9762003-03-23 01:06:05 +00006069 case TARGET_NR_rt_sigprocmask:
6070 {
6071 int how = arg1;
6072 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006073
pbrook53a59602006-03-25 19:31:22 +00006074 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006075 switch(how) {
6076 case TARGET_SIG_BLOCK:
6077 how = SIG_BLOCK;
6078 break;
6079 case TARGET_SIG_UNBLOCK:
6080 how = SIG_UNBLOCK;
6081 break;
6082 case TARGET_SIG_SETMASK:
6083 how = SIG_SETMASK;
6084 break;
6085 default:
ths0da46a62007-10-20 20:23:07 +00006086 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006087 goto fail;
6088 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006089 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006090 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006091 target_to_host_sigset(&set, p);
6092 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006093 set_ptr = &set;
6094 } else {
6095 how = 0;
6096 set_ptr = NULL;
6097 }
6098 ret = get_errno(sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006099 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006100 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006101 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006102 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006103 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006104 }
6105 }
6106 break;
thse5febef2007-04-01 18:31:35 +00006107#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006108 case TARGET_NR_sigpending:
6109 {
6110 sigset_t set;
6111 ret = get_errno(sigpending(&set));
6112 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006113 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006114 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006115 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006116 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006117 }
6118 }
6119 break;
thse5febef2007-04-01 18:31:35 +00006120#endif
bellard66fb9762003-03-23 01:06:05 +00006121 case TARGET_NR_rt_sigpending:
6122 {
6123 sigset_t set;
6124 ret = get_errno(sigpending(&set));
6125 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006126 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006127 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006128 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006129 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006130 }
6131 }
6132 break;
thse5febef2007-04-01 18:31:35 +00006133#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006134 case TARGET_NR_sigsuspend:
6135 {
6136 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006137#if defined(TARGET_ALPHA)
6138 abi_ulong mask = arg1;
6139 target_to_host_old_sigset(&set, &mask);
6140#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006141 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006142 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006143 target_to_host_old_sigset(&set, p);
6144 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006145#endif
bellard66fb9762003-03-23 01:06:05 +00006146 ret = get_errno(sigsuspend(&set));
6147 }
6148 break;
thse5febef2007-04-01 18:31:35 +00006149#endif
bellard66fb9762003-03-23 01:06:05 +00006150 case TARGET_NR_rt_sigsuspend:
6151 {
6152 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006153 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006154 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006155 target_to_host_sigset(&set, p);
6156 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006157 ret = get_errno(sigsuspend(&set));
6158 }
6159 break;
6160 case TARGET_NR_rt_sigtimedwait:
6161 {
bellard66fb9762003-03-23 01:06:05 +00006162 sigset_t set;
6163 struct timespec uts, *puts;
6164 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006165
Anthony Liguoric227f092009-10-01 16:12:16 -05006166 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006167 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006168 target_to_host_sigset(&set, p);
6169 unlock_user(p, arg1, 0);
6170 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006171 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006172 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006173 } else {
6174 puts = NULL;
6175 }
6176 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
pbrook53a59602006-03-25 19:31:22 +00006177 if (!is_error(ret) && arg2) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006178 if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006179 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006180 host_to_target_siginfo(p, &uinfo);
Anthony Liguoric227f092009-10-01 16:12:16 -05006181 unlock_user(p, arg2, sizeof(target_siginfo_t));
bellard66fb9762003-03-23 01:06:05 +00006182 }
6183 }
6184 break;
6185 case TARGET_NR_rt_sigqueueinfo:
6186 {
6187 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006188 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006189 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006190 target_to_host_siginfo(&uinfo, p);
6191 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006192 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6193 }
6194 break;
thse5febef2007-04-01 18:31:35 +00006195#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006196 case TARGET_NR_sigreturn:
6197 /* NOTE: ret is eax, so not transcoding must be done */
6198 ret = do_sigreturn(cpu_env);
6199 break;
thse5febef2007-04-01 18:31:35 +00006200#endif
bellard66fb9762003-03-23 01:06:05 +00006201 case TARGET_NR_rt_sigreturn:
6202 /* NOTE: ret is eax, so not transcoding must be done */
6203 ret = do_rt_sigreturn(cpu_env);
6204 break;
bellard31e31b82003-02-18 22:55:36 +00006205 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006206 if (!(p = lock_user_string(arg1)))
6207 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006208 ret = get_errno(sethostname(p, arg2));
6209 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006210 break;
6211 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006212 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006213 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006214 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006215 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006216 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6217 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006218 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6219 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006220 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006221 ret = get_errno(setrlimit(resource, &rlim));
6222 }
6223 break;
bellard31e31b82003-02-18 22:55:36 +00006224 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006225 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006226 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006227 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006228 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006229
bellard9de5e442003-03-23 16:49:39 +00006230 ret = get_errno(getrlimit(resource, &rlim));
6231 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006232 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6233 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006234 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6235 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006236 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006237 }
6238 }
6239 break;
bellard31e31b82003-02-18 22:55:36 +00006240 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006241 {
6242 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006243 ret = get_errno(getrusage(arg1, &rusage));
6244 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006245 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006246 }
6247 }
6248 break;
bellard31e31b82003-02-18 22:55:36 +00006249 case TARGET_NR_gettimeofday:
6250 {
bellard31e31b82003-02-18 22:55:36 +00006251 struct timeval tv;
6252 ret = get_errno(gettimeofday(&tv, NULL));
6253 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006254 if (copy_to_user_timeval(arg1, &tv))
6255 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006256 }
6257 }
6258 break;
6259 case TARGET_NR_settimeofday:
6260 {
bellard31e31b82003-02-18 22:55:36 +00006261 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006262 if (copy_from_user_timeval(&tv, arg1))
6263 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006264 ret = get_errno(settimeofday(&tv, NULL));
6265 }
6266 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006267#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006268 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006269#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6270 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6271#else
bellardf2674e32003-07-09 12:26:09 +00006272 {
pbrook53a59602006-03-25 19:31:22 +00006273 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006274 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006275 long nsel;
6276
bellard579a97f2007-11-11 14:26:47 +00006277 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6278 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006279 nsel = tswapal(sel->n);
6280 inp = tswapal(sel->inp);
6281 outp = tswapal(sel->outp);
6282 exp = tswapal(sel->exp);
6283 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006284 unlock_user_struct(sel, arg1, 0);
6285 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006286 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006287#endif
bellardf2674e32003-07-09 12:26:09 +00006288 break;
bellard048f6b42005-11-26 18:47:20 +00006289#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006290#ifdef TARGET_NR_pselect6
6291 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006292 {
6293 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6294 fd_set rfds, wfds, efds;
6295 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6296 struct timespec ts, *ts_ptr;
6297
6298 /*
6299 * The 6th arg is actually two args smashed together,
6300 * so we cannot use the C library.
6301 */
6302 sigset_t set;
6303 struct {
6304 sigset_t *set;
6305 size_t size;
6306 } sig, *sig_ptr;
6307
6308 abi_ulong arg_sigset, arg_sigsize, *arg7;
6309 target_sigset_t *target_sigset;
6310
6311 n = arg1;
6312 rfd_addr = arg2;
6313 wfd_addr = arg3;
6314 efd_addr = arg4;
6315 ts_addr = arg5;
6316
6317 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6318 if (ret) {
6319 goto fail;
6320 }
6321 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6322 if (ret) {
6323 goto fail;
6324 }
6325 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6326 if (ret) {
6327 goto fail;
6328 }
6329
6330 /*
6331 * This takes a timespec, and not a timeval, so we cannot
6332 * use the do_select() helper ...
6333 */
6334 if (ts_addr) {
6335 if (target_to_host_timespec(&ts, ts_addr)) {
6336 goto efault;
6337 }
6338 ts_ptr = &ts;
6339 } else {
6340 ts_ptr = NULL;
6341 }
6342
6343 /* Extract the two packed args for the sigset */
6344 if (arg6) {
6345 sig_ptr = &sig;
6346 sig.size = _NSIG / 8;
6347
6348 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6349 if (!arg7) {
6350 goto efault;
6351 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006352 arg_sigset = tswapal(arg7[0]);
6353 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006354 unlock_user(arg7, arg6, 0);
6355
6356 if (arg_sigset) {
6357 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006358 if (arg_sigsize != sizeof(*target_sigset)) {
6359 /* Like the kernel, we enforce correct size sigsets */
6360 ret = -TARGET_EINVAL;
6361 goto fail;
6362 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006363 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6364 sizeof(*target_sigset), 1);
6365 if (!target_sigset) {
6366 goto efault;
6367 }
6368 target_to_host_sigset(&set, target_sigset);
6369 unlock_user(target_sigset, arg_sigset, 0);
6370 } else {
6371 sig.set = NULL;
6372 }
6373 } else {
6374 sig_ptr = NULL;
6375 }
6376
6377 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6378 ts_ptr, sig_ptr));
6379
6380 if (!is_error(ret)) {
6381 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6382 goto efault;
6383 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6384 goto efault;
6385 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6386 goto efault;
6387
6388 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6389 goto efault;
6390 }
6391 }
6392 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006393#endif
bellard31e31b82003-02-18 22:55:36 +00006394 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006395 {
6396 void *p2;
6397 p = lock_user_string(arg1);
6398 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006399 if (!p || !p2)
6400 ret = -TARGET_EFAULT;
6401 else
6402 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006403 unlock_user(p2, arg2, 0);
6404 unlock_user(p, arg1, 0);
6405 }
bellard31e31b82003-02-18 22:55:36 +00006406 break;
thsf0b62432007-09-24 09:25:40 +00006407#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
6408 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006409 {
bellard579a97f2007-11-11 14:26:47 +00006410 void *p2;
thsf0b62432007-09-24 09:25:40 +00006411 p = lock_user_string(arg1);
6412 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006413 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006414 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006415 else
6416 ret = get_errno(sys_symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006417 unlock_user(p2, arg3, 0);
6418 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006419 }
6420 break;
6421#endif
bellardebc05482003-09-30 21:08:41 +00006422#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006423 case TARGET_NR_oldlstat:
6424 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006425#endif
bellard31e31b82003-02-18 22:55:36 +00006426 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006427 {
aurel32d088d662009-01-30 20:09:01 +00006428 void *p2, *temp;
pbrook53a59602006-03-25 19:31:22 +00006429 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006430 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
6431 if (!p || !p2)
6432 ret = -TARGET_EFAULT;
aurel32d088d662009-01-30 20:09:01 +00006433 else {
6434 if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
6435 char real[PATH_MAX];
6436 temp = realpath(exec_path,real);
6437 ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
6438 snprintf((char *)p2, arg3, "%s", real);
6439 }
6440 else
6441 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006442 }
pbrook53a59602006-03-25 19:31:22 +00006443 unlock_user(p2, arg2, ret);
6444 unlock_user(p, arg1, 0);
6445 }
bellard31e31b82003-02-18 22:55:36 +00006446 break;
ths5e0ccb12007-09-24 09:26:10 +00006447#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
6448 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006449 {
bellard579a97f2007-11-11 14:26:47 +00006450 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006451 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006452 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
6453 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006454 ret = -TARGET_EFAULT;
ths5e0ccb12007-09-24 09:26:10 +00006455 else
6456 ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
bellard579a97f2007-11-11 14:26:47 +00006457 unlock_user(p2, arg3, ret);
6458 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006459 }
6460 break;
6461#endif
thse5febef2007-04-01 18:31:35 +00006462#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006463 case TARGET_NR_uselib:
6464 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006465#endif
6466#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006467 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006468 if (!(p = lock_user_string(arg1)))
6469 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006470 ret = get_errno(swapon(p, arg2));
6471 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006472 break;
thse5febef2007-04-01 18:31:35 +00006473#endif
bellard31e31b82003-02-18 22:55:36 +00006474 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006475 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6476 /* arg4 must be ignored in all other cases */
6477 p = lock_user_string(arg4);
6478 if (!p) {
6479 goto efault;
6480 }
6481 ret = get_errno(reboot(arg1, arg2, arg3, p));
6482 unlock_user(p, arg4, 0);
6483 } else {
6484 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6485 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006486 break;
thse5febef2007-04-01 18:31:35 +00006487#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006488 case TARGET_NR_readdir:
6489 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006490#endif
6491#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006492 case TARGET_NR_mmap:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006493#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
6494 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6495 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006496 {
blueswir1992f48a2007-10-14 16:27:31 +00006497 abi_ulong *v;
6498 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006499 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6500 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006501 v1 = tswapal(v[0]);
6502 v2 = tswapal(v[1]);
6503 v3 = tswapal(v[2]);
6504 v4 = tswapal(v[3]);
6505 v5 = tswapal(v[4]);
6506 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006507 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006508 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006509 target_to_host_bitmask(v4, mmap_flags_tbl),
6510 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006511 }
bellard31e31b82003-02-18 22:55:36 +00006512#else
ths5fafdf22007-09-16 21:08:06 +00006513 ret = get_errno(target_mmap(arg1, arg2, arg3,
6514 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006515 arg5,
6516 arg6));
bellard31e31b82003-02-18 22:55:36 +00006517#endif
bellard6fb883e2003-07-09 17:12:39 +00006518 break;
thse5febef2007-04-01 18:31:35 +00006519#endif
bellarda315a142005-01-30 22:59:18 +00006520#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006521 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006522#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006523#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006524#endif
ths5fafdf22007-09-16 21:08:06 +00006525 ret = get_errno(target_mmap(arg1, arg2, arg3,
6526 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006527 arg5,
bellardc573ff62004-01-04 15:51:36 +00006528 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006529 break;
bellarda315a142005-01-30 22:59:18 +00006530#endif
bellard31e31b82003-02-18 22:55:36 +00006531 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006532 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006533 break;
bellard9de5e442003-03-23 16:49:39 +00006534 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006535 {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006536 TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006537 /* Special hack to detect libc making the stack executable. */
6538 if ((arg3 & PROT_GROWSDOWN)
6539 && arg1 >= ts->info->stack_limit
6540 && arg1 <= ts->info->start_stack) {
6541 arg3 &= ~PROT_GROWSDOWN;
6542 arg2 = arg2 + arg1 - ts->info->stack_limit;
6543 arg1 = ts->info->stack_limit;
6544 }
6545 }
bellard54936002003-05-13 00:25:15 +00006546 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006547 break;
thse5febef2007-04-01 18:31:35 +00006548#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006549 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006550 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006551 break;
thse5febef2007-04-01 18:31:35 +00006552#endif
pbrook53a59602006-03-25 19:31:22 +00006553 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006554#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006555 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006556 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006557 break;
thse5febef2007-04-01 18:31:35 +00006558#endif
6559#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006560 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006561 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006562 break;
thse5febef2007-04-01 18:31:35 +00006563#endif
6564#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006565 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006566 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006567 break;
thse5febef2007-04-01 18:31:35 +00006568#endif
6569#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006570 case TARGET_NR_mlockall:
6571 ret = get_errno(mlockall(arg1));
6572 break;
thse5febef2007-04-01 18:31:35 +00006573#endif
6574#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006575 case TARGET_NR_munlockall:
6576 ret = get_errno(munlockall());
6577 break;
thse5febef2007-04-01 18:31:35 +00006578#endif
bellard31e31b82003-02-18 22:55:36 +00006579 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006580 if (!(p = lock_user_string(arg1)))
6581 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006582 ret = get_errno(truncate(p, arg2));
6583 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006584 break;
6585 case TARGET_NR_ftruncate:
6586 ret = get_errno(ftruncate(arg1, arg2));
6587 break;
6588 case TARGET_NR_fchmod:
6589 ret = get_errno(fchmod(arg1, arg2));
6590 break;
ths814d7972007-09-24 09:26:51 +00006591#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
6592 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006593 if (!(p = lock_user_string(arg2)))
6594 goto efault;
aurel32465c9f02009-04-19 08:52:17 +00006595 ret = get_errno(sys_fchmodat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006596 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006597 break;
6598#endif
bellard31e31b82003-02-18 22:55:36 +00006599 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006600 /* Note that negative values are valid for getpriority, so we must
6601 differentiate based on errno settings. */
6602 errno = 0;
6603 ret = getpriority(arg1, arg2);
6604 if (ret == -1 && errno != 0) {
6605 ret = -host_to_target_errno(errno);
6606 break;
6607 }
6608#ifdef TARGET_ALPHA
6609 /* Return value is the unbiased priority. Signal no error. */
6610 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6611#else
6612 /* Return value is a biased priority to avoid negative numbers. */
6613 ret = 20 - ret;
6614#endif
bellard31e31b82003-02-18 22:55:36 +00006615 break;
6616 case TARGET_NR_setpriority:
6617 ret = get_errno(setpriority(arg1, arg2, arg3));
6618 break;
bellardebc05482003-09-30 21:08:41 +00006619#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006620 case TARGET_NR_profil:
6621 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006622#endif
bellard31e31b82003-02-18 22:55:36 +00006623 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006624 if (!(p = lock_user_string(arg1)))
6625 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006626 ret = get_errno(statfs(path(p), &stfs));
6627 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006628 convert_statfs:
6629 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006630 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006631
bellard579a97f2007-11-11 14:26:47 +00006632 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6633 goto efault;
6634 __put_user(stfs.f_type, &target_stfs->f_type);
6635 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6636 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6637 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6638 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6639 __put_user(stfs.f_files, &target_stfs->f_files);
6640 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6641 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6642 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6643 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006644 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6645 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006646 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006647 }
6648 break;
6649 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006650 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006651 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006652#ifdef TARGET_NR_statfs64
6653 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006654 if (!(p = lock_user_string(arg1)))
6655 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006656 ret = get_errno(statfs(path(p), &stfs));
6657 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006658 convert_statfs64:
6659 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006660 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006661
bellard579a97f2007-11-11 14:26:47 +00006662 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6663 goto efault;
6664 __put_user(stfs.f_type, &target_stfs->f_type);
6665 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6666 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6667 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6668 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6669 __put_user(stfs.f_files, &target_stfs->f_files);
6670 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6671 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6672 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6673 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006674 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6675 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006676 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006677 }
6678 break;
6679 case TARGET_NR_fstatfs64:
6680 ret = get_errno(fstatfs(arg1, &stfs));
6681 goto convert_statfs64;
6682#endif
bellardebc05482003-09-30 21:08:41 +00006683#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006684 case TARGET_NR_ioperm:
6685 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006686#endif
thse5febef2007-04-01 18:31:35 +00006687#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006688 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006689 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006690 break;
thse5febef2007-04-01 18:31:35 +00006691#endif
bellard3532fa72006-06-24 15:06:03 +00006692#ifdef TARGET_NR_accept
6693 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006694 ret = do_accept4(arg1, arg2, arg3, 0);
6695 break;
6696#endif
6697#ifdef TARGET_NR_accept4
6698 case TARGET_NR_accept4:
6699#ifdef CONFIG_ACCEPT4
6700 ret = do_accept4(arg1, arg2, arg3, arg4);
6701#else
6702 goto unimplemented;
6703#endif
bellard3532fa72006-06-24 15:06:03 +00006704 break;
6705#endif
6706#ifdef TARGET_NR_bind
6707 case TARGET_NR_bind:
6708 ret = do_bind(arg1, arg2, arg3);
6709 break;
6710#endif
6711#ifdef TARGET_NR_connect
6712 case TARGET_NR_connect:
6713 ret = do_connect(arg1, arg2, arg3);
6714 break;
6715#endif
6716#ifdef TARGET_NR_getpeername
6717 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006718 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006719 break;
6720#endif
6721#ifdef TARGET_NR_getsockname
6722 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006723 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006724 break;
6725#endif
6726#ifdef TARGET_NR_getsockopt
6727 case TARGET_NR_getsockopt:
6728 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6729 break;
6730#endif
6731#ifdef TARGET_NR_listen
6732 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006733 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006734 break;
6735#endif
6736#ifdef TARGET_NR_recv
6737 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006738 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006739 break;
6740#endif
6741#ifdef TARGET_NR_recvfrom
6742 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006743 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006744 break;
6745#endif
6746#ifdef TARGET_NR_recvmsg
6747 case TARGET_NR_recvmsg:
6748 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6749 break;
6750#endif
6751#ifdef TARGET_NR_send
6752 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006753 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006754 break;
6755#endif
6756#ifdef TARGET_NR_sendmsg
6757 case TARGET_NR_sendmsg:
6758 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6759 break;
6760#endif
6761#ifdef TARGET_NR_sendto
6762 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006763 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006764 break;
6765#endif
6766#ifdef TARGET_NR_shutdown
6767 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006768 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006769 break;
6770#endif
6771#ifdef TARGET_NR_socket
6772 case TARGET_NR_socket:
6773 ret = do_socket(arg1, arg2, arg3);
6774 break;
6775#endif
6776#ifdef TARGET_NR_socketpair
6777 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006778 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006779 break;
6780#endif
6781#ifdef TARGET_NR_setsockopt
6782 case TARGET_NR_setsockopt:
6783 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6784 break;
6785#endif
ths7494b0f2007-02-11 18:26:53 +00006786
bellard31e31b82003-02-18 22:55:36 +00006787 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006788 if (!(p = lock_user_string(arg2)))
6789 goto efault;
thse5574482007-02-11 20:03:13 +00006790 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6791 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006792 break;
6793
bellard31e31b82003-02-18 22:55:36 +00006794 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006795 {
bellard66fb9762003-03-23 01:06:05 +00006796 struct itimerval value, ovalue, *pvalue;
6797
pbrook53a59602006-03-25 19:31:22 +00006798 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006799 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006800 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6801 || copy_from_user_timeval(&pvalue->it_value,
6802 arg2 + sizeof(struct target_timeval)))
6803 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006804 } else {
6805 pvalue = NULL;
6806 }
6807 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006808 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006809 if (copy_to_user_timeval(arg3,
6810 &ovalue.it_interval)
6811 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6812 &ovalue.it_value))
6813 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006814 }
6815 }
6816 break;
bellard31e31b82003-02-18 22:55:36 +00006817 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006818 {
bellard66fb9762003-03-23 01:06:05 +00006819 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006820
bellard66fb9762003-03-23 01:06:05 +00006821 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006822 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006823 if (copy_to_user_timeval(arg2,
6824 &value.it_interval)
6825 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6826 &value.it_value))
6827 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006828 }
6829 }
6830 break;
bellard31e31b82003-02-18 22:55:36 +00006831 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006832 if (!(p = lock_user_string(arg1)))
6833 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006834 ret = get_errno(stat(path(p), &st));
6835 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006836 goto do_stat;
6837 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006838 if (!(p = lock_user_string(arg1)))
6839 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006840 ret = get_errno(lstat(path(p), &st));
6841 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006842 goto do_stat;
6843 case TARGET_NR_fstat:
6844 {
6845 ret = get_errno(fstat(arg1, &st));
6846 do_stat:
6847 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006848 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006849
bellard579a97f2007-11-11 14:26:47 +00006850 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6851 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006852 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006853 __put_user(st.st_dev, &target_st->st_dev);
6854 __put_user(st.st_ino, &target_st->st_ino);
6855 __put_user(st.st_mode, &target_st->st_mode);
6856 __put_user(st.st_uid, &target_st->st_uid);
6857 __put_user(st.st_gid, &target_st->st_gid);
6858 __put_user(st.st_nlink, &target_st->st_nlink);
6859 __put_user(st.st_rdev, &target_st->st_rdev);
6860 __put_user(st.st_size, &target_st->st_size);
6861 __put_user(st.st_blksize, &target_st->st_blksize);
6862 __put_user(st.st_blocks, &target_st->st_blocks);
6863 __put_user(st.st_atime, &target_st->target_st_atime);
6864 __put_user(st.st_mtime, &target_st->target_st_mtime);
6865 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006866 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006867 }
6868 }
6869 break;
bellardebc05482003-09-30 21:08:41 +00006870#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006871 case TARGET_NR_olduname:
6872 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006873#endif
6874#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006875 case TARGET_NR_iopl:
6876 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006877#endif
bellard31e31b82003-02-18 22:55:36 +00006878 case TARGET_NR_vhangup:
6879 ret = get_errno(vhangup());
6880 break;
bellardebc05482003-09-30 21:08:41 +00006881#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006882 case TARGET_NR_idle:
6883 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006884#endif
bellard42ad6ae2005-01-03 22:48:11 +00006885#ifdef TARGET_NR_syscall
6886 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006887 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6888 arg6, arg7, arg8, 0);
6889 break;
bellard42ad6ae2005-01-03 22:48:11 +00006890#endif
bellard31e31b82003-02-18 22:55:36 +00006891 case TARGET_NR_wait4:
6892 {
6893 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006894 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006895 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006896 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00006897 if (target_rusage)
6898 rusage_ptr = &rusage;
6899 else
6900 rusage_ptr = NULL;
6901 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6902 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006903 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006904 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006905 if (put_user_s32(status, status_ptr))
6906 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006907 }
bellard2f619692007-11-16 10:46:05 +00006908 if (target_rusage)
6909 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00006910 }
6911 }
6912 break;
thse5febef2007-04-01 18:31:35 +00006913#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006914 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006915 if (!(p = lock_user_string(arg1)))
6916 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006917 ret = get_errno(swapoff(p));
6918 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006919 break;
thse5febef2007-04-01 18:31:35 +00006920#endif
bellard31e31b82003-02-18 22:55:36 +00006921 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006922 {
pbrook53a59602006-03-25 19:31:22 +00006923 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006924 struct sysinfo value;
6925 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006926 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006927 {
bellard579a97f2007-11-11 14:26:47 +00006928 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6929 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006930 __put_user(value.uptime, &target_value->uptime);
6931 __put_user(value.loads[0], &target_value->loads[0]);
6932 __put_user(value.loads[1], &target_value->loads[1]);
6933 __put_user(value.loads[2], &target_value->loads[2]);
6934 __put_user(value.totalram, &target_value->totalram);
6935 __put_user(value.freeram, &target_value->freeram);
6936 __put_user(value.sharedram, &target_value->sharedram);
6937 __put_user(value.bufferram, &target_value->bufferram);
6938 __put_user(value.totalswap, &target_value->totalswap);
6939 __put_user(value.freeswap, &target_value->freeswap);
6940 __put_user(value.procs, &target_value->procs);
6941 __put_user(value.totalhigh, &target_value->totalhigh);
6942 __put_user(value.freehigh, &target_value->freehigh);
6943 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006944 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006945 }
6946 }
6947 break;
thse5febef2007-04-01 18:31:35 +00006948#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006949 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006950 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6951 break;
thse5febef2007-04-01 18:31:35 +00006952#endif
aurel32e5289082009-04-18 16:16:12 +00006953#ifdef TARGET_NR_semget
6954 case TARGET_NR_semget:
6955 ret = get_errno(semget(arg1, arg2, arg3));
6956 break;
6957#endif
6958#ifdef TARGET_NR_semop
6959 case TARGET_NR_semop:
6960 ret = get_errno(do_semop(arg1, arg2, arg3));
6961 break;
6962#endif
6963#ifdef TARGET_NR_semctl
6964 case TARGET_NR_semctl:
6965 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6966 break;
6967#endif
aurel32eeb438c2008-10-13 21:08:55 +00006968#ifdef TARGET_NR_msgctl
6969 case TARGET_NR_msgctl:
6970 ret = do_msgctl(arg1, arg2, arg3);
6971 break;
6972#endif
6973#ifdef TARGET_NR_msgget
6974 case TARGET_NR_msgget:
6975 ret = get_errno(msgget(arg1, arg2));
6976 break;
6977#endif
6978#ifdef TARGET_NR_msgrcv
6979 case TARGET_NR_msgrcv:
6980 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
6981 break;
6982#endif
6983#ifdef TARGET_NR_msgsnd
6984 case TARGET_NR_msgsnd:
6985 ret = do_msgsnd(arg1, arg2, arg3, arg4);
6986 break;
6987#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03006988#ifdef TARGET_NR_shmget
6989 case TARGET_NR_shmget:
6990 ret = get_errno(shmget(arg1, arg2, arg3));
6991 break;
6992#endif
6993#ifdef TARGET_NR_shmctl
6994 case TARGET_NR_shmctl:
6995 ret = do_shmctl(arg1, arg2, arg3);
6996 break;
6997#endif
6998#ifdef TARGET_NR_shmat
6999 case TARGET_NR_shmat:
7000 ret = do_shmat(arg1, arg2, arg3);
7001 break;
7002#endif
7003#ifdef TARGET_NR_shmdt
7004 case TARGET_NR_shmdt:
7005 ret = do_shmdt(arg1);
7006 break;
7007#endif
bellard31e31b82003-02-18 22:55:36 +00007008 case TARGET_NR_fsync:
7009 ret = get_errno(fsync(arg1));
7010 break;
bellard31e31b82003-02-18 22:55:36 +00007011 case TARGET_NR_clone:
Richard Hendersona4b388f2010-04-12 16:17:22 -07007012#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
aurel320b6d3ae2008-09-15 07:43:43 +00007013 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
edgar_iglb15ad612009-01-07 19:43:47 +00007014#elif defined(TARGET_CRIS)
7015 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007016#elif defined(TARGET_MICROBLAZE)
7017 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007018#elif defined(TARGET_S390X)
7019 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007020#else
pbrookd865bab2008-06-07 22:12:17 +00007021 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
aurel320b6d3ae2008-09-15 07:43:43 +00007022#endif
bellard1b6b0292003-03-22 17:31:38 +00007023 break;
bellardec86b0f2003-04-11 00:15:04 +00007024#ifdef __NR_exit_group
7025 /* new thread calls */
7026 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007027#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007028 _mcleanup();
7029#endif
bellarde9009672005-04-26 20:42:36 +00007030 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007031 ret = get_errno(exit_group(arg1));
7032 break;
7033#endif
bellard31e31b82003-02-18 22:55:36 +00007034 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007035 if (!(p = lock_user_string(arg1)))
7036 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007037 ret = get_errno(setdomainname(p, arg2));
7038 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007039 break;
7040 case TARGET_NR_uname:
7041 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007042 {
7043 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007044
bellard579a97f2007-11-11 14:26:47 +00007045 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7046 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007047 ret = get_errno(sys_uname(buf));
7048 if (!is_error(ret)) {
7049 /* Overrite the native machine name with whatever is being
7050 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007051 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007052 /* Allow the user to override the reported release. */
7053 if (qemu_uname_release && *qemu_uname_release)
7054 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007055 }
pbrook53a59602006-03-25 19:31:22 +00007056 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007057 }
bellard31e31b82003-02-18 22:55:36 +00007058 break;
bellard6dbad632003-03-16 18:05:05 +00007059#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007060 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007061 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007062 break;
j_mayer84409dd2007-04-06 08:56:50 +00007063#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007064 case TARGET_NR_vm86old:
7065 goto unimplemented;
7066 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007067 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007068 break;
7069#endif
j_mayer84409dd2007-04-06 08:56:50 +00007070#endif
bellard31e31b82003-02-18 22:55:36 +00007071 case TARGET_NR_adjtimex:
7072 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007073#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007074 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007075#endif
bellard31e31b82003-02-18 22:55:36 +00007076 case TARGET_NR_init_module:
7077 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007078#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007079 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007080#endif
bellard31e31b82003-02-18 22:55:36 +00007081 goto unimplemented;
7082 case TARGET_NR_quotactl:
7083 goto unimplemented;
7084 case TARGET_NR_getpgid:
7085 ret = get_errno(getpgid(arg1));
7086 break;
7087 case TARGET_NR_fchdir:
7088 ret = get_errno(fchdir(arg1));
7089 break;
j_mayer84409dd2007-04-06 08:56:50 +00007090#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007091 case TARGET_NR_bdflush:
7092 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007093#endif
thse5febef2007-04-01 18:31:35 +00007094#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007095 case TARGET_NR_sysfs:
7096 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007097#endif
bellard31e31b82003-02-18 22:55:36 +00007098 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007099 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007100 break;
thse5febef2007-04-01 18:31:35 +00007101#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007102 case TARGET_NR_afs_syscall:
7103 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007104#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007105#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007106 case TARGET_NR__llseek:
7107 {
7108 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007109#if !defined(__NR_llseek)
7110 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7111 if (res == -1) {
7112 ret = get_errno(res);
7113 } else {
7114 ret = 0;
7115 }
7116#else
bellard31e31b82003-02-18 22:55:36 +00007117 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007118#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007119 if ((ret == 0) && put_user_s64(res, arg4)) {
7120 goto efault;
7121 }
bellard31e31b82003-02-18 22:55:36 +00007122 }
7123 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007124#endif
bellard31e31b82003-02-18 22:55:36 +00007125 case TARGET_NR_getdents:
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007126#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007127 {
pbrook53a59602006-03-25 19:31:22 +00007128 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007129 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007130 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007131
7132 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007133 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007134 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007135 goto fail;
7136 }
ths3b46e622007-09-17 08:09:54 +00007137
bellard4add45b2003-06-05 01:52:59 +00007138 ret = get_errno(sys_getdents(arg1, dirp, count));
7139 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007140 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007141 struct target_dirent *tde;
7142 int len = ret;
7143 int reclen, treclen;
7144 int count1, tnamelen;
7145
7146 count1 = 0;
7147 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007148 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7149 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007150 tde = target_dirp;
7151 while (len > 0) {
7152 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007153 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7154 assert(tnamelen >= 0);
7155 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7156 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007157 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007158 tde->d_ino = tswapal(de->d_ino);
7159 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007160 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007161 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007162 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007163 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007164 count1 += treclen;
7165 }
7166 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007167 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007168 }
7169 free(dirp);
7170 }
7171#else
bellard31e31b82003-02-18 22:55:36 +00007172 {
aurel326556a832008-10-13 21:08:17 +00007173 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007174 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007175
bellard579a97f2007-11-11 14:26:47 +00007176 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7177 goto efault;
bellard72f03902003-02-18 23:33:18 +00007178 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007179 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007180 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007181 int len = ret;
7182 int reclen;
7183 de = dirp;
7184 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007185 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007186 if (reclen > len)
7187 break;
bellard8083a3e2003-03-24 23:12:16 +00007188 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007189 tswapls(&de->d_ino);
7190 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007191 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007192 len -= reclen;
7193 }
7194 }
pbrook53a59602006-03-25 19:31:22 +00007195 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007196 }
bellard4add45b2003-06-05 01:52:59 +00007197#endif
bellard31e31b82003-02-18 22:55:36 +00007198 break;
ths3ae43202007-09-16 21:39:48 +00007199#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007200 case TARGET_NR_getdents64:
7201 {
aurel326556a832008-10-13 21:08:17 +00007202 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007203 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007204 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7205 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007206 ret = get_errno(sys_getdents64(arg1, dirp, count));
7207 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007208 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007209 int len = ret;
7210 int reclen;
7211 de = dirp;
7212 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007213 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007214 if (reclen > len)
7215 break;
bellard8083a3e2003-03-24 23:12:16 +00007216 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007217 tswap64s((uint64_t *)&de->d_ino);
7218 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007219 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007220 len -= reclen;
7221 }
7222 }
pbrook53a59602006-03-25 19:31:22 +00007223 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007224 }
7225 break;
bellarda541f292004-04-12 20:39:29 +00007226#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007227#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007228 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007229 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007230 break;
thse5febef2007-04-01 18:31:35 +00007231#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007232#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7233# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007234 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007235# endif
7236# ifdef TARGET_NR_ppoll
7237 case TARGET_NR_ppoll:
7238# endif
bellard9de5e442003-03-23 16:49:39 +00007239 {
pbrook53a59602006-03-25 19:31:22 +00007240 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007241 unsigned int nfds = arg2;
7242 int timeout = arg3;
7243 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007244 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007245
bellard579a97f2007-11-11 14:26:47 +00007246 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7247 if (!target_pfd)
7248 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007249
bellard9de5e442003-03-23 16:49:39 +00007250 pfd = alloca(sizeof(struct pollfd) * nfds);
7251 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007252 pfd[i].fd = tswap32(target_pfd[i].fd);
7253 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007254 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007255
7256# ifdef TARGET_NR_ppoll
7257 if (num == TARGET_NR_ppoll) {
7258 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7259 target_sigset_t *target_set;
7260 sigset_t _set, *set = &_set;
7261
7262 if (arg3) {
7263 if (target_to_host_timespec(timeout_ts, arg3)) {
7264 unlock_user(target_pfd, arg1, 0);
7265 goto efault;
7266 }
7267 } else {
7268 timeout_ts = NULL;
7269 }
7270
7271 if (arg4) {
7272 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7273 if (!target_set) {
7274 unlock_user(target_pfd, arg1, 0);
7275 goto efault;
7276 }
7277 target_to_host_sigset(set, target_set);
7278 } else {
7279 set = NULL;
7280 }
7281
7282 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7283
7284 if (!is_error(ret) && arg3) {
7285 host_to_target_timespec(arg3, timeout_ts);
7286 }
7287 if (arg4) {
7288 unlock_user(target_set, arg4, 0);
7289 }
7290 } else
7291# endif
7292 ret = get_errno(poll(pfd, nfds, timeout));
7293
bellard9de5e442003-03-23 16:49:39 +00007294 if (!is_error(ret)) {
7295 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007296 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007297 }
7298 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007299 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007300 }
7301 break;
thse5febef2007-04-01 18:31:35 +00007302#endif
bellard31e31b82003-02-18 22:55:36 +00007303 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007304 /* NOTE: the flock constant seems to be the same for every
7305 Linux platform */
7306 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007307 break;
7308 case TARGET_NR_readv:
7309 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007310 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7311 if (vec != NULL) {
7312 ret = get_errno(readv(arg1, vec, arg3));
7313 unlock_iovec(vec, arg2, arg3, 1);
7314 } else {
7315 ret = -host_to_target_errno(errno);
7316 }
bellard31e31b82003-02-18 22:55:36 +00007317 }
7318 break;
7319 case TARGET_NR_writev:
7320 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007321 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7322 if (vec != NULL) {
7323 ret = get_errno(writev(arg1, vec, arg3));
7324 unlock_iovec(vec, arg2, arg3, 0);
7325 } else {
7326 ret = -host_to_target_errno(errno);
7327 }
bellard31e31b82003-02-18 22:55:36 +00007328 }
7329 break;
7330 case TARGET_NR_getsid:
7331 ret = get_errno(getsid(arg1));
7332 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007333#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007334 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007335 ret = get_errno(fdatasync(arg1));
7336 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007337#endif
bellard31e31b82003-02-18 22:55:36 +00007338 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007339 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007340 return value. */
ths0da46a62007-10-20 20:23:07 +00007341 ret = -TARGET_ENOTDIR;
7342 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007343 case TARGET_NR_sched_getaffinity:
7344 {
7345 unsigned int mask_size;
7346 unsigned long *mask;
7347
7348 /*
7349 * sched_getaffinity needs multiples of ulong, so need to take
7350 * care of mismatches between target ulong and host ulong sizes.
7351 */
7352 if (arg2 & (sizeof(abi_ulong) - 1)) {
7353 ret = -TARGET_EINVAL;
7354 break;
7355 }
7356 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7357
7358 mask = alloca(mask_size);
7359 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7360
7361 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007362 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007363 goto efault;
7364 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007365 }
7366 }
7367 break;
7368 case TARGET_NR_sched_setaffinity:
7369 {
7370 unsigned int mask_size;
7371 unsigned long *mask;
7372
7373 /*
7374 * sched_setaffinity needs multiples of ulong, so need to take
7375 * care of mismatches between target ulong and host ulong sizes.
7376 */
7377 if (arg2 & (sizeof(abi_ulong) - 1)) {
7378 ret = -TARGET_EINVAL;
7379 break;
7380 }
7381 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7382
7383 mask = alloca(mask_size);
7384 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7385 goto efault;
7386 }
7387 memcpy(mask, p, arg2);
7388 unlock_user_struct(p, arg2, 0);
7389
7390 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7391 }
7392 break;
bellard31e31b82003-02-18 22:55:36 +00007393 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007394 {
pbrook53a59602006-03-25 19:31:22 +00007395 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007396 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007397
bellard579a97f2007-11-11 14:26:47 +00007398 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7399 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007400 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007401 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007402 ret = get_errno(sched_setparam(arg1, &schp));
7403 }
7404 break;
bellard31e31b82003-02-18 22:55:36 +00007405 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007406 {
pbrook53a59602006-03-25 19:31:22 +00007407 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007408 struct sched_param schp;
7409 ret = get_errno(sched_getparam(arg1, &schp));
7410 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007411 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7412 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007413 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007414 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007415 }
7416 }
7417 break;
bellard31e31b82003-02-18 22:55:36 +00007418 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007419 {
pbrook53a59602006-03-25 19:31:22 +00007420 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007421 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007422 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7423 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007424 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007425 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007426 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7427 }
7428 break;
bellard31e31b82003-02-18 22:55:36 +00007429 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007430 ret = get_errno(sched_getscheduler(arg1));
7431 break;
bellard31e31b82003-02-18 22:55:36 +00007432 case TARGET_NR_sched_yield:
7433 ret = get_errno(sched_yield());
7434 break;
7435 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007436 ret = get_errno(sched_get_priority_max(arg1));
7437 break;
bellard31e31b82003-02-18 22:55:36 +00007438 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007439 ret = get_errno(sched_get_priority_min(arg1));
7440 break;
bellard31e31b82003-02-18 22:55:36 +00007441 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007442 {
bellard5cd43932003-03-29 16:54:36 +00007443 struct timespec ts;
7444 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7445 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007446 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007447 }
7448 }
7449 break;
bellard31e31b82003-02-18 22:55:36 +00007450 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007451 {
bellard1b6b0292003-03-22 17:31:38 +00007452 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007453 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007454 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007455 if (is_error(ret) && arg2) {
7456 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007457 }
7458 }
7459 break;
thse5febef2007-04-01 18:31:35 +00007460#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007461 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007462 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007463#endif
7464#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007465 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007466 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007467#endif
bellard31e31b82003-02-18 22:55:36 +00007468 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007469 switch (arg1) {
7470 case PR_GET_PDEATHSIG:
7471 {
7472 int deathsig;
7473 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7474 if (!is_error(ret) && arg2
7475 && put_user_ual(deathsig, arg2)) {
7476 goto efault;
thse5574482007-02-11 20:03:13 +00007477 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007478 break;
7479 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007480#ifdef PR_GET_NAME
7481 case PR_GET_NAME:
7482 {
7483 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7484 if (!name) {
7485 goto efault;
7486 }
7487 ret = get_errno(prctl(arg1, (unsigned long)name,
7488 arg3, arg4, arg5));
7489 unlock_user(name, arg2, 16);
7490 break;
7491 }
7492 case PR_SET_NAME:
7493 {
7494 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7495 if (!name) {
7496 goto efault;
7497 }
7498 ret = get_errno(prctl(arg1, (unsigned long)name,
7499 arg3, arg4, arg5));
7500 unlock_user(name, arg2, 0);
7501 break;
7502 }
7503#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007504 default:
7505 /* Most prctl options have no pointer arguments */
7506 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7507 break;
7508 }
ths39b9aae2007-02-11 18:36:44 +00007509 break;
bellardd2fd1af2007-11-14 18:08:56 +00007510#ifdef TARGET_NR_arch_prctl
7511 case TARGET_NR_arch_prctl:
7512#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7513 ret = do_arch_prctl(cpu_env, arg1, arg2);
7514 break;
7515#else
7516 goto unimplemented;
7517#endif
7518#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007519#ifdef TARGET_NR_pread64
7520 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007521 if (regpairs_aligned(cpu_env)) {
7522 arg4 = arg5;
7523 arg5 = arg6;
7524 }
aurel32f2c7ba12008-03-28 22:32:06 +00007525 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7526 goto efault;
7527 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7528 unlock_user(p, arg2, ret);
7529 break;
7530 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007531 if (regpairs_aligned(cpu_env)) {
7532 arg4 = arg5;
7533 arg5 = arg6;
7534 }
aurel32f2c7ba12008-03-28 22:32:06 +00007535 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7536 goto efault;
7537 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7538 unlock_user(p, arg2, 0);
7539 break;
7540#endif
bellard31e31b82003-02-18 22:55:36 +00007541 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007542 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7543 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007544 ret = get_errno(sys_getcwd1(p, arg2));
7545 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007546 break;
7547 case TARGET_NR_capget:
bellard5cd43932003-03-29 16:54:36 +00007548 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007549 case TARGET_NR_capset:
bellard5cd43932003-03-29 16:54:36 +00007550 goto unimplemented;
bellard31e31b82003-02-18 22:55:36 +00007551 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007552#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007553 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007554 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007555 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007556 break;
7557#else
bellard5cd43932003-03-29 16:54:36 +00007558 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007559#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007560
7561#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007562 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007563 {
7564 off_t *offp = NULL;
7565 off_t off;
7566 if (arg3) {
7567 ret = get_user_sal(off, arg3);
7568 if (is_error(ret)) {
7569 break;
7570 }
7571 offp = &off;
7572 }
7573 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7574 if (!is_error(ret) && arg3) {
7575 abi_long ret2 = put_user_sal(off, arg3);
7576 if (is_error(ret2)) {
7577 ret = ret2;
7578 }
7579 }
7580 break;
7581 }
7582#ifdef TARGET_NR_sendfile64
7583 case TARGET_NR_sendfile64:
7584 {
7585 off_t *offp = NULL;
7586 off_t off;
7587 if (arg3) {
7588 ret = get_user_s64(off, arg3);
7589 if (is_error(ret)) {
7590 break;
7591 }
7592 offp = &off;
7593 }
7594 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7595 if (!is_error(ret) && arg3) {
7596 abi_long ret2 = put_user_s64(off, arg3);
7597 if (is_error(ret2)) {
7598 ret = ret2;
7599 }
7600 }
7601 break;
7602 }
7603#endif
7604#else
7605 case TARGET_NR_sendfile:
7606#ifdef TARGET_NR_sendfile64:
7607 case TARGET_NR_sendfile64:
7608#endif
bellard5cd43932003-03-29 16:54:36 +00007609 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007610#endif
7611
bellardebc05482003-09-30 21:08:41 +00007612#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007613 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007614 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007615#endif
7616#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007617 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007618 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007619#endif
bellard048f6b42005-11-26 18:47:20 +00007620#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007621 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007622 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7623 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007624 break;
bellard048f6b42005-11-26 18:47:20 +00007625#endif
bellardebc05482003-09-30 21:08:41 +00007626#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007627 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007628 {
7629 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007630 int resource = target_to_host_resource(arg1);
7631 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007632 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007633 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007634 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7635 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007636 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7637 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007638 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007639 }
7640 break;
7641 }
bellardebc05482003-09-30 21:08:41 +00007642#endif
bellarda315a142005-01-30 22:59:18 +00007643#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007644 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007645 if (!(p = lock_user_string(arg1)))
7646 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007647 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7648 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007649 break;
bellarda315a142005-01-30 22:59:18 +00007650#endif
7651#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007652 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007653 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007654 break;
bellarda315a142005-01-30 22:59:18 +00007655#endif
7656#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007657 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007658 if (!(p = lock_user_string(arg1)))
7659 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007660 ret = get_errno(stat(path(p), &st));
7661 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007662 if (!is_error(ret))
7663 ret = host_to_target_stat64(cpu_env, arg2, &st);
7664 break;
bellarda315a142005-01-30 22:59:18 +00007665#endif
7666#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007667 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007668 if (!(p = lock_user_string(arg1)))
7669 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007670 ret = get_errno(lstat(path(p), &st));
7671 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007672 if (!is_error(ret))
7673 ret = host_to_target_stat64(cpu_env, arg2, &st);
7674 break;
bellarda315a142005-01-30 22:59:18 +00007675#endif
7676#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007677 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007678 ret = get_errno(fstat(arg1, &st));
7679 if (!is_error(ret))
7680 ret = host_to_target_stat64(cpu_env, arg2, &st);
7681 break;
bellardec86b0f2003-04-11 00:15:04 +00007682#endif
aurel329d33b762009-04-08 23:07:05 +00007683#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
7684 (defined(__NR_fstatat64) || defined(__NR_newfstatat))
7685#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007686 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007687#endif
7688#ifdef TARGET_NR_newfstatat
7689 case TARGET_NR_newfstatat:
7690#endif
balrog6a24a772008-09-20 02:23:36 +00007691 if (!(p = lock_user_string(arg2)))
7692 goto efault;
aurel329d33b762009-04-08 23:07:05 +00007693#ifdef __NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007694 ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
aurel329d33b762009-04-08 23:07:05 +00007695#else
7696 ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
7697#endif
balrog6a24a772008-09-20 02:23:36 +00007698 if (!is_error(ret))
7699 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007700 break;
bellarda315a142005-01-30 22:59:18 +00007701#endif
bellard67867302003-11-23 17:05:30 +00007702 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007703 if (!(p = lock_user_string(arg1)))
7704 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007705 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7706 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007707 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007708#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007709 case TARGET_NR_getuid:
7710 ret = get_errno(high2lowuid(getuid()));
7711 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007712#endif
7713#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007714 case TARGET_NR_getgid:
7715 ret = get_errno(high2lowgid(getgid()));
7716 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007717#endif
7718#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007719 case TARGET_NR_geteuid:
7720 ret = get_errno(high2lowuid(geteuid()));
7721 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007722#endif
7723#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007724 case TARGET_NR_getegid:
7725 ret = get_errno(high2lowgid(getegid()));
7726 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007727#endif
bellard67867302003-11-23 17:05:30 +00007728 case TARGET_NR_setreuid:
7729 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7730 break;
7731 case TARGET_NR_setregid:
7732 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7733 break;
7734 case TARGET_NR_getgroups:
7735 {
7736 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007737 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007738 gid_t *grouplist;
7739 int i;
7740
7741 grouplist = alloca(gidsetsize * sizeof(gid_t));
7742 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007743 if (gidsetsize == 0)
7744 break;
bellard67867302003-11-23 17:05:30 +00007745 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007746 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
7747 if (!target_grouplist)
7748 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007749 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007750 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
pbrook53a59602006-03-25 19:31:22 +00007751 unlock_user(target_grouplist, arg2, gidsetsize * 2);
bellard67867302003-11-23 17:05:30 +00007752 }
7753 }
7754 break;
7755 case TARGET_NR_setgroups:
7756 {
7757 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007758 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007759 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007760 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007761 if (gidsetsize) {
7762 grouplist = alloca(gidsetsize * sizeof(gid_t));
7763 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
7764 if (!target_grouplist) {
7765 ret = -TARGET_EFAULT;
7766 goto fail;
7767 }
7768 for (i = 0; i < gidsetsize; i++) {
7769 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7770 }
7771 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007772 }
bellard67867302003-11-23 17:05:30 +00007773 ret = get_errno(setgroups(gidsetsize, grouplist));
7774 }
7775 break;
7776 case TARGET_NR_fchown:
7777 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7778 break;
thsccfa72b2007-09-24 09:23:34 +00007779#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
7780 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007781 if (!(p = lock_user_string(arg2)))
7782 goto efault;
7783 ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
7784 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007785 break;
7786#endif
bellard67867302003-11-23 17:05:30 +00007787#ifdef TARGET_NR_setresuid
7788 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007789 ret = get_errno(setresuid(low2highuid(arg1),
7790 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007791 low2highuid(arg3)));
7792 break;
7793#endif
7794#ifdef TARGET_NR_getresuid
7795 case TARGET_NR_getresuid:
7796 {
pbrook53a59602006-03-25 19:31:22 +00007797 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007798 ret = get_errno(getresuid(&ruid, &euid, &suid));
7799 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007800 if (put_user_u16(high2lowuid(ruid), arg1)
7801 || put_user_u16(high2lowuid(euid), arg2)
7802 || put_user_u16(high2lowuid(suid), arg3))
7803 goto efault;
bellard67867302003-11-23 17:05:30 +00007804 }
7805 }
7806 break;
7807#endif
7808#ifdef TARGET_NR_getresgid
7809 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007810 ret = get_errno(setresgid(low2highgid(arg1),
7811 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007812 low2highgid(arg3)));
7813 break;
7814#endif
7815#ifdef TARGET_NR_getresgid
7816 case TARGET_NR_getresgid:
7817 {
pbrook53a59602006-03-25 19:31:22 +00007818 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007819 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7820 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00007821 if (put_user_u16(high2lowgid(rgid), arg1)
7822 || put_user_u16(high2lowgid(egid), arg2)
7823 || put_user_u16(high2lowgid(sgid), arg3))
7824 goto efault;
bellard67867302003-11-23 17:05:30 +00007825 }
7826 }
7827 break;
7828#endif
7829 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007830 if (!(p = lock_user_string(arg1)))
7831 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007832 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7833 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007834 break;
7835 case TARGET_NR_setuid:
7836 ret = get_errno(setuid(low2highuid(arg1)));
7837 break;
7838 case TARGET_NR_setgid:
7839 ret = get_errno(setgid(low2highgid(arg1)));
7840 break;
7841 case TARGET_NR_setfsuid:
7842 ret = get_errno(setfsuid(arg1));
7843 break;
7844 case TARGET_NR_setfsgid:
7845 ret = get_errno(setfsgid(arg1));
7846 break;
bellard67867302003-11-23 17:05:30 +00007847
bellarda315a142005-01-30 22:59:18 +00007848#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007849 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007850 if (!(p = lock_user_string(arg1)))
7851 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007852 ret = get_errno(lchown(p, arg2, arg3));
7853 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007854 break;
bellarda315a142005-01-30 22:59:18 +00007855#endif
7856#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007857 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007858 ret = get_errno(getuid());
7859 break;
bellarda315a142005-01-30 22:59:18 +00007860#endif
aurel3264b4d282008-11-14 17:20:15 +00007861
7862#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
7863 /* Alpha specific */
7864 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007865 {
7866 uid_t euid;
7867 euid=geteuid();
7868 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
7869 }
aurel3264b4d282008-11-14 17:20:15 +00007870 ret = get_errno(getuid());
7871 break;
7872#endif
7873#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
7874 /* Alpha specific */
7875 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007876 {
7877 uid_t egid;
7878 egid=getegid();
7879 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
7880 }
aurel3264b4d282008-11-14 17:20:15 +00007881 ret = get_errno(getgid());
7882 break;
7883#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08007884#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
7885 /* Alpha specific */
7886 case TARGET_NR_osf_getsysinfo:
7887 ret = -TARGET_EOPNOTSUPP;
7888 switch (arg1) {
7889 case TARGET_GSI_IEEE_FP_CONTROL:
7890 {
7891 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
7892
7893 /* Copied from linux ieee_fpcr_to_swcr. */
7894 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
7895 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
7896 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
7897 | SWCR_TRAP_ENABLE_DZE
7898 | SWCR_TRAP_ENABLE_OVF);
7899 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
7900 | SWCR_TRAP_ENABLE_INE);
7901 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
7902 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
7903
7904 if (put_user_u64 (swcr, arg2))
7905 goto efault;
7906 ret = 0;
7907 }
7908 break;
7909
7910 /* case GSI_IEEE_STATE_AT_SIGNAL:
7911 -- Not implemented in linux kernel.
7912 case GSI_UACPROC:
7913 -- Retrieves current unaligned access state; not much used.
7914 case GSI_PROC_TYPE:
7915 -- Retrieves implver information; surely not used.
7916 case GSI_GET_HWRPB:
7917 -- Grabs a copy of the HWRPB; surely not used.
7918 */
7919 }
7920 break;
7921#endif
7922#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
7923 /* Alpha specific */
7924 case TARGET_NR_osf_setsysinfo:
7925 ret = -TARGET_EOPNOTSUPP;
7926 switch (arg1) {
7927 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08007928 {
7929 uint64_t swcr, fpcr, orig_fpcr;
7930
Richard Henderson6e06d512012-06-01 09:08:21 -07007931 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08007932 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07007933 }
7934 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007935 fpcr = orig_fpcr & FPCR_DYN_MASK;
7936
7937 /* Copied from linux ieee_swcr_to_fpcr. */
7938 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
7939 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
7940 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
7941 | SWCR_TRAP_ENABLE_DZE
7942 | SWCR_TRAP_ENABLE_OVF)) << 48;
7943 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
7944 | SWCR_TRAP_ENABLE_INE)) << 57;
7945 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
7946 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
7947
Richard Henderson6e06d512012-06-01 09:08:21 -07007948 cpu_alpha_store_fpcr(cpu_env, fpcr);
7949 ret = 0;
7950 }
7951 break;
7952
7953 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
7954 {
7955 uint64_t exc, fpcr, orig_fpcr;
7956 int si_code;
7957
7958 if (get_user_u64(exc, arg2)) {
7959 goto efault;
7960 }
7961
7962 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
7963
7964 /* We only add to the exception status here. */
7965 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
7966
7967 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007968 ret = 0;
7969
Richard Henderson6e06d512012-06-01 09:08:21 -07007970 /* Old exceptions are not signaled. */
7971 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007972
Richard Henderson6e06d512012-06-01 09:08:21 -07007973 /* If any exceptions set by this call,
7974 and are unmasked, send a signal. */
7975 si_code = 0;
7976 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
7977 si_code = TARGET_FPE_FLTRES;
7978 }
7979 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
7980 si_code = TARGET_FPE_FLTUND;
7981 }
7982 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
7983 si_code = TARGET_FPE_FLTOVF;
7984 }
7985 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
7986 si_code = TARGET_FPE_FLTDIV;
7987 }
7988 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
7989 si_code = TARGET_FPE_FLTINV;
7990 }
7991 if (si_code != 0) {
7992 target_siginfo_t info;
7993 info.si_signo = SIGFPE;
7994 info.si_errno = 0;
7995 info.si_code = si_code;
7996 info._sifields._sigfault._addr
7997 = ((CPUArchState *)cpu_env)->pc;
7998 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08007999 }
8000 }
8001 break;
8002
8003 /* case SSI_NVPAIRS:
8004 -- Used with SSIN_UACPROC to enable unaligned accesses.
8005 case SSI_IEEE_STATE_AT_SIGNAL:
8006 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8007 -- Not implemented in linux kernel
8008 */
8009 }
8010 break;
8011#endif
8012#ifdef TARGET_NR_osf_sigprocmask
8013 /* Alpha specific. */
8014 case TARGET_NR_osf_sigprocmask:
8015 {
8016 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008017 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008018 sigset_t set, oldset;
8019
8020 switch(arg1) {
8021 case TARGET_SIG_BLOCK:
8022 how = SIG_BLOCK;
8023 break;
8024 case TARGET_SIG_UNBLOCK:
8025 how = SIG_UNBLOCK;
8026 break;
8027 case TARGET_SIG_SETMASK:
8028 how = SIG_SETMASK;
8029 break;
8030 default:
8031 ret = -TARGET_EINVAL;
8032 goto fail;
8033 }
8034 mask = arg2;
8035 target_to_host_old_sigset(&set, &mask);
Juan Quintelabc088ba2011-06-16 17:37:10 +01008036 sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008037 host_to_target_old_sigset(&mask, &oldset);
8038 ret = mask;
8039 }
8040 break;
8041#endif
aurel3264b4d282008-11-14 17:20:15 +00008042
bellarda315a142005-01-30 22:59:18 +00008043#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008044 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008045 ret = get_errno(getgid());
8046 break;
bellarda315a142005-01-30 22:59:18 +00008047#endif
8048#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008049 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008050 ret = get_errno(geteuid());
8051 break;
bellarda315a142005-01-30 22:59:18 +00008052#endif
8053#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008054 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008055 ret = get_errno(getegid());
8056 break;
bellarda315a142005-01-30 22:59:18 +00008057#endif
8058#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008059 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008060 ret = get_errno(setreuid(arg1, arg2));
8061 break;
bellarda315a142005-01-30 22:59:18 +00008062#endif
8063#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008064 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008065 ret = get_errno(setregid(arg1, arg2));
8066 break;
bellarda315a142005-01-30 22:59:18 +00008067#endif
8068#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008069 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008070 {
8071 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008072 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008073 gid_t *grouplist;
8074 int i;
8075
8076 grouplist = alloca(gidsetsize * sizeof(gid_t));
8077 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008078 if (gidsetsize == 0)
8079 break;
bellard99c475a2005-01-31 20:45:13 +00008080 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008081 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8082 if (!target_grouplist) {
8083 ret = -TARGET_EFAULT;
8084 goto fail;
8085 }
balroga2155fc2008-09-20 02:12:08 +00008086 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008087 target_grouplist[i] = tswap32(grouplist[i]);
8088 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008089 }
8090 }
8091 break;
bellarda315a142005-01-30 22:59:18 +00008092#endif
8093#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008094 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008095 {
8096 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008097 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008098 gid_t *grouplist;
8099 int i;
ths3b46e622007-09-17 08:09:54 +00008100
bellard99c475a2005-01-31 20:45:13 +00008101 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008102 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8103 if (!target_grouplist) {
8104 ret = -TARGET_EFAULT;
8105 goto fail;
8106 }
bellard99c475a2005-01-31 20:45:13 +00008107 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008108 grouplist[i] = tswap32(target_grouplist[i]);
8109 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008110 ret = get_errno(setgroups(gidsetsize, grouplist));
8111 }
8112 break;
bellarda315a142005-01-30 22:59:18 +00008113#endif
8114#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008115 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008116 ret = get_errno(fchown(arg1, arg2, arg3));
8117 break;
bellarda315a142005-01-30 22:59:18 +00008118#endif
8119#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008120 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008121 ret = get_errno(setresuid(arg1, arg2, arg3));
8122 break;
bellarda315a142005-01-30 22:59:18 +00008123#endif
8124#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008125 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008126 {
pbrook53a59602006-03-25 19:31:22 +00008127 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008128 ret = get_errno(getresuid(&ruid, &euid, &suid));
8129 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008130 if (put_user_u32(ruid, arg1)
8131 || put_user_u32(euid, arg2)
8132 || put_user_u32(suid, arg3))
8133 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008134 }
8135 }
8136 break;
bellarda315a142005-01-30 22:59:18 +00008137#endif
8138#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008139 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008140 ret = get_errno(setresgid(arg1, arg2, arg3));
8141 break;
bellarda315a142005-01-30 22:59:18 +00008142#endif
8143#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008144 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008145 {
pbrook53a59602006-03-25 19:31:22 +00008146 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008147 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8148 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008149 if (put_user_u32(rgid, arg1)
8150 || put_user_u32(egid, arg2)
8151 || put_user_u32(sgid, arg3))
8152 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008153 }
8154 }
8155 break;
bellarda315a142005-01-30 22:59:18 +00008156#endif
8157#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008158 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008159 if (!(p = lock_user_string(arg1)))
8160 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008161 ret = get_errno(chown(p, arg2, arg3));
8162 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008163 break;
bellarda315a142005-01-30 22:59:18 +00008164#endif
8165#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008166 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008167 ret = get_errno(setuid(arg1));
8168 break;
bellarda315a142005-01-30 22:59:18 +00008169#endif
8170#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008171 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008172 ret = get_errno(setgid(arg1));
8173 break;
bellarda315a142005-01-30 22:59:18 +00008174#endif
8175#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008176 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008177 ret = get_errno(setfsuid(arg1));
8178 break;
bellarda315a142005-01-30 22:59:18 +00008179#endif
8180#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008181 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008182 ret = get_errno(setfsgid(arg1));
8183 break;
bellarda315a142005-01-30 22:59:18 +00008184#endif
bellard67867302003-11-23 17:05:30 +00008185
bellard31e31b82003-02-18 22:55:36 +00008186 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008187 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008188#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008189 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008190 {
8191 void *a;
8192 ret = -TARGET_EFAULT;
8193 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8194 goto efault;
8195 if (!(p = lock_user_string(arg3)))
8196 goto mincore_fail;
8197 ret = get_errno(mincore(a, arg2, p));
8198 unlock_user(p, arg3, ret);
8199 mincore_fail:
8200 unlock_user(a, arg1, 0);
8201 }
8202 break;
bellardffa65c32004-01-04 23:57:22 +00008203#endif
aurel32408321b2008-10-01 21:46:32 +00008204#ifdef TARGET_NR_arm_fadvise64_64
8205 case TARGET_NR_arm_fadvise64_64:
8206 {
8207 /*
8208 * arm_fadvise64_64 looks like fadvise64_64 but
8209 * with different argument order
8210 */
8211 abi_long temp;
8212 temp = arg3;
8213 arg3 = arg4;
8214 arg4 = temp;
8215 }
8216#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008217#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008218#ifdef TARGET_NR_fadvise64_64
8219 case TARGET_NR_fadvise64_64:
8220#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008221#ifdef TARGET_NR_fadvise64
8222 case TARGET_NR_fadvise64:
8223#endif
8224#ifdef TARGET_S390X
8225 switch (arg4) {
8226 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8227 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8228 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8229 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8230 default: break;
8231 }
8232#endif
8233 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008234 break;
8235#endif
bellardffa65c32004-01-04 23:57:22 +00008236#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008237 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008238 /* A straight passthrough may not be safe because qemu sometimes
8239 turns private flie-backed mappings into anonymous mappings.
8240 This will break MADV_DONTNEED.
8241 This is a hint, so ignoring and returning success is ok. */
8242 ret = get_errno(0);
8243 break;
bellardffa65c32004-01-04 23:57:22 +00008244#endif
blueswir1992f48a2007-10-14 16:27:31 +00008245#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008246 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008247 {
thsb1e341e2007-03-20 21:50:52 +00008248 int cmd;
bellard77e46722003-04-29 20:39:06 +00008249 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008250 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008251#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008252 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008253#endif
bellard77e46722003-04-29 20:39:06 +00008254
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008255 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008256 if (cmd == -TARGET_EINVAL) {
8257 ret = cmd;
8258 break;
8259 }
thsb1e341e2007-03-20 21:50:52 +00008260
bellard60cd49d2003-03-16 22:53:56 +00008261 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008262 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008263#ifdef TARGET_ARM
8264 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008265 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8266 goto efault;
ths58134272007-03-31 18:59:32 +00008267 fl.l_type = tswap16(target_efl->l_type);
8268 fl.l_whence = tswap16(target_efl->l_whence);
8269 fl.l_start = tswap64(target_efl->l_start);
8270 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008271 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008272 unlock_user_struct(target_efl, arg3, 0);
8273 } else
8274#endif
8275 {
bellard9ee1fa22007-11-11 15:11:19 +00008276 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8277 goto efault;
ths58134272007-03-31 18:59:32 +00008278 fl.l_type = tswap16(target_fl->l_type);
8279 fl.l_whence = tswap16(target_fl->l_whence);
8280 fl.l_start = tswap64(target_fl->l_start);
8281 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008282 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008283 unlock_user_struct(target_fl, arg3, 0);
8284 }
thsb1e341e2007-03-20 21:50:52 +00008285 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008286 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008287#ifdef TARGET_ARM
8288 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008289 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8290 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008291 target_efl->l_type = tswap16(fl.l_type);
8292 target_efl->l_whence = tswap16(fl.l_whence);
8293 target_efl->l_start = tswap64(fl.l_start);
8294 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008295 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008296 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008297 } else
8298#endif
8299 {
bellard9ee1fa22007-11-11 15:11:19 +00008300 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8301 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008302 target_fl->l_type = tswap16(fl.l_type);
8303 target_fl->l_whence = tswap16(fl.l_whence);
8304 target_fl->l_start = tswap64(fl.l_start);
8305 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008306 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008307 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008308 }
bellard77e46722003-04-29 20:39:06 +00008309 }
8310 break;
8311
thsb1e341e2007-03-20 21:50:52 +00008312 case TARGET_F_SETLK64:
8313 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008314#ifdef TARGET_ARM
8315 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008316 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8317 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008318 fl.l_type = tswap16(target_efl->l_type);
8319 fl.l_whence = tswap16(target_efl->l_whence);
8320 fl.l_start = tswap64(target_efl->l_start);
8321 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008322 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008323 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008324 } else
8325#endif
8326 {
bellard9ee1fa22007-11-11 15:11:19 +00008327 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8328 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008329 fl.l_type = tswap16(target_fl->l_type);
8330 fl.l_whence = tswap16(target_fl->l_whence);
8331 fl.l_start = tswap64(target_fl->l_start);
8332 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008333 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008334 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008335 }
thsb1e341e2007-03-20 21:50:52 +00008336 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008337 break;
bellard60cd49d2003-03-16 22:53:56 +00008338 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008339 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008340 break;
8341 }
bellard77e46722003-04-29 20:39:06 +00008342 break;
8343 }
bellard60cd49d2003-03-16 22:53:56 +00008344#endif
ths7d600c82006-12-08 01:32:58 +00008345#ifdef TARGET_NR_cacheflush
8346 case TARGET_NR_cacheflush:
8347 /* self-modifying code is handled automatically, so nothing needed */
8348 ret = 0;
8349 break;
8350#endif
bellardebc05482003-09-30 21:08:41 +00008351#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008352 case TARGET_NR_security:
8353 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008354#endif
bellardc573ff62004-01-04 15:51:36 +00008355#ifdef TARGET_NR_getpagesize
8356 case TARGET_NR_getpagesize:
8357 ret = TARGET_PAGE_SIZE;
8358 break;
8359#endif
bellard31e31b82003-02-18 22:55:36 +00008360 case TARGET_NR_gettid:
8361 ret = get_errno(gettid());
8362 break;
thse5febef2007-04-01 18:31:35 +00008363#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008364 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008365#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008366 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008367 arg2 = arg3;
8368 arg3 = arg4;
8369 arg4 = arg5;
8370 }
aurel322054ac92008-10-13 21:08:07 +00008371 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8372#else
8373 ret = get_errno(readahead(arg1, arg2, arg3));
8374#endif
8375 break;
thse5febef2007-04-01 18:31:35 +00008376#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008377#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008378#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008379 case TARGET_NR_listxattr:
8380 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008381 {
8382 void *p, *b = 0;
8383 if (arg2) {
8384 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8385 if (!b) {
8386 ret = -TARGET_EFAULT;
8387 break;
8388 }
8389 }
8390 p = lock_user_string(arg1);
8391 if (p) {
8392 if (num == TARGET_NR_listxattr) {
8393 ret = get_errno(listxattr(p, b, arg3));
8394 } else {
8395 ret = get_errno(llistxattr(p, b, arg3));
8396 }
8397 } else {
8398 ret = -TARGET_EFAULT;
8399 }
8400 unlock_user(p, arg1, 0);
8401 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008402 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008403 }
8404 case TARGET_NR_flistxattr:
8405 {
8406 void *b = 0;
8407 if (arg2) {
8408 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8409 if (!b) {
8410 ret = -TARGET_EFAULT;
8411 break;
8412 }
8413 }
8414 ret = get_errno(flistxattr(arg1, b, arg3));
8415 unlock_user(b, arg2, arg3);
8416 break;
8417 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008418 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008419 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008420 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008421 void *p, *n, *v = 0;
8422 if (arg3) {
8423 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8424 if (!v) {
8425 ret = -TARGET_EFAULT;
8426 break;
8427 }
8428 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008429 p = lock_user_string(arg1);
8430 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008431 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008432 if (num == TARGET_NR_setxattr) {
8433 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8434 } else {
8435 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8436 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008437 } else {
8438 ret = -TARGET_EFAULT;
8439 }
8440 unlock_user(p, arg1, 0);
8441 unlock_user(n, arg2, 0);
8442 unlock_user(v, arg3, 0);
8443 }
8444 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008445 case TARGET_NR_fsetxattr:
8446 {
8447 void *n, *v = 0;
8448 if (arg3) {
8449 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8450 if (!v) {
8451 ret = -TARGET_EFAULT;
8452 break;
8453 }
8454 }
8455 n = lock_user_string(arg2);
8456 if (n) {
8457 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8458 } else {
8459 ret = -TARGET_EFAULT;
8460 }
8461 unlock_user(n, arg2, 0);
8462 unlock_user(v, arg3, 0);
8463 }
8464 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008465 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008466 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008467 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008468 void *p, *n, *v = 0;
8469 if (arg3) {
8470 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8471 if (!v) {
8472 ret = -TARGET_EFAULT;
8473 break;
8474 }
8475 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008476 p = lock_user_string(arg1);
8477 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008478 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008479 if (num == TARGET_NR_getxattr) {
8480 ret = get_errno(getxattr(p, n, v, arg4));
8481 } else {
8482 ret = get_errno(lgetxattr(p, n, v, arg4));
8483 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008484 } else {
8485 ret = -TARGET_EFAULT;
8486 }
8487 unlock_user(p, arg1, 0);
8488 unlock_user(n, arg2, 0);
8489 unlock_user(v, arg3, arg4);
8490 }
8491 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008492 case TARGET_NR_fgetxattr:
8493 {
8494 void *n, *v = 0;
8495 if (arg3) {
8496 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8497 if (!v) {
8498 ret = -TARGET_EFAULT;
8499 break;
8500 }
8501 }
8502 n = lock_user_string(arg2);
8503 if (n) {
8504 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8505 } else {
8506 ret = -TARGET_EFAULT;
8507 }
8508 unlock_user(n, arg2, 0);
8509 unlock_user(v, arg3, arg4);
8510 }
8511 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008512 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008513 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008514 {
8515 void *p, *n;
8516 p = lock_user_string(arg1);
8517 n = lock_user_string(arg2);
8518 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008519 if (num == TARGET_NR_removexattr) {
8520 ret = get_errno(removexattr(p, n));
8521 } else {
8522 ret = get_errno(lremovexattr(p, n));
8523 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008524 } else {
8525 ret = -TARGET_EFAULT;
8526 }
8527 unlock_user(p, arg1, 0);
8528 unlock_user(n, arg2, 0);
8529 }
8530 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008531 case TARGET_NR_fremovexattr:
8532 {
8533 void *n;
8534 n = lock_user_string(arg2);
8535 if (n) {
8536 ret = get_errno(fremovexattr(arg1, n));
8537 } else {
8538 ret = -TARGET_EFAULT;
8539 }
8540 unlock_user(n, arg2, 0);
8541 }
8542 break;
bellardebc05482003-09-30 21:08:41 +00008543#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008544#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008545#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008546 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008547#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008548 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8549 ret = 0;
8550 break;
edgar_iglef967792009-01-07 14:19:38 +00008551#elif defined(TARGET_CRIS)
8552 if (arg1 & 0xff)
8553 ret = -TARGET_EINVAL;
8554 else {
8555 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8556 ret = 0;
8557 }
8558 break;
bellard8d18e892007-11-14 15:18:40 +00008559#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8560 ret = do_set_thread_area(cpu_env, arg1);
8561 break;
ths6f5b89a2007-03-02 20:48:00 +00008562#else
8563 goto unimplemented_nowarn;
8564#endif
8565#endif
8566#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008567 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008568#if defined(TARGET_I386) && defined(TARGET_ABI32)
8569 ret = do_get_thread_area(cpu_env, arg1);
8570#else
bellard5cd43932003-03-29 16:54:36 +00008571 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008572#endif
bellard8d18e892007-11-14 15:18:40 +00008573#endif
bellard48dc41e2006-06-21 18:15:50 +00008574#ifdef TARGET_NR_getdomainname
8575 case TARGET_NR_getdomainname:
8576 goto unimplemented_nowarn;
8577#endif
ths6f5b89a2007-03-02 20:48:00 +00008578
thsb5906f92007-03-19 13:32:45 +00008579#ifdef TARGET_NR_clock_gettime
8580 case TARGET_NR_clock_gettime:
8581 {
8582 struct timespec ts;
8583 ret = get_errno(clock_gettime(arg1, &ts));
8584 if (!is_error(ret)) {
8585 host_to_target_timespec(arg2, &ts);
8586 }
8587 break;
8588 }
8589#endif
8590#ifdef TARGET_NR_clock_getres
8591 case TARGET_NR_clock_getres:
8592 {
8593 struct timespec ts;
8594 ret = get_errno(clock_getres(arg1, &ts));
8595 if (!is_error(ret)) {
8596 host_to_target_timespec(arg2, &ts);
8597 }
8598 break;
8599 }
8600#endif
pbrook63d76512008-05-29 13:43:29 +00008601#ifdef TARGET_NR_clock_nanosleep
8602 case TARGET_NR_clock_nanosleep:
8603 {
8604 struct timespec ts;
8605 target_to_host_timespec(&ts, arg3);
8606 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8607 if (arg4)
8608 host_to_target_timespec(arg4, &ts);
8609 break;
8610 }
8611#endif
thsb5906f92007-03-19 13:32:45 +00008612
ths6f5b89a2007-03-02 20:48:00 +00008613#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8614 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008615 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8616 break;
ths6f5b89a2007-03-02 20:48:00 +00008617#endif
8618
ths3ae43202007-09-16 21:39:48 +00008619#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008620 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008621 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008622 break;
8623#endif
8624
ths3ae43202007-09-16 21:39:48 +00008625#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008626 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008627 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8628 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008629 break;
8630#endif
8631
ths4f2b1fe2007-06-21 21:57:12 +00008632#ifdef TARGET_NR_set_robust_list
8633 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008634 case TARGET_NR_get_robust_list:
8635 /* The ABI for supporting robust futexes has userspace pass
8636 * the kernel a pointer to a linked list which is updated by
8637 * userspace after the syscall; the list is walked by the kernel
8638 * when the thread exits. Since the linked list in QEMU guest
8639 * memory isn't a valid linked list for the host and we have
8640 * no way to reliably intercept the thread-death event, we can't
8641 * support these. Silently return ENOSYS so that guest userspace
8642 * falls back to a non-robust futex implementation (which should
8643 * be OK except in the corner case of the guest crashing while
8644 * holding a mutex that is shared with another process via
8645 * shared memory).
8646 */
8647 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008648#endif
8649
ths9007f0e2007-09-25 17:50:37 +00008650#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
8651 case TARGET_NR_utimensat:
8652 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008653 struct timespec *tsp, ts[2];
8654 if (!arg3) {
8655 tsp = NULL;
8656 } else {
8657 target_to_host_timespec(ts, arg3);
8658 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8659 tsp = ts;
8660 }
ths9007f0e2007-09-25 17:50:37 +00008661 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008662 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008663 else {
bellard579a97f2007-11-11 14:26:47 +00008664 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008665 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008666 goto fail;
8667 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008668 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008669 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008670 }
8671 }
8672 break;
8673#endif
Juan Quintela2f7bb872009-07-27 16:13:24 +02008674#if defined(CONFIG_USE_NPTL)
pbrookbd0c5662008-05-29 14:34:11 +00008675 case TARGET_NR_futex:
8676 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8677 break;
8678#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008679#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008680 case TARGET_NR_inotify_init:
8681 ret = get_errno(sys_inotify_init());
8682 break;
8683#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008684#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008685#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8686 case TARGET_NR_inotify_init1:
8687 ret = get_errno(sys_inotify_init1(arg1));
8688 break;
8689#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008690#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008691#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008692 case TARGET_NR_inotify_add_watch:
8693 p = lock_user_string(arg2);
8694 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8695 unlock_user(p, arg2, 0);
8696 break;
8697#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008698#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008699 case TARGET_NR_inotify_rm_watch:
8700 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8701 break;
8702#endif
ths9007f0e2007-09-25 17:50:37 +00008703
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008704#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008705 case TARGET_NR_mq_open:
8706 {
8707 struct mq_attr posix_mq_attr;
8708
8709 p = lock_user_string(arg1 - 1);
8710 if (arg4 != 0)
8711 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8712 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8713 unlock_user (p, arg1, 0);
8714 }
8715 break;
8716
8717 case TARGET_NR_mq_unlink:
8718 p = lock_user_string(arg1 - 1);
8719 ret = get_errno(mq_unlink(p));
8720 unlock_user (p, arg1, 0);
8721 break;
8722
8723 case TARGET_NR_mq_timedsend:
8724 {
8725 struct timespec ts;
8726
8727 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8728 if (arg5 != 0) {
8729 target_to_host_timespec(&ts, arg5);
8730 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8731 host_to_target_timespec(arg5, &ts);
8732 }
8733 else
8734 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8735 unlock_user (p, arg2, arg3);
8736 }
8737 break;
8738
8739 case TARGET_NR_mq_timedreceive:
8740 {
8741 struct timespec ts;
8742 unsigned int prio;
8743
8744 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8745 if (arg5 != 0) {
8746 target_to_host_timespec(&ts, arg5);
8747 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8748 host_to_target_timespec(arg5, &ts);
8749 }
8750 else
8751 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8752 unlock_user (p, arg2, arg3);
8753 if (arg4 != 0)
8754 put_user_u32(prio, arg4);
8755 }
8756 break;
8757
8758 /* Not implemented for now... */
8759/* case TARGET_NR_mq_notify: */
8760/* break; */
8761
8762 case TARGET_NR_mq_getsetattr:
8763 {
8764 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8765 ret = 0;
8766 if (arg3 != 0) {
8767 ret = mq_getattr(arg1, &posix_mq_attr_out);
8768 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8769 }
8770 if (arg2 != 0) {
8771 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8772 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8773 }
8774
8775 }
8776 break;
8777#endif
8778
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308779#ifdef CONFIG_SPLICE
8780#ifdef TARGET_NR_tee
8781 case TARGET_NR_tee:
8782 {
8783 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8784 }
8785 break;
8786#endif
8787#ifdef TARGET_NR_splice
8788 case TARGET_NR_splice:
8789 {
8790 loff_t loff_in, loff_out;
8791 loff_t *ploff_in = NULL, *ploff_out = NULL;
8792 if(arg2) {
8793 get_user_u64(loff_in, arg2);
8794 ploff_in = &loff_in;
8795 }
8796 if(arg4) {
8797 get_user_u64(loff_out, arg2);
8798 ploff_out = &loff_out;
8799 }
8800 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8801 }
8802 break;
8803#endif
8804#ifdef TARGET_NR_vmsplice
8805 case TARGET_NR_vmsplice:
8806 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008807 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8808 if (vec != NULL) {
8809 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8810 unlock_iovec(vec, arg2, arg3, 0);
8811 } else {
8812 ret = -host_to_target_errno(errno);
8813 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308814 }
8815 break;
8816#endif
8817#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008818#ifdef CONFIG_EVENTFD
8819#if defined(TARGET_NR_eventfd)
8820 case TARGET_NR_eventfd:
8821 ret = get_errno(eventfd(arg1, 0));
8822 break;
8823#endif
8824#if defined(TARGET_NR_eventfd2)
8825 case TARGET_NR_eventfd2:
8826 ret = get_errno(eventfd(arg1, arg2));
8827 break;
8828#endif
8829#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008830#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8831 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008832#if TARGET_ABI_BITS == 32
8833 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8834 target_offset64(arg5, arg6)));
8835#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008836 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008837#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008838 break;
8839#endif
Peter Maydellc727f472011-01-06 11:05:10 +00008840#if defined(CONFIG_SYNC_FILE_RANGE)
8841#if defined(TARGET_NR_sync_file_range)
8842 case TARGET_NR_sync_file_range:
8843#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03008844#if defined(TARGET_MIPS)
8845 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8846 target_offset64(arg5, arg6), arg7));
8847#else
Peter Maydellc727f472011-01-06 11:05:10 +00008848 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
8849 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03008850#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00008851#else
8852 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
8853#endif
8854 break;
8855#endif
8856#if defined(TARGET_NR_sync_file_range2)
8857 case TARGET_NR_sync_file_range2:
8858 /* This is like sync_file_range but the arguments are reordered */
8859#if TARGET_ABI_BITS == 32
8860 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
8861 target_offset64(arg5, arg6), arg2));
8862#else
8863 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
8864#endif
8865 break;
8866#endif
8867#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00008868#if defined(CONFIG_EPOLL)
8869#if defined(TARGET_NR_epoll_create)
8870 case TARGET_NR_epoll_create:
8871 ret = get_errno(epoll_create(arg1));
8872 break;
8873#endif
8874#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
8875 case TARGET_NR_epoll_create1:
8876 ret = get_errno(epoll_create1(arg1));
8877 break;
8878#endif
8879#if defined(TARGET_NR_epoll_ctl)
8880 case TARGET_NR_epoll_ctl:
8881 {
8882 struct epoll_event ep;
8883 struct epoll_event *epp = 0;
8884 if (arg4) {
8885 struct target_epoll_event *target_ep;
8886 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
8887 goto efault;
8888 }
8889 ep.events = tswap32(target_ep->events);
8890 /* The epoll_data_t union is just opaque data to the kernel,
8891 * so we transfer all 64 bits across and need not worry what
8892 * actual data type it is.
8893 */
8894 ep.data.u64 = tswap64(target_ep->data.u64);
8895 unlock_user_struct(target_ep, arg4, 0);
8896 epp = &ep;
8897 }
8898 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
8899 break;
8900 }
8901#endif
8902
8903#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
8904#define IMPLEMENT_EPOLL_PWAIT
8905#endif
8906#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
8907#if defined(TARGET_NR_epoll_wait)
8908 case TARGET_NR_epoll_wait:
8909#endif
8910#if defined(IMPLEMENT_EPOLL_PWAIT)
8911 case TARGET_NR_epoll_pwait:
8912#endif
8913 {
8914 struct target_epoll_event *target_ep;
8915 struct epoll_event *ep;
8916 int epfd = arg1;
8917 int maxevents = arg3;
8918 int timeout = arg4;
8919
8920 target_ep = lock_user(VERIFY_WRITE, arg2,
8921 maxevents * sizeof(struct target_epoll_event), 1);
8922 if (!target_ep) {
8923 goto efault;
8924 }
8925
8926 ep = alloca(maxevents * sizeof(struct epoll_event));
8927
8928 switch (num) {
8929#if defined(IMPLEMENT_EPOLL_PWAIT)
8930 case TARGET_NR_epoll_pwait:
8931 {
8932 target_sigset_t *target_set;
8933 sigset_t _set, *set = &_set;
8934
8935 if (arg5) {
8936 target_set = lock_user(VERIFY_READ, arg5,
8937 sizeof(target_sigset_t), 1);
8938 if (!target_set) {
8939 unlock_user(target_ep, arg2, 0);
8940 goto efault;
8941 }
8942 target_to_host_sigset(set, target_set);
8943 unlock_user(target_set, arg5, 0);
8944 } else {
8945 set = NULL;
8946 }
8947
8948 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
8949 break;
8950 }
8951#endif
8952#if defined(TARGET_NR_epoll_wait)
8953 case TARGET_NR_epoll_wait:
8954 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
8955 break;
8956#endif
8957 default:
8958 ret = -TARGET_ENOSYS;
8959 }
8960 if (!is_error(ret)) {
8961 int i;
8962 for (i = 0; i < ret; i++) {
8963 target_ep[i].events = tswap32(ep[i].events);
8964 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
8965 }
8966 }
8967 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
8968 break;
8969 }
8970#endif
8971#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01008972#ifdef TARGET_NR_prlimit64
8973 case TARGET_NR_prlimit64:
8974 {
8975 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
8976 struct target_rlimit64 *target_rnew, *target_rold;
8977 struct host_rlimit64 rnew, rold, *rnewp = 0;
8978 if (arg3) {
8979 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
8980 goto efault;
8981 }
8982 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
8983 rnew.rlim_max = tswap64(target_rnew->rlim_max);
8984 unlock_user_struct(target_rnew, arg3, 0);
8985 rnewp = &rnew;
8986 }
8987
8988 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
8989 if (!is_error(ret) && arg4) {
8990 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
8991 goto efault;
8992 }
8993 target_rold->rlim_cur = tswap64(rold.rlim_cur);
8994 target_rold->rlim_max = tswap64(rold.rlim_max);
8995 unlock_user_struct(target_rold, arg4, 1);
8996 }
8997 break;
8998 }
8999#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009000#ifdef TARGET_NR_gethostname
9001 case TARGET_NR_gethostname:
9002 {
9003 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9004 if (name) {
9005 ret = get_errno(gethostname(name, arg2));
9006 unlock_user(name, arg1, arg2);
9007 } else {
9008 ret = -TARGET_EFAULT;
9009 }
9010 break;
9011 }
9012#endif
bellard31e31b82003-02-18 22:55:36 +00009013 default:
9014 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009015 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009016#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 +00009017 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009018#endif
ths0da46a62007-10-20 20:23:07 +00009019 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009020 break;
9021 }
bellard579a97f2007-11-11 14:26:47 +00009022fail:
bellardc573ff62004-01-04 15:51:36 +00009023#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009024 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009025#endif
thsb92c47c2007-11-01 00:07:38 +00009026 if(do_strace)
9027 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009028 return ret;
bellard579a97f2007-11-11 14:26:47 +00009029efault:
9030 ret = -TARGET_EFAULT;
9031 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009032}