blob: a175cc15f8c538182b4b6f0813790bc58aa0b26d [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>
Peter Maydelle0eb2102014-03-17 12:15:35 +000046#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000047#include <signal.h>
48#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020049#ifdef __ia64__
50int __clone2(int (*fn)(void *), void *child_stack_base,
51 size_t stack_size, int flags, void *arg, ...);
52#endif
bellard31e31b82003-02-18 22:55:36 +000053#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000054#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000055#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000056#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000057#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000058#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000059#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000060#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000061#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000062#include <sys/sysinfo.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"
Riku Voipiod80a1902014-10-01 16:05:46 +030069#ifdef CONFIG_TIMERFD
70#include <sys/timerfd.h>
71#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020072#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000073#include <sys/gmon.h>
74#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030075#ifdef CONFIG_EVENTFD
76#include <sys/eventfd.h>
77#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000078#ifdef CONFIG_EPOLL
79#include <sys/epoll.h>
80#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070081#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010082#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070083#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000084#ifdef CONFIG_SENDFILE
85#include <sys/sendfile.h>
86#endif
bellard31e31b82003-02-18 22:55:36 +000087
88#define termios host_termios
89#define winsize host_winsize
90#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000091#define sgttyb host_sgttyb /* same as target */
92#define tchars host_tchars /* same as target */
93#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000094
95#include <linux/termios.h>
96#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000097#include <linux/cdrom.h>
98#include <linux/hdreg.h>
99#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +0000100#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +0000101#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300102#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000103#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000104#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000105#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200106#include <linux/fb.h>
107#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100108#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000109#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100110#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200111#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100112#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000113#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200114#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000115
bellard3ef693a2003-03-23 20:17:16 +0000116#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000117
pbrookd865bab2008-06-07 22:12:17 +0000118#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
119 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000120
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
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000185#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000186#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000187#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000189#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000190#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000191#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000192#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000193#define __NR_sys_inotify_init __NR_inotify_init
194#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
195#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000196
Alexander Graf42a39fb2011-04-15 17:32:45 +0200197#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
198 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000199#define __NR__llseek __NR_lseek
200#endif
201
James Hogana29e5ba2014-03-25 21:51:08 +0000202/* Newer kernel ports have llseek() instead of _llseek() */
203#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
204#define TARGET_NR__llseek TARGET_NR_llseek
205#endif
206
bellard72f03902003-02-18 23:33:18 +0000207#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000208_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000209#else
ths0da46a62007-10-20 20:23:07 +0000210/* This is a replacement for the host gettid() and must return a host
211 errno. */
bellard72f03902003-02-18 23:33:18 +0000212static int gettid(void) {
213 return -ENOSYS;
214}
215#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100216#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000217_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100218#endif
219#if !defined(__NR_getdents) || \
220 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000221_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
222#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700223#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000224_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
225 loff_t *, res, uint, wh);
226#endif
227_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
228_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
229#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
230_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
231#endif
232#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
233_syscall2(int,sys_tkill,int,tid,int,sig)
234#endif
235#ifdef __NR_exit_group
236_syscall1(int,exit_group,int,error_code)
237#endif
238#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
239_syscall1(int,set_tid_address,int *,tidptr)
240#endif
aurel323b3f24a2009-04-15 16:12:13 +0000241#if defined(TARGET_NR_futex) && defined(__NR_futex)
242_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
243 const struct timespec *,timeout,int *,uaddr2,int,val3)
244#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500245#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
246_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
247 unsigned long *, user_mask_ptr);
248#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
249_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
250 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200251_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
252 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000253_syscall2(int, capget, struct __user_cap_header_struct *, header,
254 struct __user_cap_data_struct *, data);
255_syscall2(int, capset, struct __user_cap_header_struct *, header,
256 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100257#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
258_syscall2(int, ioprio_get, int, which, int, who)
259#endif
260#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
261_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
262#endif
aurel323b3f24a2009-04-15 16:12:13 +0000263
264static bitmask_transtbl fcntl_flags_tbl[] = {
265 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
266 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
267 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
268 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
269 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
270 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
271 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
272 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700273 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000274 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
275 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
276 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
277 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000278#if defined(O_DIRECT)
279 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
280#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700281#if defined(O_NOATIME)
282 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
283#endif
284#if defined(O_CLOEXEC)
285 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
286#endif
287#if defined(O_PATH)
288 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
289#endif
290 /* Don't terminate the list prematurely on 64-bit host+guest. */
291#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
292 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
293#endif
aurel323b3f24a2009-04-15 16:12:13 +0000294 { 0, 0, 0, 0 }
295};
296
aurel323b3f24a2009-04-15 16:12:13 +0000297static int sys_getcwd1(char *buf, size_t size)
298{
299 if (getcwd(buf, size) == NULL) {
300 /* getcwd() sets errno */
301 return (-1);
302 }
aurel32aaf4ad32009-04-16 14:17:14 +0000303 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000304}
305
Alexander Graff4c69012011-09-25 06:25:35 +0200306static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000307{
308 /*
309 * open(2) has extra parameter 'mode' when called with
310 * flag O_CREAT.
311 */
312 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000313 return (openat(dirfd, pathname, flags, mode));
314 }
315 return (openat(dirfd, pathname, flags));
316}
Riku Voipioebc996f2009-04-21 15:01:51 +0300317
Peter Maydell1acae9f2013-07-02 14:04:12 +0100318#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300319#ifdef CONFIG_UTIMENSAT
320static int sys_utimensat(int dirfd, const char *pathname,
321 const struct timespec times[2], int flags)
322{
323 if (pathname == NULL)
324 return futimens(dirfd, times);
325 else
326 return utimensat(dirfd, pathname, times, flags);
327}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100328#elif defined(__NR_utimensat)
329#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000330_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
331 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100332#else
333static int sys_utimensat(int dirfd, const char *pathname,
334 const struct timespec times[2], int flags)
335{
336 errno = ENOSYS;
337 return -1;
338}
ths9007f0e2007-09-25 17:50:37 +0000339#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100340#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000341
342#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000343#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000344
aurel3239b59762008-10-01 21:46:50 +0000345#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000346static int sys_inotify_init(void)
347{
348 return (inotify_init());
349}
aurel3239b59762008-10-01 21:46:50 +0000350#endif
351#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000352static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
353{
354 return (inotify_add_watch(fd, pathname, mask));
355}
aurel3239b59762008-10-01 21:46:50 +0000356#endif
357#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000358static int sys_inotify_rm_watch(int fd, int32_t wd)
359{
aurel328690e422009-04-17 13:50:32 +0000360 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000361}
aurel3239b59762008-10-01 21:46:50 +0000362#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000363#ifdef CONFIG_INOTIFY1
364#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
365static int sys_inotify_init1(int flags)
366{
367 return (inotify_init1(flags));
368}
369#endif
370#endif
aurel323b3f24a2009-04-15 16:12:13 +0000371#else
372/* Userspace can usually survive runtime without inotify */
373#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000374#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000375#undef TARGET_NR_inotify_add_watch
376#undef TARGET_NR_inotify_rm_watch
377#endif /* CONFIG_INOTIFY */
378
Mike Frysingerd8035d42011-02-07 01:05:51 -0500379#if defined(TARGET_NR_ppoll)
380#ifndef __NR_ppoll
381# define __NR_ppoll -1
382#endif
383#define __NR_sys_ppoll __NR_ppoll
384_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200385 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500386 size_t, sigsetsize)
387#endif
bellard66fb9762003-03-23 01:06:05 +0000388
Mike Frysinger055e0902011-06-03 17:01:49 -0400389#if defined(TARGET_NR_pselect6)
390#ifndef __NR_pselect6
391# define __NR_pselect6 -1
392#endif
393#define __NR_sys_pselect6 __NR_pselect6
394_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
395 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
396#endif
397
Peter Maydell163a05a2011-06-27 17:44:52 +0100398#if defined(TARGET_NR_prlimit64)
399#ifndef __NR_prlimit64
400# define __NR_prlimit64 -1
401#endif
402#define __NR_sys_prlimit64 __NR_prlimit64
403/* The glibc rlimit structure may not be that used by the underlying syscall */
404struct host_rlimit64 {
405 uint64_t rlim_cur;
406 uint64_t rlim_max;
407};
408_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
409 const struct host_rlimit64 *, new_limit,
410 struct host_rlimit64 *, old_limit)
411#endif
412
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100413
414#if defined(TARGET_NR_timer_create)
415/* Maxiumum of 32 active POSIX timers allowed at any one time. */
416static timer_t g_posix_timers[32] = { 0, } ;
417
418static inline int next_free_host_timer(void)
419{
420 int k ;
421 /* FIXME: Does finding the next free slot require a lock? */
422 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
423 if (g_posix_timers[k] == 0) {
424 g_posix_timers[k] = (timer_t) 1;
425 return k;
426 }
427 }
428 return -1;
429}
430#endif
431
Riku Voipio48e515d2011-07-12 15:40:51 +0300432/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000433#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300434static inline int regpairs_aligned(void *cpu_env) {
435 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
436}
437#elif defined(TARGET_MIPS)
438static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000439#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
440/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
441 * of registers which translates to the same as ARM/MIPS, because we start with
442 * r3 as arg1 */
443static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300444#else
445static inline int regpairs_aligned(void *cpu_env) { return 0; }
446#endif
447
thsb92c47c2007-11-01 00:07:38 +0000448#define ERRNO_TABLE_SIZE 1200
449
450/* target_to_host_errno_table[] is initialized from
451 * host_to_target_errno_table[] in syscall_init(). */
452static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
453};
454
ths637947f2007-06-01 12:09:19 +0000455/*
thsfe8f0962007-07-12 10:59:21 +0000456 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000457 * minus the errnos that are not actually generic to all archs.
458 */
thsb92c47c2007-11-01 00:07:38 +0000459static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000460 [EIDRM] = TARGET_EIDRM,
461 [ECHRNG] = TARGET_ECHRNG,
462 [EL2NSYNC] = TARGET_EL2NSYNC,
463 [EL3HLT] = TARGET_EL3HLT,
464 [EL3RST] = TARGET_EL3RST,
465 [ELNRNG] = TARGET_ELNRNG,
466 [EUNATCH] = TARGET_EUNATCH,
467 [ENOCSI] = TARGET_ENOCSI,
468 [EL2HLT] = TARGET_EL2HLT,
469 [EDEADLK] = TARGET_EDEADLK,
470 [ENOLCK] = TARGET_ENOLCK,
471 [EBADE] = TARGET_EBADE,
472 [EBADR] = TARGET_EBADR,
473 [EXFULL] = TARGET_EXFULL,
474 [ENOANO] = TARGET_ENOANO,
475 [EBADRQC] = TARGET_EBADRQC,
476 [EBADSLT] = TARGET_EBADSLT,
477 [EBFONT] = TARGET_EBFONT,
478 [ENOSTR] = TARGET_ENOSTR,
479 [ENODATA] = TARGET_ENODATA,
480 [ETIME] = TARGET_ETIME,
481 [ENOSR] = TARGET_ENOSR,
482 [ENONET] = TARGET_ENONET,
483 [ENOPKG] = TARGET_ENOPKG,
484 [EREMOTE] = TARGET_EREMOTE,
485 [ENOLINK] = TARGET_ENOLINK,
486 [EADV] = TARGET_EADV,
487 [ESRMNT] = TARGET_ESRMNT,
488 [ECOMM] = TARGET_ECOMM,
489 [EPROTO] = TARGET_EPROTO,
490 [EDOTDOT] = TARGET_EDOTDOT,
491 [EMULTIHOP] = TARGET_EMULTIHOP,
492 [EBADMSG] = TARGET_EBADMSG,
493 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
494 [EOVERFLOW] = TARGET_EOVERFLOW,
495 [ENOTUNIQ] = TARGET_ENOTUNIQ,
496 [EBADFD] = TARGET_EBADFD,
497 [EREMCHG] = TARGET_EREMCHG,
498 [ELIBACC] = TARGET_ELIBACC,
499 [ELIBBAD] = TARGET_ELIBBAD,
500 [ELIBSCN] = TARGET_ELIBSCN,
501 [ELIBMAX] = TARGET_ELIBMAX,
502 [ELIBEXEC] = TARGET_ELIBEXEC,
503 [EILSEQ] = TARGET_EILSEQ,
504 [ENOSYS] = TARGET_ENOSYS,
505 [ELOOP] = TARGET_ELOOP,
506 [ERESTART] = TARGET_ERESTART,
507 [ESTRPIPE] = TARGET_ESTRPIPE,
508 [ENOTEMPTY] = TARGET_ENOTEMPTY,
509 [EUSERS] = TARGET_EUSERS,
510 [ENOTSOCK] = TARGET_ENOTSOCK,
511 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
512 [EMSGSIZE] = TARGET_EMSGSIZE,
513 [EPROTOTYPE] = TARGET_EPROTOTYPE,
514 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
515 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
516 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
517 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
518 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
519 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
520 [EADDRINUSE] = TARGET_EADDRINUSE,
521 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
522 [ENETDOWN] = TARGET_ENETDOWN,
523 [ENETUNREACH] = TARGET_ENETUNREACH,
524 [ENETRESET] = TARGET_ENETRESET,
525 [ECONNABORTED] = TARGET_ECONNABORTED,
526 [ECONNRESET] = TARGET_ECONNRESET,
527 [ENOBUFS] = TARGET_ENOBUFS,
528 [EISCONN] = TARGET_EISCONN,
529 [ENOTCONN] = TARGET_ENOTCONN,
530 [EUCLEAN] = TARGET_EUCLEAN,
531 [ENOTNAM] = TARGET_ENOTNAM,
532 [ENAVAIL] = TARGET_ENAVAIL,
533 [EISNAM] = TARGET_EISNAM,
534 [EREMOTEIO] = TARGET_EREMOTEIO,
535 [ESHUTDOWN] = TARGET_ESHUTDOWN,
536 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
537 [ETIMEDOUT] = TARGET_ETIMEDOUT,
538 [ECONNREFUSED] = TARGET_ECONNREFUSED,
539 [EHOSTDOWN] = TARGET_EHOSTDOWN,
540 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
541 [EALREADY] = TARGET_EALREADY,
542 [EINPROGRESS] = TARGET_EINPROGRESS,
543 [ESTALE] = TARGET_ESTALE,
544 [ECANCELED] = TARGET_ECANCELED,
545 [ENOMEDIUM] = TARGET_ENOMEDIUM,
546 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000547#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000548 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000549#endif
550#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000551 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000552#endif
553#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000554 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000555#endif
556#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000557 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000558#endif
559#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000560 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000561#endif
562#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000563 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000564#endif
thsb92c47c2007-11-01 00:07:38 +0000565};
ths637947f2007-06-01 12:09:19 +0000566
567static inline int host_to_target_errno(int err)
568{
569 if(host_to_target_errno_table[err])
570 return host_to_target_errno_table[err];
571 return err;
572}
573
thsb92c47c2007-11-01 00:07:38 +0000574static inline int target_to_host_errno(int err)
575{
576 if (target_to_host_errno_table[err])
577 return target_to_host_errno_table[err];
578 return err;
579}
580
blueswir1992f48a2007-10-14 16:27:31 +0000581static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000582{
583 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000584 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000585 else
586 return ret;
587}
588
blueswir1992f48a2007-10-14 16:27:31 +0000589static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000590{
blueswir1992f48a2007-10-14 16:27:31 +0000591 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000592}
593
thsb92c47c2007-11-01 00:07:38 +0000594char *target_strerror(int err)
595{
Alexander Graf962b2892011-11-21 12:04:07 +0100596 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
597 return NULL;
598 }
thsb92c47c2007-11-01 00:07:38 +0000599 return strerror(target_to_host_errno(err));
600}
601
Paul Burton8289d112014-06-22 11:25:33 +0100602static inline int host_to_target_sock_type(int host_type)
603{
604 int target_type;
605
606 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
607 case SOCK_DGRAM:
608 target_type = TARGET_SOCK_DGRAM;
609 break;
610 case SOCK_STREAM:
611 target_type = TARGET_SOCK_STREAM;
612 break;
613 default:
614 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
615 break;
616 }
617
618#if defined(SOCK_CLOEXEC)
619 if (host_type & SOCK_CLOEXEC) {
620 target_type |= TARGET_SOCK_CLOEXEC;
621 }
622#endif
623
624#if defined(SOCK_NONBLOCK)
625 if (host_type & SOCK_NONBLOCK) {
626 target_type |= TARGET_SOCK_NONBLOCK;
627 }
628#endif
629
630 return target_type;
631}
632
blueswir1992f48a2007-10-14 16:27:31 +0000633static abi_ulong target_brk;
634static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000635static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000636
blueswir1992f48a2007-10-14 16:27:31 +0000637void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000638{
blueswir14c1de732007-07-07 20:45:44 +0000639 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000640 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000641}
642
vincent4d1de872011-06-14 21:56:33 +0000643//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
644#define DEBUGF_BRK(message, args...)
645
ths0da46a62007-10-20 20:23:07 +0000646/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000647abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000648{
blueswir1992f48a2007-10-14 16:27:31 +0000649 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000650 int new_alloc_size;
651
Paul Brook3a0c6c42012-02-09 19:04:27 +0000652 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000653
vincent4d1de872011-06-14 21:56:33 +0000654 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000655 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000656 return target_brk;
657 }
658 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000659 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
660 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000661 return target_brk;
662 }
bellard31e31b82003-02-18 22:55:36 +0000663
vincent4d1de872011-06-14 21:56:33 +0000664 /* If the new brk is less than the highest page reserved to the
665 * target heap allocation, set it and we're almost done... */
666 if (new_brk <= brk_page) {
667 /* Heap contents are initialized to zero, as for anonymous
668 * mapped pages. */
669 if (new_brk > target_brk) {
670 memset(g2h(target_brk), 0, new_brk - target_brk);
671 }
bellard31e31b82003-02-18 22:55:36 +0000672 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000673 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000674 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000675 }
676
Peter Maydell00faf082011-04-18 16:34:24 +0100677 /* We need to allocate more memory after the brk... Note that
678 * we don't use MAP_FIXED because that will map over the top of
679 * any existing mapping (like the one with the host libc or qemu
680 * itself); instead we treat "mapped but at wrong address" as
681 * a failure and unmap again.
682 */
vincent4d1de872011-06-14 21:56:33 +0000683 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000684 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000685 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100686 MAP_ANON|MAP_PRIVATE, 0, 0));
687
688 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200689 /* Heap contents are initialized to zero, as for anonymous
690 * mapped pages. Technically the new pages are already
691 * initialized to zero since they *are* anonymous mapped
692 * pages, however we have to take care with the contents that
693 * come from the remaining part of the previous page: it may
694 * contains garbage data due to a previous heap usage (grown
695 * then shrunken). */
696 memset(g2h(target_brk), 0, brk_page - target_brk);
697
Peter Maydell00faf082011-04-18 16:34:24 +0100698 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000699 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000700 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
701 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100702 return target_brk;
703 } else if (mapped_addr != -1) {
704 /* Mapped but at wrong address, meaning there wasn't actually
705 * enough space for this brk.
706 */
707 target_munmap(mapped_addr, new_alloc_size);
708 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000709 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000710 }
711 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000712 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100713 }
balrog7ab240a2008-04-26 12:17:34 +0000714
Richard Henderson7dd46c02010-05-03 10:07:49 -0700715#if defined(TARGET_ALPHA)
716 /* We (partially) emulate OSF/1 on Alpha, which requires we
717 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100718 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700719#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100720 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000721 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000722}
723
ths26edcf42007-12-09 02:25:24 +0000724static inline abi_long copy_from_user_fdset(fd_set *fds,
725 abi_ulong target_fds_addr,
726 int n)
bellard31e31b82003-02-18 22:55:36 +0000727{
ths26edcf42007-12-09 02:25:24 +0000728 int i, nw, j, k;
729 abi_ulong b, *target_fds;
730
731 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
732 if (!(target_fds = lock_user(VERIFY_READ,
733 target_fds_addr,
734 sizeof(abi_ulong) * nw,
735 1)))
736 return -TARGET_EFAULT;
737
738 FD_ZERO(fds);
739 k = 0;
740 for (i = 0; i < nw; i++) {
741 /* grab the abi_ulong */
742 __get_user(b, &target_fds[i]);
743 for (j = 0; j < TARGET_ABI_BITS; j++) {
744 /* check the bit inside the abi_ulong */
745 if ((b >> j) & 1)
746 FD_SET(k, fds);
747 k++;
bellard31e31b82003-02-18 22:55:36 +0000748 }
bellard31e31b82003-02-18 22:55:36 +0000749 }
ths26edcf42007-12-09 02:25:24 +0000750
751 unlock_user(target_fds, target_fds_addr, 0);
752
753 return 0;
bellard31e31b82003-02-18 22:55:36 +0000754}
755
Mike Frysinger055e0902011-06-03 17:01:49 -0400756static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
757 abi_ulong target_fds_addr,
758 int n)
759{
760 if (target_fds_addr) {
761 if (copy_from_user_fdset(fds, target_fds_addr, n))
762 return -TARGET_EFAULT;
763 *fds_ptr = fds;
764 } else {
765 *fds_ptr = NULL;
766 }
767 return 0;
768}
769
ths26edcf42007-12-09 02:25:24 +0000770static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
771 const fd_set *fds,
772 int n)
bellard31e31b82003-02-18 22:55:36 +0000773{
bellard31e31b82003-02-18 22:55:36 +0000774 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000776 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000777
ths26edcf42007-12-09 02:25:24 +0000778 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
779 if (!(target_fds = lock_user(VERIFY_WRITE,
780 target_fds_addr,
781 sizeof(abi_ulong) * nw,
782 0)))
783 return -TARGET_EFAULT;
784
785 k = 0;
786 for (i = 0; i < nw; i++) {
787 v = 0;
788 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000789 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000790 k++;
bellard31e31b82003-02-18 22:55:36 +0000791 }
ths26edcf42007-12-09 02:25:24 +0000792 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000793 }
ths26edcf42007-12-09 02:25:24 +0000794
795 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
796
797 return 0;
bellard31e31b82003-02-18 22:55:36 +0000798}
799
bellardc596ed12003-07-13 17:32:31 +0000800#if defined(__alpha__)
801#define HOST_HZ 1024
802#else
803#define HOST_HZ 100
804#endif
805
blueswir1992f48a2007-10-14 16:27:31 +0000806static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000807{
808#if HOST_HZ == TARGET_HZ
809 return ticks;
810#else
811 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
812#endif
813}
814
bellard579a97f2007-11-11 14:26:47 +0000815static inline abi_long host_to_target_rusage(abi_ulong target_addr,
816 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000817{
pbrook53a59602006-03-25 19:31:22 +0000818 struct target_rusage *target_rusage;
819
bellard579a97f2007-11-11 14:26:47 +0000820 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
821 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200822 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
823 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
824 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
825 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
826 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
827 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
828 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
829 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
830 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
831 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
832 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
833 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
834 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
835 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
836 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
837 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
838 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
839 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000840 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000841
842 return 0;
bellardb4091862003-05-16 15:39:34 +0000843}
844
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200845static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900846{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200847 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300848 rlim_t result;
849
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200850 target_rlim_swap = tswapal(target_rlim);
851 if (target_rlim_swap == TARGET_RLIM_INFINITY)
852 return RLIM_INFINITY;
853
854 result = target_rlim_swap;
855 if (target_rlim_swap != (rlim_t)result)
856 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300857
858 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900859}
860
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200861static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900862{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200863 abi_ulong target_rlim_swap;
864 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300865
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200866 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300867 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900868 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300869 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200870 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300871
872 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900873}
874
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300875static inline int target_to_host_resource(int code)
876{
877 switch (code) {
878 case TARGET_RLIMIT_AS:
879 return RLIMIT_AS;
880 case TARGET_RLIMIT_CORE:
881 return RLIMIT_CORE;
882 case TARGET_RLIMIT_CPU:
883 return RLIMIT_CPU;
884 case TARGET_RLIMIT_DATA:
885 return RLIMIT_DATA;
886 case TARGET_RLIMIT_FSIZE:
887 return RLIMIT_FSIZE;
888 case TARGET_RLIMIT_LOCKS:
889 return RLIMIT_LOCKS;
890 case TARGET_RLIMIT_MEMLOCK:
891 return RLIMIT_MEMLOCK;
892 case TARGET_RLIMIT_MSGQUEUE:
893 return RLIMIT_MSGQUEUE;
894 case TARGET_RLIMIT_NICE:
895 return RLIMIT_NICE;
896 case TARGET_RLIMIT_NOFILE:
897 return RLIMIT_NOFILE;
898 case TARGET_RLIMIT_NPROC:
899 return RLIMIT_NPROC;
900 case TARGET_RLIMIT_RSS:
901 return RLIMIT_RSS;
902 case TARGET_RLIMIT_RTPRIO:
903 return RLIMIT_RTPRIO;
904 case TARGET_RLIMIT_SIGPENDING:
905 return RLIMIT_SIGPENDING;
906 case TARGET_RLIMIT_STACK:
907 return RLIMIT_STACK;
908 default:
909 return code;
910 }
911}
912
ths788f5ec2007-12-09 02:37:05 +0000913static inline abi_long copy_from_user_timeval(struct timeval *tv,
914 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000915{
pbrook53a59602006-03-25 19:31:22 +0000916 struct target_timeval *target_tv;
917
ths788f5ec2007-12-09 02:37:05 +0000918 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000919 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000920
921 __get_user(tv->tv_sec, &target_tv->tv_sec);
922 __get_user(tv->tv_usec, &target_tv->tv_usec);
923
924 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000925
926 return 0;
bellard31e31b82003-02-18 22:55:36 +0000927}
928
ths788f5ec2007-12-09 02:37:05 +0000929static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
930 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000931{
pbrook53a59602006-03-25 19:31:22 +0000932 struct target_timeval *target_tv;
933
ths788f5ec2007-12-09 02:37:05 +0000934 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000935 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000936
937 __put_user(tv->tv_sec, &target_tv->tv_sec);
938 __put_user(tv->tv_usec, &target_tv->tv_usec);
939
940 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000941
942 return 0;
bellard31e31b82003-02-18 22:55:36 +0000943}
944
Paul Burtonef4467e2014-06-22 11:25:40 +0100945static inline abi_long copy_from_user_timezone(struct timezone *tz,
946 abi_ulong target_tz_addr)
947{
948 struct target_timezone *target_tz;
949
950 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
951 return -TARGET_EFAULT;
952 }
953
954 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
955 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
956
957 unlock_user_struct(target_tz, target_tz_addr, 0);
958
959 return 0;
960}
961
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700962#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
963#include <mqueue.h>
964
aurel3224e10032009-04-15 16:11:43 +0000965static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
966 abi_ulong target_mq_attr_addr)
967{
968 struct target_mq_attr *target_mq_attr;
969
970 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
971 target_mq_attr_addr, 1))
972 return -TARGET_EFAULT;
973
974 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
975 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
976 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
977 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
978
979 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
980
981 return 0;
982}
983
984static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
985 const struct mq_attr *attr)
986{
987 struct target_mq_attr *target_mq_attr;
988
989 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
990 target_mq_attr_addr, 0))
991 return -TARGET_EFAULT;
992
993 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
994 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
995 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
996 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
997
998 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
999
1000 return 0;
1001}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001002#endif
bellard31e31b82003-02-18 22:55:36 +00001003
Mike Frysinger055e0902011-06-03 17:01:49 -04001004#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001005/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001006static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001007 abi_ulong rfd_addr, abi_ulong wfd_addr,
1008 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001009{
1010 fd_set rfds, wfds, efds;
1011 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1012 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001013 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001014
Mike Frysinger055e0902011-06-03 17:01:49 -04001015 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1016 if (ret) {
1017 return ret;
pbrook53a59602006-03-25 19:31:22 +00001018 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001019 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1020 if (ret) {
1021 return ret;
pbrook53a59602006-03-25 19:31:22 +00001022 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001023 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1024 if (ret) {
1025 return ret;
pbrook53a59602006-03-25 19:31:22 +00001026 }
ths3b46e622007-09-17 08:09:54 +00001027
ths26edcf42007-12-09 02:25:24 +00001028 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001029 if (copy_from_user_timeval(&tv, target_tv_addr))
1030 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001031 tv_ptr = &tv;
1032 } else {
1033 tv_ptr = NULL;
1034 }
ths26edcf42007-12-09 02:25:24 +00001035
bellard31e31b82003-02-18 22:55:36 +00001036 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001037
ths26edcf42007-12-09 02:25:24 +00001038 if (!is_error(ret)) {
1039 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1040 return -TARGET_EFAULT;
1041 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1042 return -TARGET_EFAULT;
1043 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1044 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001045
ths788f5ec2007-12-09 02:37:05 +00001046 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1047 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001048 }
bellard579a97f2007-11-11 14:26:47 +00001049
bellard31e31b82003-02-18 22:55:36 +00001050 return ret;
1051}
Mike Frysinger055e0902011-06-03 17:01:49 -04001052#endif
bellard31e31b82003-02-18 22:55:36 +00001053
Riku Voipio099d6b02009-05-05 12:10:04 +03001054static abi_long do_pipe2(int host_pipe[], int flags)
1055{
1056#ifdef CONFIG_PIPE2
1057 return pipe2(host_pipe, flags);
1058#else
1059 return -ENOSYS;
1060#endif
1061}
1062
Richard Hendersonfb41a662010-05-03 10:07:52 -07001063static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1064 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001065{
1066 int host_pipe[2];
1067 abi_long ret;
1068 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1069
1070 if (is_error(ret))
1071 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001072
1073 /* Several targets have special calling conventions for the original
1074 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1075 if (!is_pipe2) {
1076#if defined(TARGET_ALPHA)
1077 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1078 return host_pipe[0];
1079#elif defined(TARGET_MIPS)
1080 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1081 return host_pipe[0];
1082#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001083 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001084 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001085#elif defined(TARGET_SPARC)
1086 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1087 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001088#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001089 }
1090
Riku Voipio099d6b02009-05-05 12:10:04 +03001091 if (put_user_s32(host_pipe[0], pipedes)
1092 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1093 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001094 return get_errno(ret);
1095}
1096
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001097static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1098 abi_ulong target_addr,
1099 socklen_t len)
1100{
1101 struct target_ip_mreqn *target_smreqn;
1102
1103 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1104 if (!target_smreqn)
1105 return -TARGET_EFAULT;
1106 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1107 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1108 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001109 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001110 unlock_user(target_smreqn, target_addr, 0);
1111
1112 return 0;
1113}
1114
bellard579a97f2007-11-11 14:26:47 +00001115static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1116 abi_ulong target_addr,
1117 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001118{
aurel32607175e2009-04-15 16:11:59 +00001119 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1120 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001121 struct target_sockaddr *target_saddr;
1122
bellard579a97f2007-11-11 14:26:47 +00001123 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1124 if (!target_saddr)
1125 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001126
1127 sa_family = tswap16(target_saddr->sa_family);
1128
1129 /* Oops. The caller might send a incomplete sun_path; sun_path
1130 * must be terminated by \0 (see the manual page), but
1131 * unfortunately it is quite common to specify sockaddr_un
1132 * length as "strlen(x->sun_path)" while it should be
1133 * "strlen(...) + 1". We'll fix that here if needed.
1134 * Linux kernel has a similar feature.
1135 */
1136
1137 if (sa_family == AF_UNIX) {
1138 if (len < unix_maxlen && len > 0) {
1139 char *cp = (char*)target_saddr;
1140
1141 if ( cp[len-1] && !cp[len] )
1142 len++;
1143 }
1144 if (len > unix_maxlen)
1145 len = unix_maxlen;
1146 }
1147
pbrook53a59602006-03-25 19:31:22 +00001148 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001149 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001150 if (sa_family == AF_PACKET) {
1151 struct target_sockaddr_ll *lladdr;
1152
1153 lladdr = (struct target_sockaddr_ll *)addr;
1154 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1155 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1156 }
pbrook53a59602006-03-25 19:31:22 +00001157 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001158
1159 return 0;
bellard7854b052003-03-29 17:22:23 +00001160}
1161
bellard579a97f2007-11-11 14:26:47 +00001162static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1163 struct sockaddr *addr,
1164 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001165{
pbrook53a59602006-03-25 19:31:22 +00001166 struct target_sockaddr *target_saddr;
1167
bellard579a97f2007-11-11 14:26:47 +00001168 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1169 if (!target_saddr)
1170 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001171 memcpy(target_saddr, addr, len);
1172 target_saddr->sa_family = tswap16(addr->sa_family);
1173 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001174
1175 return 0;
bellard7854b052003-03-29 17:22:23 +00001176}
1177
bellard5a4a8982007-11-11 17:39:18 +00001178static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1179 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001180{
1181 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001182 abi_long msg_controllen;
1183 abi_ulong target_cmsg_addr;
1184 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001185 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001186
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001187 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001188 if (msg_controllen < sizeof (struct target_cmsghdr))
1189 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001190 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001191 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1192 if (!target_cmsg)
1193 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001194
1195 while (cmsg && target_cmsg) {
1196 void *data = CMSG_DATA(cmsg);
1197 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1198
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001199 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001200 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1201
1202 space += CMSG_SPACE(len);
1203 if (space > msgh->msg_controllen) {
1204 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001205 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001206 break;
1207 }
1208
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001209 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1210 cmsg->cmsg_level = SOL_SOCKET;
1211 } else {
1212 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1213 }
bellard7854b052003-03-29 17:22:23 +00001214 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1215 cmsg->cmsg_len = CMSG_LEN(len);
1216
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001217 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001218 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1219 memcpy(data, target_data, len);
1220 } else {
1221 int *fd = (int *)data;
1222 int *target_fd = (int *)target_data;
1223 int i, numfds = len / sizeof(int);
1224
1225 for (i = 0; i < numfds; i++)
1226 fd[i] = tswap32(target_fd[i]);
1227 }
1228
1229 cmsg = CMSG_NXTHDR(msgh, cmsg);
1230 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1231 }
bellard5a4a8982007-11-11 17:39:18 +00001232 unlock_user(target_cmsg, target_cmsg_addr, 0);
1233 the_end:
bellard7854b052003-03-29 17:22:23 +00001234 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001235 return 0;
bellard7854b052003-03-29 17:22:23 +00001236}
1237
bellard5a4a8982007-11-11 17:39:18 +00001238static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1239 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001240{
1241 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001242 abi_long msg_controllen;
1243 abi_ulong target_cmsg_addr;
1244 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001245 socklen_t space = 0;
1246
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001247 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001248 if (msg_controllen < sizeof (struct target_cmsghdr))
1249 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001250 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001251 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1252 if (!target_cmsg)
1253 return -TARGET_EFAULT;
1254
bellard7854b052003-03-29 17:22:23 +00001255 while (cmsg && target_cmsg) {
1256 void *data = CMSG_DATA(cmsg);
1257 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1258
1259 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1260
1261 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001262 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001263 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001264 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001265 break;
1266 }
1267
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001268 if (cmsg->cmsg_level == SOL_SOCKET) {
1269 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1270 } else {
1271 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1272 }
bellard7854b052003-03-29 17:22:23 +00001273 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001274 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001275
Huw Davies52b65492014-04-17 14:02:47 +01001276 switch (cmsg->cmsg_level) {
1277 case SOL_SOCKET:
1278 switch (cmsg->cmsg_type) {
1279 case SCM_RIGHTS:
1280 {
1281 int *fd = (int *)data;
1282 int *target_fd = (int *)target_data;
1283 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001284
Huw Davies52b65492014-04-17 14:02:47 +01001285 for (i = 0; i < numfds; i++)
1286 target_fd[i] = tswap32(fd[i]);
1287 break;
1288 }
1289 case SO_TIMESTAMP:
1290 {
1291 struct timeval *tv = (struct timeval *)data;
1292 struct target_timeval *target_tv =
1293 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001294
Huw Davies52b65492014-04-17 14:02:47 +01001295 if (len != sizeof(struct timeval))
1296 goto unimplemented;
1297
1298 /* copy struct timeval to target */
1299 target_tv->tv_sec = tswapal(tv->tv_sec);
1300 target_tv->tv_usec = tswapal(tv->tv_usec);
1301 break;
1302 }
Huw Davies4bc29752014-04-17 14:02:48 +01001303 case SCM_CREDENTIALS:
1304 {
1305 struct ucred *cred = (struct ucred *)data;
1306 struct target_ucred *target_cred =
1307 (struct target_ucred *)target_data;
1308
1309 __put_user(cred->pid, &target_cred->pid);
1310 __put_user(cred->uid, &target_cred->uid);
1311 __put_user(cred->gid, &target_cred->gid);
1312 break;
1313 }
Huw Davies52b65492014-04-17 14:02:47 +01001314 default:
1315 goto unimplemented;
1316 }
1317 break;
1318
1319 default:
1320 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001321 gemu_log("Unsupported ancillary data: %d/%d\n",
1322 cmsg->cmsg_level, cmsg->cmsg_type);
1323 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001324 }
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, space);
1330 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001331 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001332 return 0;
bellard7854b052003-03-29 17:22:23 +00001333}
1334
ths0da46a62007-10-20 20:23:07 +00001335/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001336static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001337 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001338{
blueswir1992f48a2007-10-14 16:27:31 +00001339 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001340 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001341 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001342 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001343
bellard8853f862004-02-22 14:57:26 +00001344 switch(level) {
1345 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001346 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001347 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001348 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001349
bellard2f619692007-11-16 10:46:05 +00001350 if (get_user_u32(val, optval_addr))
1351 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001352 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1353 break;
1354 case SOL_IP:
1355 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001356 case IP_TOS:
1357 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001358 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001359 case IP_ROUTER_ALERT:
1360 case IP_RECVOPTS:
1361 case IP_RETOPTS:
1362 case IP_PKTINFO:
1363 case IP_MTU_DISCOVER:
1364 case IP_RECVERR:
1365 case IP_RECVTOS:
1366#ifdef IP_FREEBIND
1367 case IP_FREEBIND:
1368#endif
1369 case IP_MULTICAST_TTL:
1370 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001371 val = 0;
1372 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001373 if (get_user_u32(val, optval_addr))
1374 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001375 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001376 if (get_user_u8(val, optval_addr))
1377 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001378 }
1379 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1380 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001381 case IP_ADD_MEMBERSHIP:
1382 case IP_DROP_MEMBERSHIP:
1383 if (optlen < sizeof (struct target_ip_mreq) ||
1384 optlen > sizeof (struct target_ip_mreqn))
1385 return -TARGET_EINVAL;
1386
1387 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1388 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1389 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1390 break;
1391
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001392 case IP_BLOCK_SOURCE:
1393 case IP_UNBLOCK_SOURCE:
1394 case IP_ADD_SOURCE_MEMBERSHIP:
1395 case IP_DROP_SOURCE_MEMBERSHIP:
1396 if (optlen != sizeof (struct target_ip_mreq_source))
1397 return -TARGET_EINVAL;
1398
1399 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1400 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1401 unlock_user (ip_mreq_source, optval_addr, 0);
1402 break;
1403
bellard8853f862004-02-22 14:57:26 +00001404 default:
1405 goto unimplemented;
1406 }
1407 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001408 case SOL_IPV6:
1409 switch (optname) {
1410 case IPV6_MTU_DISCOVER:
1411 case IPV6_MTU:
1412 case IPV6_V6ONLY:
1413 case IPV6_RECVPKTINFO:
1414 val = 0;
1415 if (optlen < sizeof(uint32_t)) {
1416 return -TARGET_EINVAL;
1417 }
1418 if (get_user_u32(val, optval_addr)) {
1419 return -TARGET_EFAULT;
1420 }
1421 ret = get_errno(setsockopt(sockfd, level, optname,
1422 &val, sizeof(val)));
1423 break;
1424 default:
1425 goto unimplemented;
1426 }
1427 break;
Jing Huang920394d2012-07-24 13:59:23 +00001428 case SOL_RAW:
1429 switch (optname) {
1430 case ICMP_FILTER:
1431 /* struct icmp_filter takes an u32 value */
1432 if (optlen < sizeof(uint32_t)) {
1433 return -TARGET_EINVAL;
1434 }
1435
1436 if (get_user_u32(val, optval_addr)) {
1437 return -TARGET_EFAULT;
1438 }
1439 ret = get_errno(setsockopt(sockfd, level, optname,
1440 &val, sizeof(val)));
1441 break;
1442
1443 default:
1444 goto unimplemented;
1445 }
1446 break;
bellard3532fa72006-06-24 15:06:03 +00001447 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001448 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001449 case TARGET_SO_RCVTIMEO:
1450 {
1451 struct timeval tv;
1452
1453 optname = SO_RCVTIMEO;
1454
1455set_timeout:
1456 if (optlen != sizeof(struct target_timeval)) {
1457 return -TARGET_EINVAL;
1458 }
1459
1460 if (copy_from_user_timeval(&tv, optval_addr)) {
1461 return -TARGET_EFAULT;
1462 }
1463
1464 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1465 &tv, sizeof(tv)));
1466 return ret;
1467 }
1468 case TARGET_SO_SNDTIMEO:
1469 optname = SO_SNDTIMEO;
1470 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001471 case TARGET_SO_ATTACH_FILTER:
1472 {
1473 struct target_sock_fprog *tfprog;
1474 struct target_sock_filter *tfilter;
1475 struct sock_fprog fprog;
1476 struct sock_filter *filter;
1477 int i;
1478
1479 if (optlen != sizeof(*tfprog)) {
1480 return -TARGET_EINVAL;
1481 }
1482 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1483 return -TARGET_EFAULT;
1484 }
1485 if (!lock_user_struct(VERIFY_READ, tfilter,
1486 tswapal(tfprog->filter), 0)) {
1487 unlock_user_struct(tfprog, optval_addr, 1);
1488 return -TARGET_EFAULT;
1489 }
1490
1491 fprog.len = tswap16(tfprog->len);
1492 filter = malloc(fprog.len * sizeof(*filter));
1493 if (filter == NULL) {
1494 unlock_user_struct(tfilter, tfprog->filter, 1);
1495 unlock_user_struct(tfprog, optval_addr, 1);
1496 return -TARGET_ENOMEM;
1497 }
1498 for (i = 0; i < fprog.len; i++) {
1499 filter[i].code = tswap16(tfilter[i].code);
1500 filter[i].jt = tfilter[i].jt;
1501 filter[i].jf = tfilter[i].jf;
1502 filter[i].k = tswap32(tfilter[i].k);
1503 }
1504 fprog.filter = filter;
1505
1506 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1507 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1508 free(filter);
1509
1510 unlock_user_struct(tfilter, tfprog->filter, 1);
1511 unlock_user_struct(tfprog, optval_addr, 1);
1512 return ret;
1513 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001514 case TARGET_SO_BINDTODEVICE:
1515 {
1516 char *dev_ifname, *addr_ifname;
1517
1518 if (optlen > IFNAMSIZ - 1) {
1519 optlen = IFNAMSIZ - 1;
1520 }
1521 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1522 if (!dev_ifname) {
1523 return -TARGET_EFAULT;
1524 }
1525 optname = SO_BINDTODEVICE;
1526 addr_ifname = alloca(IFNAMSIZ);
1527 memcpy(addr_ifname, dev_ifname, optlen);
1528 addr_ifname[optlen] = 0;
1529 ret = get_errno(setsockopt(sockfd, level, optname, addr_ifname, optlen));
1530 unlock_user (dev_ifname, optval_addr, 0);
1531 return ret;
1532 }
bellard8853f862004-02-22 14:57:26 +00001533 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001534 case TARGET_SO_DEBUG:
1535 optname = SO_DEBUG;
1536 break;
1537 case TARGET_SO_REUSEADDR:
1538 optname = SO_REUSEADDR;
1539 break;
1540 case TARGET_SO_TYPE:
1541 optname = SO_TYPE;
1542 break;
1543 case TARGET_SO_ERROR:
1544 optname = SO_ERROR;
1545 break;
1546 case TARGET_SO_DONTROUTE:
1547 optname = SO_DONTROUTE;
1548 break;
1549 case TARGET_SO_BROADCAST:
1550 optname = SO_BROADCAST;
1551 break;
1552 case TARGET_SO_SNDBUF:
1553 optname = SO_SNDBUF;
1554 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001555 case TARGET_SO_SNDBUFFORCE:
1556 optname = SO_SNDBUFFORCE;
1557 break;
bellard3532fa72006-06-24 15:06:03 +00001558 case TARGET_SO_RCVBUF:
1559 optname = SO_RCVBUF;
1560 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001561 case TARGET_SO_RCVBUFFORCE:
1562 optname = SO_RCVBUFFORCE;
1563 break;
bellard3532fa72006-06-24 15:06:03 +00001564 case TARGET_SO_KEEPALIVE:
1565 optname = SO_KEEPALIVE;
1566 break;
1567 case TARGET_SO_OOBINLINE:
1568 optname = SO_OOBINLINE;
1569 break;
1570 case TARGET_SO_NO_CHECK:
1571 optname = SO_NO_CHECK;
1572 break;
1573 case TARGET_SO_PRIORITY:
1574 optname = SO_PRIORITY;
1575 break;
bellard5e83e8e2005-03-01 22:32:06 +00001576#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001577 case TARGET_SO_BSDCOMPAT:
1578 optname = SO_BSDCOMPAT;
1579 break;
bellard5e83e8e2005-03-01 22:32:06 +00001580#endif
bellard3532fa72006-06-24 15:06:03 +00001581 case TARGET_SO_PASSCRED:
1582 optname = SO_PASSCRED;
1583 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001584 case TARGET_SO_PASSSEC:
1585 optname = SO_PASSSEC;
1586 break;
bellard3532fa72006-06-24 15:06:03 +00001587 case TARGET_SO_TIMESTAMP:
1588 optname = SO_TIMESTAMP;
1589 break;
1590 case TARGET_SO_RCVLOWAT:
1591 optname = SO_RCVLOWAT;
1592 break;
bellard8853f862004-02-22 14:57:26 +00001593 break;
1594 default:
1595 goto unimplemented;
1596 }
bellard3532fa72006-06-24 15:06:03 +00001597 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001598 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001599
bellard2f619692007-11-16 10:46:05 +00001600 if (get_user_u32(val, optval_addr))
1601 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001602 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001603 break;
bellard7854b052003-03-29 17:22:23 +00001604 default:
bellard8853f862004-02-22 14:57:26 +00001605 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001606 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001607 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001608 }
bellard8853f862004-02-22 14:57:26 +00001609 return ret;
bellard7854b052003-03-29 17:22:23 +00001610}
1611
ths0da46a62007-10-20 20:23:07 +00001612/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001613static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001614 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001615{
blueswir1992f48a2007-10-14 16:27:31 +00001616 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001617 int len, val;
1618 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001619
1620 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001621 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001622 level = SOL_SOCKET;
1623 switch (optname) {
1624 /* These don't just return a single integer */
1625 case TARGET_SO_LINGER:
1626 case TARGET_SO_RCVTIMEO:
1627 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001628 case TARGET_SO_PEERNAME:
1629 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001630 case TARGET_SO_PEERCRED: {
1631 struct ucred cr;
1632 socklen_t crlen;
1633 struct target_ucred *tcr;
1634
1635 if (get_user_u32(len, optlen)) {
1636 return -TARGET_EFAULT;
1637 }
1638 if (len < 0) {
1639 return -TARGET_EINVAL;
1640 }
1641
1642 crlen = sizeof(cr);
1643 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1644 &cr, &crlen));
1645 if (ret < 0) {
1646 return ret;
1647 }
1648 if (len > crlen) {
1649 len = crlen;
1650 }
1651 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1652 return -TARGET_EFAULT;
1653 }
1654 __put_user(cr.pid, &tcr->pid);
1655 __put_user(cr.uid, &tcr->uid);
1656 __put_user(cr.gid, &tcr->gid);
1657 unlock_user_struct(tcr, optval_addr, 1);
1658 if (put_user_u32(len, optlen)) {
1659 return -TARGET_EFAULT;
1660 }
1661 break;
1662 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001663 /* Options with 'int' argument. */
1664 case TARGET_SO_DEBUG:
1665 optname = SO_DEBUG;
1666 goto int_case;
1667 case TARGET_SO_REUSEADDR:
1668 optname = SO_REUSEADDR;
1669 goto int_case;
1670 case TARGET_SO_TYPE:
1671 optname = SO_TYPE;
1672 goto int_case;
1673 case TARGET_SO_ERROR:
1674 optname = SO_ERROR;
1675 goto int_case;
1676 case TARGET_SO_DONTROUTE:
1677 optname = SO_DONTROUTE;
1678 goto int_case;
1679 case TARGET_SO_BROADCAST:
1680 optname = SO_BROADCAST;
1681 goto int_case;
1682 case TARGET_SO_SNDBUF:
1683 optname = SO_SNDBUF;
1684 goto int_case;
1685 case TARGET_SO_RCVBUF:
1686 optname = SO_RCVBUF;
1687 goto int_case;
1688 case TARGET_SO_KEEPALIVE:
1689 optname = SO_KEEPALIVE;
1690 goto int_case;
1691 case TARGET_SO_OOBINLINE:
1692 optname = SO_OOBINLINE;
1693 goto int_case;
1694 case TARGET_SO_NO_CHECK:
1695 optname = SO_NO_CHECK;
1696 goto int_case;
1697 case TARGET_SO_PRIORITY:
1698 optname = SO_PRIORITY;
1699 goto int_case;
1700#ifdef SO_BSDCOMPAT
1701 case TARGET_SO_BSDCOMPAT:
1702 optname = SO_BSDCOMPAT;
1703 goto int_case;
1704#endif
1705 case TARGET_SO_PASSCRED:
1706 optname = SO_PASSCRED;
1707 goto int_case;
1708 case TARGET_SO_TIMESTAMP:
1709 optname = SO_TIMESTAMP;
1710 goto int_case;
1711 case TARGET_SO_RCVLOWAT:
1712 optname = SO_RCVLOWAT;
1713 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001714 case TARGET_SO_ACCEPTCONN:
1715 optname = SO_ACCEPTCONN;
1716 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001717 default:
bellard2efbe912005-07-23 15:10:20 +00001718 goto int_case;
1719 }
1720 break;
1721 case SOL_TCP:
1722 /* TCP options all take an 'int' value. */
1723 int_case:
bellard2f619692007-11-16 10:46:05 +00001724 if (get_user_u32(len, optlen))
1725 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001726 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001727 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001728 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001729 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1730 if (ret < 0)
1731 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001732 if (optname == SO_TYPE) {
1733 val = host_to_target_sock_type(val);
1734 }
bellard2efbe912005-07-23 15:10:20 +00001735 if (len > lv)
1736 len = lv;
bellard2f619692007-11-16 10:46:05 +00001737 if (len == 4) {
1738 if (put_user_u32(val, optval_addr))
1739 return -TARGET_EFAULT;
1740 } else {
1741 if (put_user_u8(val, optval_addr))
1742 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001743 }
bellard2f619692007-11-16 10:46:05 +00001744 if (put_user_u32(len, optlen))
1745 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001746 break;
1747 case SOL_IP:
1748 switch(optname) {
1749 case IP_TOS:
1750 case IP_TTL:
1751 case IP_HDRINCL:
1752 case IP_ROUTER_ALERT:
1753 case IP_RECVOPTS:
1754 case IP_RETOPTS:
1755 case IP_PKTINFO:
1756 case IP_MTU_DISCOVER:
1757 case IP_RECVERR:
1758 case IP_RECVTOS:
1759#ifdef IP_FREEBIND
1760 case IP_FREEBIND:
1761#endif
1762 case IP_MULTICAST_TTL:
1763 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001764 if (get_user_u32(len, optlen))
1765 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001766 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001767 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001768 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001769 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1770 if (ret < 0)
1771 return ret;
bellard2efbe912005-07-23 15:10:20 +00001772 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001773 len = 1;
bellard2f619692007-11-16 10:46:05 +00001774 if (put_user_u32(len, optlen)
1775 || put_user_u8(val, optval_addr))
1776 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001777 } else {
bellard2efbe912005-07-23 15:10:20 +00001778 if (len > sizeof(int))
1779 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001780 if (put_user_u32(len, optlen)
1781 || put_user_u32(val, optval_addr))
1782 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001783 }
bellard8853f862004-02-22 14:57:26 +00001784 break;
bellard2efbe912005-07-23 15:10:20 +00001785 default:
thsc02f4992007-12-18 02:39:59 +00001786 ret = -TARGET_ENOPROTOOPT;
1787 break;
bellard8853f862004-02-22 14:57:26 +00001788 }
1789 break;
1790 default:
1791 unimplemented:
1792 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1793 level, optname);
thsc02f4992007-12-18 02:39:59 +00001794 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001795 break;
1796 }
1797 return ret;
bellard7854b052003-03-29 17:22:23 +00001798}
1799
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001800static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1801 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001802{
1803 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001804 struct iovec *vec;
1805 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001806 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001807 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001808 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001809
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001810 if (count == 0) {
1811 errno = 0;
1812 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001813 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001814 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001815 errno = EINVAL;
1816 return NULL;
1817 }
1818
1819 vec = calloc(count, sizeof(struct iovec));
1820 if (vec == NULL) {
1821 errno = ENOMEM;
1822 return NULL;
1823 }
1824
1825 target_vec = lock_user(VERIFY_READ, target_addr,
1826 count * sizeof(struct target_iovec), 1);
1827 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001828 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001829 goto fail2;
1830 }
1831
1832 /* ??? If host page size > target page size, this will result in a
1833 value larger than what we can actually support. */
1834 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1835 total_len = 0;
1836
1837 for (i = 0; i < count; i++) {
1838 abi_ulong base = tswapal(target_vec[i].iov_base);
1839 abi_long len = tswapal(target_vec[i].iov_len);
1840
1841 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001842 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001843 goto fail;
1844 } else if (len == 0) {
1845 /* Zero length pointer is ignored. */
1846 vec[i].iov_base = 0;
1847 } else {
1848 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05001849 /* If the first buffer pointer is bad, this is a fault. But
1850 * subsequent bad buffers will result in a partial write; this
1851 * is realized by filling the vector with null pointers and
1852 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001853 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05001854 if (i == 0) {
1855 err = EFAULT;
1856 goto fail;
1857 } else {
1858 bad_address = true;
1859 }
1860 }
1861 if (bad_address) {
1862 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001863 }
1864 if (len > max_len - total_len) {
1865 len = max_len - total_len;
1866 }
1867 }
1868 vec[i].iov_len = len;
1869 total_len += len;
1870 }
1871
1872 unlock_user(target_vec, target_addr, 0);
1873 return vec;
1874
1875 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001876 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001877 fail2:
1878 free(vec);
1879 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001880 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001881}
1882
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001883static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1884 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001885{
1886 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001887 int i;
1888
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001889 target_vec = lock_user(VERIFY_READ, target_addr,
1890 count * sizeof(struct target_iovec), 1);
1891 if (target_vec) {
1892 for (i = 0; i < count; i++) {
1893 abi_ulong base = tswapal(target_vec[i].iov_base);
1894 abi_long len = tswapal(target_vec[i].iov_base);
1895 if (len < 0) {
1896 break;
1897 }
balrogd732dcb2008-10-28 10:21:03 +00001898 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1899 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001900 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001901 }
bellard579a97f2007-11-11 14:26:47 +00001902
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001903 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001904}
1905
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001906static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001907{
1908 int host_type = 0;
1909 int target_type = *type;
1910
1911 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1912 case TARGET_SOCK_DGRAM:
1913 host_type = SOCK_DGRAM;
1914 break;
1915 case TARGET_SOCK_STREAM:
1916 host_type = SOCK_STREAM;
1917 break;
1918 default:
1919 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1920 break;
1921 }
1922 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001923#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001924 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001925#else
1926 return -TARGET_EINVAL;
1927#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001928 }
1929 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001930#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001931 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001932#elif !defined(O_NONBLOCK)
1933 return -TARGET_EINVAL;
1934#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001935 }
1936 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001937 return 0;
1938}
1939
1940/* Try to emulate socket type flags after socket creation. */
1941static int sock_flags_fixup(int fd, int target_type)
1942{
1943#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1944 if (target_type & TARGET_SOCK_NONBLOCK) {
1945 int flags = fcntl(fd, F_GETFL);
1946 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1947 close(fd);
1948 return -TARGET_EINVAL;
1949 }
1950 }
1951#endif
1952 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001953}
1954
ths0da46a62007-10-20 20:23:07 +00001955/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001956static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001957{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001958 int target_type = type;
1959 int ret;
1960
1961 ret = target_to_host_sock_type(&type);
1962 if (ret) {
1963 return ret;
1964 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001965
balrog12bc92a2007-10-30 21:06:14 +00001966 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07001967 return -TARGET_EAFNOSUPPORT;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001968 ret = get_errno(socket(domain, type, protocol));
1969 if (ret >= 0) {
1970 ret = sock_flags_fixup(ret, target_type);
1971 }
1972 return ret;
bellard3532fa72006-06-24 15:06:03 +00001973}
1974
ths0da46a62007-10-20 20:23:07 +00001975/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001976static abi_long do_bind(int sockfd, abi_ulong target_addr,
1977 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001978{
aurel328f7aeaf2009-01-30 19:47:57 +00001979 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001980 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001981
Blue Swirl38724252010-09-18 05:53:14 +00001982 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001983 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001984 }
aurel328f7aeaf2009-01-30 19:47:57 +00001985
aurel32607175e2009-04-15 16:11:59 +00001986 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001987
Arnaud Patard917507b2009-06-19 10:44:45 +03001988 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1989 if (ret)
1990 return ret;
1991
bellard3532fa72006-06-24 15:06:03 +00001992 return get_errno(bind(sockfd, addr, addrlen));
1993}
1994
ths0da46a62007-10-20 20:23:07 +00001995/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001996static abi_long do_connect(int sockfd, abi_ulong target_addr,
1997 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001998{
aurel328f7aeaf2009-01-30 19:47:57 +00001999 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002000 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002001
Blue Swirl38724252010-09-18 05:53:14 +00002002 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002003 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002004 }
aurel328f7aeaf2009-01-30 19:47:57 +00002005
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002006 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002007
Arnaud Patard917507b2009-06-19 10:44:45 +03002008 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2009 if (ret)
2010 return ret;
2011
bellard3532fa72006-06-24 15:06:03 +00002012 return get_errno(connect(sockfd, addr, addrlen));
2013}
2014
Alexander Graff19e00d2014-03-02 19:36:42 +00002015/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2016static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2017 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002018{
balrog6de645c2008-10-28 10:26:29 +00002019 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002020 struct msghdr msg;
2021 int count;
2022 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002023 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002024
bellard3532fa72006-06-24 15:06:03 +00002025 if (msgp->msg_name) {
2026 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002027 msg.msg_name = alloca(msg.msg_namelen+1);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002028 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00002029 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002030 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002031 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002032 }
bellard3532fa72006-06-24 15:06:03 +00002033 } else {
2034 msg.msg_name = NULL;
2035 msg.msg_namelen = 0;
2036 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002037 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002038 msg.msg_control = alloca(msg.msg_controllen);
2039 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002040
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002041 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002042 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002043 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2044 target_vec, count, send);
2045 if (vec == NULL) {
2046 ret = -host_to_target_errno(errno);
2047 goto out2;
2048 }
bellard3532fa72006-06-24 15:06:03 +00002049 msg.msg_iovlen = count;
2050 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002051
bellard3532fa72006-06-24 15:06:03 +00002052 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002053 ret = target_to_host_cmsg(&msg, msgp);
2054 if (ret == 0)
2055 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002056 } else {
2057 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002058 if (!is_error(ret)) {
2059 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002060 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002061 if (!is_error(ret)) {
2062 msgp->msg_namelen = tswap32(msg.msg_namelen);
2063 if (msg.msg_name != NULL) {
2064 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2065 msg.msg_name, msg.msg_namelen);
2066 if (ret) {
2067 goto out;
2068 }
2069 }
2070
balrog6de645c2008-10-28 10:26:29 +00002071 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002072 }
balrog6de645c2008-10-28 10:26:29 +00002073 }
bellard3532fa72006-06-24 15:06:03 +00002074 }
Jing Huangca619062012-07-24 13:58:02 +00002075
2076out:
bellard3532fa72006-06-24 15:06:03 +00002077 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002078out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002079 return ret;
2080}
2081
2082static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2083 int flags, int send)
2084{
2085 abi_long ret;
2086 struct target_msghdr *msgp;
2087
2088 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2089 msgp,
2090 target_msg,
2091 send ? 1 : 0)) {
2092 return -TARGET_EFAULT;
2093 }
2094 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002095 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002096 return ret;
2097}
2098
Alexander Graff19e00d2014-03-02 19:36:42 +00002099#ifdef TARGET_NR_sendmmsg
2100/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2101 * so it might not have this *mmsg-specific flag either.
2102 */
2103#ifndef MSG_WAITFORONE
2104#define MSG_WAITFORONE 0x10000
2105#endif
2106
2107static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2108 unsigned int vlen, unsigned int flags,
2109 int send)
2110{
2111 struct target_mmsghdr *mmsgp;
2112 abi_long ret = 0;
2113 int i;
2114
2115 if (vlen > UIO_MAXIOV) {
2116 vlen = UIO_MAXIOV;
2117 }
2118
2119 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2120 if (!mmsgp) {
2121 return -TARGET_EFAULT;
2122 }
2123
2124 for (i = 0; i < vlen; i++) {
2125 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2126 if (is_error(ret)) {
2127 break;
2128 }
2129 mmsgp[i].msg_len = tswap32(ret);
2130 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2131 if (flags & MSG_WAITFORONE) {
2132 flags |= MSG_DONTWAIT;
2133 }
2134 }
2135
2136 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2137
2138 /* Return number of datagrams sent if we sent any at all;
2139 * otherwise return the error.
2140 */
2141 if (i) {
2142 return i;
2143 }
2144 return ret;
2145}
2146#endif
2147
Peter Maydella94b4982013-02-08 04:35:04 +00002148/* If we don't have a system accept4() then just call accept.
2149 * The callsites to do_accept4() will ensure that they don't
2150 * pass a non-zero flags argument in this config.
2151 */
2152#ifndef CONFIG_ACCEPT4
2153static inline int accept4(int sockfd, struct sockaddr *addr,
2154 socklen_t *addrlen, int flags)
2155{
2156 assert(flags == 0);
2157 return accept(sockfd, addr, addrlen);
2158}
2159#endif
2160
2161/* do_accept4() Must return target values and target errnos. */
2162static abi_long do_accept4(int fd, abi_ulong target_addr,
2163 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002164{
bellard2f619692007-11-16 10:46:05 +00002165 socklen_t addrlen;
2166 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002167 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002168 int host_flags;
2169
2170 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002171
Peter Maydella94b4982013-02-08 04:35:04 +00002172 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002173 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002174 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002175
2176 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002177 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002178 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002179
Blue Swirl38724252010-09-18 05:53:14 +00002180 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002181 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002182 }
aurel328f7aeaf2009-01-30 19:47:57 +00002183
Arnaud Patard917507b2009-06-19 10:44:45 +03002184 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2185 return -TARGET_EINVAL;
2186
bellard2f619692007-11-16 10:46:05 +00002187 addr = alloca(addrlen);
2188
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002189 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002190 if (!is_error(ret)) {
2191 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002192 if (put_user_u32(addrlen, target_addrlen_addr))
2193 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002194 }
2195 return ret;
2196}
2197
ths0da46a62007-10-20 20:23:07 +00002198/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002199static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002200 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002201{
bellard2f619692007-11-16 10:46:05 +00002202 socklen_t addrlen;
2203 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002204 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002205
bellard2f619692007-11-16 10:46:05 +00002206 if (get_user_u32(addrlen, target_addrlen_addr))
2207 return -TARGET_EFAULT;
2208
Blue Swirl38724252010-09-18 05:53:14 +00002209 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002210 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002211 }
aurel328f7aeaf2009-01-30 19:47:57 +00002212
Arnaud Patard917507b2009-06-19 10:44:45 +03002213 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2214 return -TARGET_EFAULT;
2215
bellard2f619692007-11-16 10:46:05 +00002216 addr = alloca(addrlen);
2217
pbrook1be9e1d2006-11-19 15:26:04 +00002218 ret = get_errno(getpeername(fd, addr, &addrlen));
2219 if (!is_error(ret)) {
2220 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002221 if (put_user_u32(addrlen, target_addrlen_addr))
2222 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002223 }
2224 return ret;
2225}
2226
ths0da46a62007-10-20 20:23:07 +00002227/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002228static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002229 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002230{
bellard2f619692007-11-16 10:46:05 +00002231 socklen_t addrlen;
2232 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002233 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002234
bellard2f619692007-11-16 10:46:05 +00002235 if (get_user_u32(addrlen, target_addrlen_addr))
2236 return -TARGET_EFAULT;
2237
Blue Swirl38724252010-09-18 05:53:14 +00002238 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002239 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002240 }
aurel328f7aeaf2009-01-30 19:47:57 +00002241
Arnaud Patard917507b2009-06-19 10:44:45 +03002242 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2243 return -TARGET_EFAULT;
2244
bellard2f619692007-11-16 10:46:05 +00002245 addr = alloca(addrlen);
2246
pbrook1be9e1d2006-11-19 15:26:04 +00002247 ret = get_errno(getsockname(fd, addr, &addrlen));
2248 if (!is_error(ret)) {
2249 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002250 if (put_user_u32(addrlen, target_addrlen_addr))
2251 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002252 }
2253 return ret;
2254}
2255
ths0da46a62007-10-20 20:23:07 +00002256/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002257static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002258 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002259{
2260 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002261 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002262
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002263 target_to_host_sock_type(&type);
2264
pbrook1be9e1d2006-11-19 15:26:04 +00002265 ret = get_errno(socketpair(domain, type, protocol, tab));
2266 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002267 if (put_user_s32(tab[0], target_tab_addr)
2268 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2269 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002270 }
2271 return ret;
2272}
2273
ths0da46a62007-10-20 20:23:07 +00002274/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002275static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2276 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002277{
2278 void *addr;
2279 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002280 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002281
Blue Swirl38724252010-09-18 05:53:14 +00002282 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002283 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002284 }
aurel328f7aeaf2009-01-30 19:47:57 +00002285
bellard579a97f2007-11-11 14:26:47 +00002286 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2287 if (!host_msg)
2288 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002289 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002290 addr = alloca(addrlen+1);
Arnaud Patard917507b2009-06-19 10:44:45 +03002291 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2292 if (ret) {
2293 unlock_user(host_msg, msg, 0);
2294 return ret;
2295 }
pbrook1be9e1d2006-11-19 15:26:04 +00002296 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2297 } else {
2298 ret = get_errno(send(fd, host_msg, len, flags));
2299 }
2300 unlock_user(host_msg, msg, 0);
2301 return ret;
2302}
2303
ths0da46a62007-10-20 20:23:07 +00002304/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002305static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2306 abi_ulong target_addr,
2307 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002308{
2309 socklen_t addrlen;
2310 void *addr;
2311 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002312 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002313
bellard579a97f2007-11-11 14:26:47 +00002314 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2315 if (!host_msg)
2316 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002317 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002318 if (get_user_u32(addrlen, target_addrlen)) {
2319 ret = -TARGET_EFAULT;
2320 goto fail;
2321 }
Blue Swirl38724252010-09-18 05:53:14 +00002322 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002323 ret = -TARGET_EINVAL;
2324 goto fail;
2325 }
pbrook1be9e1d2006-11-19 15:26:04 +00002326 addr = alloca(addrlen);
2327 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2328 } else {
2329 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002330 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002331 }
2332 if (!is_error(ret)) {
2333 if (target_addr) {
2334 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002335 if (put_user_u32(addrlen, target_addrlen)) {
2336 ret = -TARGET_EFAULT;
2337 goto fail;
2338 }
pbrook1be9e1d2006-11-19 15:26:04 +00002339 }
2340 unlock_user(host_msg, msg, len);
2341 } else {
bellard2f619692007-11-16 10:46:05 +00002342fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002343 unlock_user(host_msg, msg, 0);
2344 }
2345 return ret;
2346}
2347
j_mayer32407102007-09-26 23:01:49 +00002348#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002349/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002350static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002351{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002352 static const unsigned ac[] = { /* number of arguments per call */
2353 [SOCKOP_socket] = 3, /* domain, type, protocol */
2354 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2355 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2356 [SOCKOP_listen] = 2, /* sockfd, backlog */
2357 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2358 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2359 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2360 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2361 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2362 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2363 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2364 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2365 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2366 [SOCKOP_shutdown] = 2, /* sockfd, how */
2367 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2368 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2369 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2370 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2371 };
2372 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002373
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002374 /* first, collect the arguments in a[] according to ac[] */
2375 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2376 unsigned i;
2377 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2378 for (i = 0; i < ac[num]; ++i) {
2379 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002380 return -TARGET_EFAULT;
2381 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002382 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002383 }
bellard2f619692007-11-16 10:46:05 +00002384
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002385 /* now when we have the args, actually handle the call */
2386 switch (num) {
2387 case SOCKOP_socket: /* domain, type, protocol */
2388 return do_socket(a[0], a[1], a[2]);
2389 case SOCKOP_bind: /* sockfd, addr, addrlen */
2390 return do_bind(a[0], a[1], a[2]);
2391 case SOCKOP_connect: /* sockfd, addr, addrlen */
2392 return do_connect(a[0], a[1], a[2]);
2393 case SOCKOP_listen: /* sockfd, backlog */
2394 return get_errno(listen(a[0], a[1]));
2395 case SOCKOP_accept: /* sockfd, addr, addrlen */
2396 return do_accept4(a[0], a[1], a[2], 0);
2397 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2398 return do_accept4(a[0], a[1], a[2], a[3]);
2399 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2400 return do_getsockname(a[0], a[1], a[2]);
2401 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2402 return do_getpeername(a[0], a[1], a[2]);
2403 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2404 return do_socketpair(a[0], a[1], a[2], a[3]);
2405 case SOCKOP_send: /* sockfd, msg, len, flags */
2406 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2407 case SOCKOP_recv: /* sockfd, msg, len, flags */
2408 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2409 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2410 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2411 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2412 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2413 case SOCKOP_shutdown: /* sockfd, how */
2414 return get_errno(shutdown(a[0], a[1]));
2415 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2416 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2417 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2418 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2419 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2420 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2421 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2422 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002423 default:
2424 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002425 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002426 }
bellard31e31b82003-02-18 22:55:36 +00002427}
j_mayer32407102007-09-26 23:01:49 +00002428#endif
bellard31e31b82003-02-18 22:55:36 +00002429
bellard8853f862004-02-22 14:57:26 +00002430#define N_SHM_REGIONS 32
2431
2432static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002433 abi_ulong start;
2434 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002435} shm_regions[N_SHM_REGIONS];
2436
ths3eb6b042007-06-03 14:26:27 +00002437struct target_semid_ds
2438{
2439 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002440 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002441#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002442 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002443#endif
blueswir1992f48a2007-10-14 16:27:31 +00002444 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002445#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002446 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002447#endif
blueswir1992f48a2007-10-14 16:27:31 +00002448 abi_ulong sem_nsems;
2449 abi_ulong __unused3;
2450 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002451};
2452
bellard579a97f2007-11-11 14:26:47 +00002453static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2454 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002455{
2456 struct target_ipc_perm *target_ip;
2457 struct target_semid_ds *target_sd;
2458
bellard579a97f2007-11-11 14:26:47 +00002459 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2460 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002461 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002462 host_ip->__key = tswap32(target_ip->__key);
2463 host_ip->uid = tswap32(target_ip->uid);
2464 host_ip->gid = tswap32(target_ip->gid);
2465 host_ip->cuid = tswap32(target_ip->cuid);
2466 host_ip->cgid = tswap32(target_ip->cgid);
2467#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2468 host_ip->mode = tswap32(target_ip->mode);
2469#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002470 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002471#endif
2472#if defined(TARGET_PPC)
2473 host_ip->__seq = tswap32(target_ip->__seq);
2474#else
2475 host_ip->__seq = tswap16(target_ip->__seq);
2476#endif
ths3eb6b042007-06-03 14:26:27 +00002477 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002478 return 0;
ths3eb6b042007-06-03 14:26:27 +00002479}
2480
bellard579a97f2007-11-11 14:26:47 +00002481static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2482 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002483{
2484 struct target_ipc_perm *target_ip;
2485 struct target_semid_ds *target_sd;
2486
bellard579a97f2007-11-11 14:26:47 +00002487 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2488 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002489 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002490 target_ip->__key = tswap32(host_ip->__key);
2491 target_ip->uid = tswap32(host_ip->uid);
2492 target_ip->gid = tswap32(host_ip->gid);
2493 target_ip->cuid = tswap32(host_ip->cuid);
2494 target_ip->cgid = tswap32(host_ip->cgid);
2495#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2496 target_ip->mode = tswap32(host_ip->mode);
2497#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002498 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002499#endif
2500#if defined(TARGET_PPC)
2501 target_ip->__seq = tswap32(host_ip->__seq);
2502#else
2503 target_ip->__seq = tswap16(host_ip->__seq);
2504#endif
ths3eb6b042007-06-03 14:26:27 +00002505 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002506 return 0;
ths3eb6b042007-06-03 14:26:27 +00002507}
2508
bellard579a97f2007-11-11 14:26:47 +00002509static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2510 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002511{
2512 struct target_semid_ds *target_sd;
2513
bellard579a97f2007-11-11 14:26:47 +00002514 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2515 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002516 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2517 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002518 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2519 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2520 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002521 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002522 return 0;
ths3eb6b042007-06-03 14:26:27 +00002523}
2524
bellard579a97f2007-11-11 14:26:47 +00002525static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2526 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002527{
2528 struct target_semid_ds *target_sd;
2529
bellard579a97f2007-11-11 14:26:47 +00002530 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2531 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002532 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002533 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002534 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2535 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2536 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002537 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002538 return 0;
ths3eb6b042007-06-03 14:26:27 +00002539}
2540
aurel32e5289082009-04-18 16:16:12 +00002541struct target_seminfo {
2542 int semmap;
2543 int semmni;
2544 int semmns;
2545 int semmnu;
2546 int semmsl;
2547 int semopm;
2548 int semume;
2549 int semusz;
2550 int semvmx;
2551 int semaem;
2552};
2553
2554static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2555 struct seminfo *host_seminfo)
2556{
2557 struct target_seminfo *target_seminfo;
2558 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2559 return -TARGET_EFAULT;
2560 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2561 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2562 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2563 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2564 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2565 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2566 __put_user(host_seminfo->semume, &target_seminfo->semume);
2567 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2568 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2569 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2570 unlock_user_struct(target_seminfo, target_addr, 1);
2571 return 0;
2572}
2573
thsfa294812007-02-02 22:05:00 +00002574union semun {
2575 int val;
ths3eb6b042007-06-03 14:26:27 +00002576 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002577 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002578 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002579};
2580
ths3eb6b042007-06-03 14:26:27 +00002581union target_semun {
2582 int val;
aurel32e5289082009-04-18 16:16:12 +00002583 abi_ulong buf;
2584 abi_ulong array;
2585 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002586};
2587
aurel32e5289082009-04-18 16:16:12 +00002588static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2589 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002590{
aurel32e5289082009-04-18 16:16:12 +00002591 int nsems;
2592 unsigned short *array;
2593 union semun semun;
2594 struct semid_ds semid_ds;
2595 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002596
aurel32e5289082009-04-18 16:16:12 +00002597 semun.buf = &semid_ds;
2598
2599 ret = semctl(semid, 0, IPC_STAT, semun);
2600 if (ret == -1)
2601 return get_errno(ret);
2602
2603 nsems = semid_ds.sem_nsems;
2604
2605 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002606 if (!*host_array) {
2607 return -TARGET_ENOMEM;
2608 }
aurel32e5289082009-04-18 16:16:12 +00002609 array = lock_user(VERIFY_READ, target_addr,
2610 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002611 if (!array) {
2612 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002613 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002614 }
aurel32e5289082009-04-18 16:16:12 +00002615
2616 for(i=0; i<nsems; i++) {
2617 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002618 }
aurel32e5289082009-04-18 16:16:12 +00002619 unlock_user(array, target_addr, 0);
2620
bellard579a97f2007-11-11 14:26:47 +00002621 return 0;
ths3eb6b042007-06-03 14:26:27 +00002622}
2623
aurel32e5289082009-04-18 16:16:12 +00002624static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2625 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002626{
aurel32e5289082009-04-18 16:16:12 +00002627 int nsems;
2628 unsigned short *array;
2629 union semun semun;
2630 struct semid_ds semid_ds;
2631 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002632
aurel32e5289082009-04-18 16:16:12 +00002633 semun.buf = &semid_ds;
2634
2635 ret = semctl(semid, 0, IPC_STAT, semun);
2636 if (ret == -1)
2637 return get_errno(ret);
2638
2639 nsems = semid_ds.sem_nsems;
2640
2641 array = lock_user(VERIFY_WRITE, target_addr,
2642 nsems*sizeof(unsigned short), 0);
2643 if (!array)
2644 return -TARGET_EFAULT;
2645
2646 for(i=0; i<nsems; i++) {
2647 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002648 }
aurel32e5289082009-04-18 16:16:12 +00002649 free(*host_array);
2650 unlock_user(array, target_addr, 1);
2651
bellard579a97f2007-11-11 14:26:47 +00002652 return 0;
ths3eb6b042007-06-03 14:26:27 +00002653}
2654
aurel32e5289082009-04-18 16:16:12 +00002655static inline abi_long do_semctl(int semid, int semnum, int cmd,
2656 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002657{
2658 union semun arg;
2659 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302660 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002661 struct seminfo seminfo;
2662 abi_long ret = -TARGET_EINVAL;
2663 abi_long err;
2664 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002665
2666 switch( cmd ) {
2667 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002668 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002669 /* In 64 bit cross-endian situations, we will erroneously pick up
2670 * the wrong half of the union for the "val" element. To rectify
2671 * this, the entire 8-byte structure is byteswapped, followed by
2672 * a swap of the 4 byte val field. In other cases, the data is
2673 * already in proper host byte order. */
2674 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2675 target_su.buf = tswapal(target_su.buf);
2676 arg.val = tswap32(target_su.val);
2677 } else {
2678 arg.val = target_su.val;
2679 }
aurel32e5289082009-04-18 16:16:12 +00002680 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002681 break;
2682 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002683 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002684 err = target_to_host_semarray(semid, &array, target_su.array);
2685 if (err)
2686 return err;
2687 arg.array = array;
2688 ret = get_errno(semctl(semid, semnum, cmd, arg));
2689 err = host_to_target_semarray(semid, target_su.array, &array);
2690 if (err)
2691 return err;
ths3eb6b042007-06-03 14:26:27 +00002692 break;
2693 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002694 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002695 case SEM_STAT:
2696 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2697 if (err)
2698 return err;
2699 arg.buf = &dsarg;
2700 ret = get_errno(semctl(semid, semnum, cmd, arg));
2701 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2702 if (err)
2703 return err;
ths3eb6b042007-06-03 14:26:27 +00002704 break;
aurel32e5289082009-04-18 16:16:12 +00002705 case IPC_INFO:
2706 case SEM_INFO:
2707 arg.__buf = &seminfo;
2708 ret = get_errno(semctl(semid, semnum, cmd, arg));
2709 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2710 if (err)
2711 return err;
2712 break;
2713 case IPC_RMID:
2714 case GETPID:
2715 case GETNCNT:
2716 case GETZCNT:
2717 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2718 break;
ths3eb6b042007-06-03 14:26:27 +00002719 }
2720
2721 return ret;
2722}
2723
aurel32e5289082009-04-18 16:16:12 +00002724struct target_sembuf {
2725 unsigned short sem_num;
2726 short sem_op;
2727 short sem_flg;
2728};
2729
2730static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2731 abi_ulong target_addr,
2732 unsigned nsops)
2733{
2734 struct target_sembuf *target_sembuf;
2735 int i;
2736
2737 target_sembuf = lock_user(VERIFY_READ, target_addr,
2738 nsops*sizeof(struct target_sembuf), 1);
2739 if (!target_sembuf)
2740 return -TARGET_EFAULT;
2741
2742 for(i=0; i<nsops; i++) {
2743 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2744 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2745 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2746 }
2747
2748 unlock_user(target_sembuf, target_addr, 0);
2749
2750 return 0;
2751}
2752
2753static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2754{
2755 struct sembuf sops[nsops];
2756
2757 if (target_to_host_sembuf(sops, ptr, nsops))
2758 return -TARGET_EFAULT;
2759
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002760 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002761}
2762
ths1bc012f2007-06-03 14:27:49 +00002763struct target_msqid_ds
2764{
aurel321c54ff92008-10-13 21:08:44 +00002765 struct target_ipc_perm msg_perm;
2766 abi_ulong msg_stime;
2767#if TARGET_ABI_BITS == 32
2768 abi_ulong __unused1;
2769#endif
2770 abi_ulong msg_rtime;
2771#if TARGET_ABI_BITS == 32
2772 abi_ulong __unused2;
2773#endif
2774 abi_ulong msg_ctime;
2775#if TARGET_ABI_BITS == 32
2776 abi_ulong __unused3;
2777#endif
2778 abi_ulong __msg_cbytes;
2779 abi_ulong msg_qnum;
2780 abi_ulong msg_qbytes;
2781 abi_ulong msg_lspid;
2782 abi_ulong msg_lrpid;
2783 abi_ulong __unused4;
2784 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002785};
2786
bellard579a97f2007-11-11 14:26:47 +00002787static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2788 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002789{
2790 struct target_msqid_ds *target_md;
2791
bellard579a97f2007-11-11 14:26:47 +00002792 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2793 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002794 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2795 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002796 host_md->msg_stime = tswapal(target_md->msg_stime);
2797 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2798 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2799 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2800 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2801 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2802 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2803 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002804 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002805 return 0;
ths1bc012f2007-06-03 14:27:49 +00002806}
2807
bellard579a97f2007-11-11 14:26:47 +00002808static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2809 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002810{
2811 struct target_msqid_ds *target_md;
2812
bellard579a97f2007-11-11 14:26:47 +00002813 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2814 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002815 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2816 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002817 target_md->msg_stime = tswapal(host_md->msg_stime);
2818 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2819 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2820 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2821 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2822 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2823 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2824 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002825 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002826 return 0;
ths1bc012f2007-06-03 14:27:49 +00002827}
2828
aurel321c54ff92008-10-13 21:08:44 +00002829struct target_msginfo {
2830 int msgpool;
2831 int msgmap;
2832 int msgmax;
2833 int msgmnb;
2834 int msgmni;
2835 int msgssz;
2836 int msgtql;
2837 unsigned short int msgseg;
2838};
2839
2840static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2841 struct msginfo *host_msginfo)
2842{
2843 struct target_msginfo *target_msginfo;
2844 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2845 return -TARGET_EFAULT;
2846 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2847 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2848 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2849 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2850 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2851 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2852 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2853 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2854 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002855 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002856}
2857
2858static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002859{
2860 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002861 struct msginfo msginfo;
2862 abi_long ret = -TARGET_EINVAL;
2863
2864 cmd &= 0xff;
2865
2866 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002867 case IPC_STAT:
2868 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002869 case MSG_STAT:
2870 if (target_to_host_msqid_ds(&dsarg,ptr))
2871 return -TARGET_EFAULT;
2872 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2873 if (host_to_target_msqid_ds(ptr,&dsarg))
2874 return -TARGET_EFAULT;
2875 break;
2876 case IPC_RMID:
2877 ret = get_errno(msgctl(msgid, cmd, NULL));
2878 break;
2879 case IPC_INFO:
2880 case MSG_INFO:
2881 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2882 if (host_to_target_msginfo(ptr, &msginfo))
2883 return -TARGET_EFAULT;
2884 break;
ths1bc012f2007-06-03 14:27:49 +00002885 }
aurel321c54ff92008-10-13 21:08:44 +00002886
ths1bc012f2007-06-03 14:27:49 +00002887 return ret;
2888}
2889
2890struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002891 abi_long mtype;
2892 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002893};
2894
blueswir1992f48a2007-10-14 16:27:31 +00002895static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05002896 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002897{
2898 struct target_msgbuf *target_mb;
2899 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002900 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002901
Tom Mustaedcc5f92014-08-12 13:53:37 -05002902 if (msgsz < 0) {
2903 return -TARGET_EINVAL;
2904 }
2905
bellard579a97f2007-11-11 14:26:47 +00002906 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2907 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002908 host_mb = malloc(msgsz+sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08002909 if (!host_mb) {
2910 unlock_user_struct(target_mb, msgp, 0);
2911 return -TARGET_ENOMEM;
2912 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002913 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002914 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002915 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2916 free(host_mb);
2917 unlock_user_struct(target_mb, msgp, 0);
2918
2919 return ret;
2920}
2921
blueswir1992f48a2007-10-14 16:27:31 +00002922static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002923 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002924 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002925{
2926 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002927 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002928 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002929 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002930
bellard579a97f2007-11-11 14:26:47 +00002931 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2932 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002933
Jim Meyering0d07fe42012-08-22 13:55:53 +02002934 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002935 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002936
bellard579a97f2007-11-11 14:26:47 +00002937 if (ret > 0) {
2938 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2939 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2940 if (!target_mtext) {
2941 ret = -TARGET_EFAULT;
2942 goto end;
2943 }
aurel321c54ff92008-10-13 21:08:44 +00002944 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002945 unlock_user(target_mtext, target_mtext_addr, ret);
2946 }
aurel321c54ff92008-10-13 21:08:44 +00002947
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002948 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002949
bellard579a97f2007-11-11 14:26:47 +00002950end:
2951 if (target_mb)
2952 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002953 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002954 return ret;
2955}
2956
Riku Voipio88a8c982009-04-03 10:42:00 +03002957static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2958 abi_ulong target_addr)
2959{
2960 struct target_shmid_ds *target_sd;
2961
2962 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2963 return -TARGET_EFAULT;
2964 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2965 return -TARGET_EFAULT;
2966 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2967 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2968 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2969 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2970 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2971 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2972 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2973 unlock_user_struct(target_sd, target_addr, 0);
2974 return 0;
2975}
2976
2977static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2978 struct shmid_ds *host_sd)
2979{
2980 struct target_shmid_ds *target_sd;
2981
2982 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2983 return -TARGET_EFAULT;
2984 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2985 return -TARGET_EFAULT;
2986 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2987 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2988 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2989 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2990 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2991 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2992 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2993 unlock_user_struct(target_sd, target_addr, 1);
2994 return 0;
2995}
2996
2997struct target_shminfo {
2998 abi_ulong shmmax;
2999 abi_ulong shmmin;
3000 abi_ulong shmmni;
3001 abi_ulong shmseg;
3002 abi_ulong shmall;
3003};
3004
3005static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3006 struct shminfo *host_shminfo)
3007{
3008 struct target_shminfo *target_shminfo;
3009 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3010 return -TARGET_EFAULT;
3011 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3012 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3013 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3014 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3015 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3016 unlock_user_struct(target_shminfo, target_addr, 1);
3017 return 0;
3018}
3019
3020struct target_shm_info {
3021 int used_ids;
3022 abi_ulong shm_tot;
3023 abi_ulong shm_rss;
3024 abi_ulong shm_swp;
3025 abi_ulong swap_attempts;
3026 abi_ulong swap_successes;
3027};
3028
3029static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3030 struct shm_info *host_shm_info)
3031{
3032 struct target_shm_info *target_shm_info;
3033 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3034 return -TARGET_EFAULT;
3035 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3036 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3037 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3038 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3039 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3040 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3041 unlock_user_struct(target_shm_info, target_addr, 1);
3042 return 0;
3043}
3044
3045static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3046{
3047 struct shmid_ds dsarg;
3048 struct shminfo shminfo;
3049 struct shm_info shm_info;
3050 abi_long ret = -TARGET_EINVAL;
3051
3052 cmd &= 0xff;
3053
3054 switch(cmd) {
3055 case IPC_STAT:
3056 case IPC_SET:
3057 case SHM_STAT:
3058 if (target_to_host_shmid_ds(&dsarg, buf))
3059 return -TARGET_EFAULT;
3060 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3061 if (host_to_target_shmid_ds(buf, &dsarg))
3062 return -TARGET_EFAULT;
3063 break;
3064 case IPC_INFO:
3065 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3066 if (host_to_target_shminfo(buf, &shminfo))
3067 return -TARGET_EFAULT;
3068 break;
3069 case SHM_INFO:
3070 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3071 if (host_to_target_shm_info(buf, &shm_info))
3072 return -TARGET_EFAULT;
3073 break;
3074 case IPC_RMID:
3075 case SHM_LOCK:
3076 case SHM_UNLOCK:
3077 ret = get_errno(shmctl(shmid, cmd, NULL));
3078 break;
3079 }
3080
3081 return ret;
3082}
3083
3084static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3085{
3086 abi_long raddr;
3087 void *host_raddr;
3088 struct shmid_ds shm_info;
3089 int i,ret;
3090
3091 /* find out the length of the shared memory segment */
3092 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3093 if (is_error(ret)) {
3094 /* can't get length, bail out */
3095 return ret;
3096 }
3097
3098 mmap_lock();
3099
3100 if (shmaddr)
3101 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3102 else {
3103 abi_ulong mmap_start;
3104
3105 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3106
3107 if (mmap_start == -1) {
3108 errno = ENOMEM;
3109 host_raddr = (void *)-1;
3110 } else
3111 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3112 }
3113
3114 if (host_raddr == (void *)-1) {
3115 mmap_unlock();
3116 return get_errno((long)host_raddr);
3117 }
3118 raddr=h2g((unsigned long)host_raddr);
3119
3120 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3121 PAGE_VALID | PAGE_READ |
3122 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3123
3124 for (i = 0; i < N_SHM_REGIONS; i++) {
3125 if (shm_regions[i].start == 0) {
3126 shm_regions[i].start = raddr;
3127 shm_regions[i].size = shm_info.shm_segsz;
3128 break;
3129 }
3130 }
3131
3132 mmap_unlock();
3133 return raddr;
3134
3135}
3136
3137static inline abi_long do_shmdt(abi_ulong shmaddr)
3138{
3139 int i;
3140
3141 for (i = 0; i < N_SHM_REGIONS; ++i) {
3142 if (shm_regions[i].start == shmaddr) {
3143 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003144 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003145 break;
3146 }
3147 }
3148
3149 return get_errno(shmdt(g2h(shmaddr)));
3150}
3151
aurel321c54ff92008-10-13 21:08:44 +00003152#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003153/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003154/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003155static abi_long do_ipc(unsigned int call, abi_long first,
3156 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003157 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003158{
3159 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003160 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003161
3162 version = call >> 16;
3163 call &= 0xffff;
3164
3165 switch (call) {
thsfa294812007-02-02 22:05:00 +00003166 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003167 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003168 break;
3169
3170 case IPCOP_semget:
3171 ret = get_errno(semget(first, second, third));
3172 break;
3173
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003174 case IPCOP_semctl: {
3175 /* The semun argument to semctl is passed by value, so dereference the
3176 * ptr argument. */
3177 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003178 get_user_ual(atptr, ptr);
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003179 ret = do_semctl(first, second, third,
Tom Musta37ed0952014-08-12 13:53:35 -05003180 (union target_semun) atptr);
thsfa294812007-02-02 22:05:00 +00003181 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003182 }
thsd96372e2007-02-02 22:05:44 +00003183
aurel321c54ff92008-10-13 21:08:44 +00003184 case IPCOP_msgget:
3185 ret = get_errno(msgget(first, second));
3186 break;
thsd96372e2007-02-02 22:05:44 +00003187
aurel321c54ff92008-10-13 21:08:44 +00003188 case IPCOP_msgsnd:
3189 ret = do_msgsnd(first, ptr, second, third);
3190 break;
thsd96372e2007-02-02 22:05:44 +00003191
aurel321c54ff92008-10-13 21:08:44 +00003192 case IPCOP_msgctl:
3193 ret = do_msgctl(first, second, ptr);
3194 break;
thsd96372e2007-02-02 22:05:44 +00003195
aurel321c54ff92008-10-13 21:08:44 +00003196 case IPCOP_msgrcv:
3197 switch (version) {
3198 case 0:
3199 {
3200 struct target_ipc_kludge {
3201 abi_long msgp;
3202 abi_long msgtyp;
3203 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003204
aurel321c54ff92008-10-13 21:08:44 +00003205 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3206 ret = -TARGET_EFAULT;
3207 break;
ths1bc012f2007-06-03 14:27:49 +00003208 }
aurel321c54ff92008-10-13 21:08:44 +00003209
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003210 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003211
3212 unlock_user_struct(tmp, ptr, 0);
3213 break;
3214 }
3215 default:
3216 ret = do_msgrcv(first, ptr, second, fifth, third);
3217 }
3218 break;
thsd96372e2007-02-02 22:05:44 +00003219
bellard8853f862004-02-22 14:57:26 +00003220 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003221 switch (version) {
3222 default:
bellard5a4a8982007-11-11 17:39:18 +00003223 {
3224 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003225 raddr = do_shmat(first, ptr, second);
3226 if (is_error(raddr))
3227 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003228 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003229 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003230 break;
3231 }
3232 case 1:
3233 ret = -TARGET_EINVAL;
3234 break;
bellard5a4a8982007-11-11 17:39:18 +00003235 }
bellard8853f862004-02-22 14:57:26 +00003236 break;
3237 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003238 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003239 break;
3240
3241 case IPCOP_shmget:
3242 /* IPC_* flag values are the same on all linux platforms */
3243 ret = get_errno(shmget(first, second, third));
3244 break;
3245
3246 /* IPC_* and SHM_* command values are the same on all linux platforms */
3247 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003248 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003249 break;
3250 default:
j_mayer32407102007-09-26 23:01:49 +00003251 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003252 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003253 break;
3254 }
3255 return ret;
3256}
j_mayer32407102007-09-26 23:01:49 +00003257#endif
bellard8853f862004-02-22 14:57:26 +00003258
bellard31e31b82003-02-18 22:55:36 +00003259/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003260
Blue Swirl001faf32009-05-13 17:53:17 +00003261#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003262#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3263enum {
3264#include "syscall_types.h"
3265};
3266#undef STRUCT
3267#undef STRUCT_SPECIAL
3268
Blue Swirl001faf32009-05-13 17:53:17 +00003269#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003270#define STRUCT_SPECIAL(name)
3271#include "syscall_types.h"
3272#undef STRUCT
3273#undef STRUCT_SPECIAL
3274
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003275typedef struct IOCTLEntry IOCTLEntry;
3276
3277typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3278 int fd, abi_long cmd, abi_long arg);
3279
3280struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003281 unsigned int target_cmd;
3282 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003283 const char *name;
3284 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003285 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003286 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003287};
bellard31e31b82003-02-18 22:55:36 +00003288
3289#define IOC_R 0x0001
3290#define IOC_W 0x0002
3291#define IOC_RW (IOC_R | IOC_W)
3292
3293#define MAX_STRUCT_SIZE 4096
3294
Peter Maydelldace20d2011-01-10 13:11:24 +00003295#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003296/* So fiemap access checks don't overflow on 32 bit systems.
3297 * This is very slightly smaller than the limit imposed by
3298 * the underlying kernel.
3299 */
3300#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3301 / sizeof(struct fiemap_extent))
3302
3303static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3304 int fd, abi_long cmd, abi_long arg)
3305{
3306 /* The parameter for this ioctl is a struct fiemap followed
3307 * by an array of struct fiemap_extent whose size is set
3308 * in fiemap->fm_extent_count. The array is filled in by the
3309 * ioctl.
3310 */
3311 int target_size_in, target_size_out;
3312 struct fiemap *fm;
3313 const argtype *arg_type = ie->arg_type;
3314 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3315 void *argptr, *p;
3316 abi_long ret;
3317 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3318 uint32_t outbufsz;
3319 int free_fm = 0;
3320
3321 assert(arg_type[0] == TYPE_PTR);
3322 assert(ie->access == IOC_RW);
3323 arg_type++;
3324 target_size_in = thunk_type_size(arg_type, 0);
3325 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3326 if (!argptr) {
3327 return -TARGET_EFAULT;
3328 }
3329 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3330 unlock_user(argptr, arg, 0);
3331 fm = (struct fiemap *)buf_temp;
3332 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3333 return -TARGET_EINVAL;
3334 }
3335
3336 outbufsz = sizeof (*fm) +
3337 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3338
3339 if (outbufsz > MAX_STRUCT_SIZE) {
3340 /* We can't fit all the extents into the fixed size buffer.
3341 * Allocate one that is large enough and use it instead.
3342 */
3343 fm = malloc(outbufsz);
3344 if (!fm) {
3345 return -TARGET_ENOMEM;
3346 }
3347 memcpy(fm, buf_temp, sizeof(struct fiemap));
3348 free_fm = 1;
3349 }
3350 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3351 if (!is_error(ret)) {
3352 target_size_out = target_size_in;
3353 /* An extent_count of 0 means we were only counting the extents
3354 * so there are no structs to copy
3355 */
3356 if (fm->fm_extent_count != 0) {
3357 target_size_out += fm->fm_mapped_extents * extent_size;
3358 }
3359 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3360 if (!argptr) {
3361 ret = -TARGET_EFAULT;
3362 } else {
3363 /* Convert the struct fiemap */
3364 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3365 if (fm->fm_extent_count != 0) {
3366 p = argptr + target_size_in;
3367 /* ...and then all the struct fiemap_extents */
3368 for (i = 0; i < fm->fm_mapped_extents; i++) {
3369 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3370 THUNK_TARGET);
3371 p += extent_size;
3372 }
3373 }
3374 unlock_user(argptr, arg, target_size_out);
3375 }
3376 }
3377 if (free_fm) {
3378 free(fm);
3379 }
3380 return ret;
3381}
Peter Maydelldace20d2011-01-10 13:11:24 +00003382#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003383
Laurent Vivier059c2f22011-03-30 00:12:12 +02003384static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3385 int fd, abi_long cmd, abi_long arg)
3386{
3387 const argtype *arg_type = ie->arg_type;
3388 int target_size;
3389 void *argptr;
3390 int ret;
3391 struct ifconf *host_ifconf;
3392 uint32_t outbufsz;
3393 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3394 int target_ifreq_size;
3395 int nb_ifreq;
3396 int free_buf = 0;
3397 int i;
3398 int target_ifc_len;
3399 abi_long target_ifc_buf;
3400 int host_ifc_len;
3401 char *host_ifc_buf;
3402
3403 assert(arg_type[0] == TYPE_PTR);
3404 assert(ie->access == IOC_RW);
3405
3406 arg_type++;
3407 target_size = thunk_type_size(arg_type, 0);
3408
3409 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3410 if (!argptr)
3411 return -TARGET_EFAULT;
3412 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3413 unlock_user(argptr, arg, 0);
3414
3415 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3416 target_ifc_len = host_ifconf->ifc_len;
3417 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3418
3419 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3420 nb_ifreq = target_ifc_len / target_ifreq_size;
3421 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3422
3423 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3424 if (outbufsz > MAX_STRUCT_SIZE) {
3425 /* We can't fit all the extents into the fixed size buffer.
3426 * Allocate one that is large enough and use it instead.
3427 */
3428 host_ifconf = malloc(outbufsz);
3429 if (!host_ifconf) {
3430 return -TARGET_ENOMEM;
3431 }
3432 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3433 free_buf = 1;
3434 }
3435 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3436
3437 host_ifconf->ifc_len = host_ifc_len;
3438 host_ifconf->ifc_buf = host_ifc_buf;
3439
3440 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3441 if (!is_error(ret)) {
3442 /* convert host ifc_len to target ifc_len */
3443
3444 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3445 target_ifc_len = nb_ifreq * target_ifreq_size;
3446 host_ifconf->ifc_len = target_ifc_len;
3447
3448 /* restore target ifc_buf */
3449
3450 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3451
3452 /* copy struct ifconf to target user */
3453
3454 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3455 if (!argptr)
3456 return -TARGET_EFAULT;
3457 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3458 unlock_user(argptr, arg, target_size);
3459
3460 /* copy ifreq[] to target user */
3461
3462 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3463 for (i = 0; i < nb_ifreq ; i++) {
3464 thunk_convert(argptr + i * target_ifreq_size,
3465 host_ifc_buf + i * sizeof(struct ifreq),
3466 ifreq_arg_type, THUNK_TARGET);
3467 }
3468 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3469 }
3470
3471 if (free_buf) {
3472 free(host_ifconf);
3473 }
3474
3475 return ret;
3476}
3477
Alexander Graf56e904e2012-01-31 18:42:06 +01003478static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3479 abi_long cmd, abi_long arg)
3480{
3481 void *argptr;
3482 struct dm_ioctl *host_dm;
3483 abi_long guest_data;
3484 uint32_t guest_data_size;
3485 int target_size;
3486 const argtype *arg_type = ie->arg_type;
3487 abi_long ret;
3488 void *big_buf = NULL;
3489 char *host_data;
3490
3491 arg_type++;
3492 target_size = thunk_type_size(arg_type, 0);
3493 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3494 if (!argptr) {
3495 ret = -TARGET_EFAULT;
3496 goto out;
3497 }
3498 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3499 unlock_user(argptr, arg, 0);
3500
3501 /* buf_temp is too small, so fetch things into a bigger buffer */
3502 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3503 memcpy(big_buf, buf_temp, target_size);
3504 buf_temp = big_buf;
3505 host_dm = big_buf;
3506
3507 guest_data = arg + host_dm->data_start;
3508 if ((guest_data - arg) < 0) {
3509 ret = -EINVAL;
3510 goto out;
3511 }
3512 guest_data_size = host_dm->data_size - host_dm->data_start;
3513 host_data = (char*)host_dm + host_dm->data_start;
3514
3515 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3516 switch (ie->host_cmd) {
3517 case DM_REMOVE_ALL:
3518 case DM_LIST_DEVICES:
3519 case DM_DEV_CREATE:
3520 case DM_DEV_REMOVE:
3521 case DM_DEV_SUSPEND:
3522 case DM_DEV_STATUS:
3523 case DM_DEV_WAIT:
3524 case DM_TABLE_STATUS:
3525 case DM_TABLE_CLEAR:
3526 case DM_TABLE_DEPS:
3527 case DM_LIST_VERSIONS:
3528 /* no input data */
3529 break;
3530 case DM_DEV_RENAME:
3531 case DM_DEV_SET_GEOMETRY:
3532 /* data contains only strings */
3533 memcpy(host_data, argptr, guest_data_size);
3534 break;
3535 case DM_TARGET_MSG:
3536 memcpy(host_data, argptr, guest_data_size);
3537 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3538 break;
3539 case DM_TABLE_LOAD:
3540 {
3541 void *gspec = argptr;
3542 void *cur_data = host_data;
3543 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3544 int spec_size = thunk_type_size(arg_type, 0);
3545 int i;
3546
3547 for (i = 0; i < host_dm->target_count; i++) {
3548 struct dm_target_spec *spec = cur_data;
3549 uint32_t next;
3550 int slen;
3551
3552 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3553 slen = strlen((char*)gspec + spec_size) + 1;
3554 next = spec->next;
3555 spec->next = sizeof(*spec) + slen;
3556 strcpy((char*)&spec[1], gspec + spec_size);
3557 gspec += next;
3558 cur_data += spec->next;
3559 }
3560 break;
3561 }
3562 default:
3563 ret = -TARGET_EINVAL;
3564 goto out;
3565 }
3566 unlock_user(argptr, guest_data, 0);
3567
3568 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3569 if (!is_error(ret)) {
3570 guest_data = arg + host_dm->data_start;
3571 guest_data_size = host_dm->data_size - host_dm->data_start;
3572 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3573 switch (ie->host_cmd) {
3574 case DM_REMOVE_ALL:
3575 case DM_DEV_CREATE:
3576 case DM_DEV_REMOVE:
3577 case DM_DEV_RENAME:
3578 case DM_DEV_SUSPEND:
3579 case DM_DEV_STATUS:
3580 case DM_TABLE_LOAD:
3581 case DM_TABLE_CLEAR:
3582 case DM_TARGET_MSG:
3583 case DM_DEV_SET_GEOMETRY:
3584 /* no return data */
3585 break;
3586 case DM_LIST_DEVICES:
3587 {
3588 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3589 uint32_t remaining_data = guest_data_size;
3590 void *cur_data = argptr;
3591 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3592 int nl_size = 12; /* can't use thunk_size due to alignment */
3593
3594 while (1) {
3595 uint32_t next = nl->next;
3596 if (next) {
3597 nl->next = nl_size + (strlen(nl->name) + 1);
3598 }
3599 if (remaining_data < nl->next) {
3600 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3601 break;
3602 }
3603 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3604 strcpy(cur_data + nl_size, nl->name);
3605 cur_data += nl->next;
3606 remaining_data -= nl->next;
3607 if (!next) {
3608 break;
3609 }
3610 nl = (void*)nl + next;
3611 }
3612 break;
3613 }
3614 case DM_DEV_WAIT:
3615 case DM_TABLE_STATUS:
3616 {
3617 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3618 void *cur_data = argptr;
3619 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3620 int spec_size = thunk_type_size(arg_type, 0);
3621 int i;
3622
3623 for (i = 0; i < host_dm->target_count; i++) {
3624 uint32_t next = spec->next;
3625 int slen = strlen((char*)&spec[1]) + 1;
3626 spec->next = (cur_data - argptr) + spec_size + slen;
3627 if (guest_data_size < spec->next) {
3628 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3629 break;
3630 }
3631 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3632 strcpy(cur_data + spec_size, (char*)&spec[1]);
3633 cur_data = argptr + spec->next;
3634 spec = (void*)host_dm + host_dm->data_start + next;
3635 }
3636 break;
3637 }
3638 case DM_TABLE_DEPS:
3639 {
3640 void *hdata = (void*)host_dm + host_dm->data_start;
3641 int count = *(uint32_t*)hdata;
3642 uint64_t *hdev = hdata + 8;
3643 uint64_t *gdev = argptr + 8;
3644 int i;
3645
3646 *(uint32_t*)argptr = tswap32(count);
3647 for (i = 0; i < count; i++) {
3648 *gdev = tswap64(*hdev);
3649 gdev++;
3650 hdev++;
3651 }
3652 break;
3653 }
3654 case DM_LIST_VERSIONS:
3655 {
3656 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3657 uint32_t remaining_data = guest_data_size;
3658 void *cur_data = argptr;
3659 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3660 int vers_size = thunk_type_size(arg_type, 0);
3661
3662 while (1) {
3663 uint32_t next = vers->next;
3664 if (next) {
3665 vers->next = vers_size + (strlen(vers->name) + 1);
3666 }
3667 if (remaining_data < vers->next) {
3668 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3669 break;
3670 }
3671 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3672 strcpy(cur_data + vers_size, vers->name);
3673 cur_data += vers->next;
3674 remaining_data -= vers->next;
3675 if (!next) {
3676 break;
3677 }
3678 vers = (void*)vers + next;
3679 }
3680 break;
3681 }
3682 default:
3683 ret = -TARGET_EINVAL;
3684 goto out;
3685 }
3686 unlock_user(argptr, guest_data, guest_data_size);
3687
3688 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3689 if (!argptr) {
3690 ret = -TARGET_EFAULT;
3691 goto out;
3692 }
3693 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3694 unlock_user(argptr, arg, target_size);
3695 }
3696out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003697 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003698 return ret;
3699}
3700
Alexander Grafa59b5e32014-08-22 13:15:50 +02003701static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3702 abi_long cmd, abi_long arg)
3703{
3704 void *argptr;
3705 int target_size;
3706 const argtype *arg_type = ie->arg_type;
3707 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3708 abi_long ret;
3709
3710 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3711 struct blkpg_partition host_part;
3712
3713 /* Read and convert blkpg */
3714 arg_type++;
3715 target_size = thunk_type_size(arg_type, 0);
3716 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3717 if (!argptr) {
3718 ret = -TARGET_EFAULT;
3719 goto out;
3720 }
3721 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3722 unlock_user(argptr, arg, 0);
3723
3724 switch (host_blkpg->op) {
3725 case BLKPG_ADD_PARTITION:
3726 case BLKPG_DEL_PARTITION:
3727 /* payload is struct blkpg_partition */
3728 break;
3729 default:
3730 /* Unknown opcode */
3731 ret = -TARGET_EINVAL;
3732 goto out;
3733 }
3734
3735 /* Read and convert blkpg->data */
3736 arg = (abi_long)(uintptr_t)host_blkpg->data;
3737 target_size = thunk_type_size(part_arg_type, 0);
3738 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3739 if (!argptr) {
3740 ret = -TARGET_EFAULT;
3741 goto out;
3742 }
3743 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3744 unlock_user(argptr, arg, 0);
3745
3746 /* Swizzle the data pointer to our local copy and call! */
3747 host_blkpg->data = &host_part;
3748 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3749
3750out:
3751 return ret;
3752}
3753
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003754static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3755 int fd, abi_long cmd, abi_long arg)
3756{
3757 const argtype *arg_type = ie->arg_type;
3758 const StructEntry *se;
3759 const argtype *field_types;
3760 const int *dst_offsets, *src_offsets;
3761 int target_size;
3762 void *argptr;
3763 abi_ulong *target_rt_dev_ptr;
3764 unsigned long *host_rt_dev_ptr;
3765 abi_long ret;
3766 int i;
3767
3768 assert(ie->access == IOC_W);
3769 assert(*arg_type == TYPE_PTR);
3770 arg_type++;
3771 assert(*arg_type == TYPE_STRUCT);
3772 target_size = thunk_type_size(arg_type, 0);
3773 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3774 if (!argptr) {
3775 return -TARGET_EFAULT;
3776 }
3777 arg_type++;
3778 assert(*arg_type == (int)STRUCT_rtentry);
3779 se = struct_entries + *arg_type++;
3780 assert(se->convert[0] == NULL);
3781 /* convert struct here to be able to catch rt_dev string */
3782 field_types = se->field_types;
3783 dst_offsets = se->field_offsets[THUNK_HOST];
3784 src_offsets = se->field_offsets[THUNK_TARGET];
3785 for (i = 0; i < se->nb_fields; i++) {
3786 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3787 assert(*field_types == TYPE_PTRVOID);
3788 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3789 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3790 if (*target_rt_dev_ptr != 0) {
3791 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3792 tswapal(*target_rt_dev_ptr));
3793 if (!*host_rt_dev_ptr) {
3794 unlock_user(argptr, arg, 0);
3795 return -TARGET_EFAULT;
3796 }
3797 } else {
3798 *host_rt_dev_ptr = 0;
3799 }
3800 field_types++;
3801 continue;
3802 }
3803 field_types = thunk_convert(buf_temp + dst_offsets[i],
3804 argptr + src_offsets[i],
3805 field_types, THUNK_HOST);
3806 }
3807 unlock_user(argptr, arg, 0);
3808
3809 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3810 if (*host_rt_dev_ptr != 0) {
3811 unlock_user((void *)*host_rt_dev_ptr,
3812 *target_rt_dev_ptr, 0);
3813 }
3814 return ret;
3815}
3816
Paul Burtonca56f5b2014-06-22 11:25:47 +01003817static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
3818 int fd, abi_long cmd, abi_long arg)
3819{
3820 int sig = target_to_host_signal(arg);
3821 return get_errno(ioctl(fd, ie->host_cmd, sig));
3822}
3823
blueswir19f106a72008-10-05 10:52:52 +00003824static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003825#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003826 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3827#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3828 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003829#include "ioctls.h"
3830 { 0, 0, },
3831};
3832
pbrook53a59602006-03-25 19:31:22 +00003833/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003834/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003835static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003836{
3837 const IOCTLEntry *ie;
3838 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003839 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003840 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003841 int target_size;
3842 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003843
3844 ie = ioctl_entries;
3845 for(;;) {
3846 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003847 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003848 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003849 }
3850 if (ie->target_cmd == cmd)
3851 break;
3852 ie++;
3853 }
3854 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003855#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003856 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003857#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003858 if (ie->do_ioctl) {
3859 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3860 }
3861
bellard31e31b82003-02-18 22:55:36 +00003862 switch(arg_type[0]) {
3863 case TYPE_NULL:
3864 /* no argument */
3865 ret = get_errno(ioctl(fd, ie->host_cmd));
3866 break;
3867 case TYPE_PTRVOID:
3868 case TYPE_INT:
3869 /* int argment */
3870 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3871 break;
3872 case TYPE_PTR:
3873 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003874 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003875 switch(ie->access) {
3876 case IOC_R:
3877 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3878 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003879 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3880 if (!argptr)
3881 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003882 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3883 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003884 }
3885 break;
3886 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003887 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3888 if (!argptr)
3889 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003890 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3891 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003892 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3893 break;
3894 default:
3895 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003896 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3897 if (!argptr)
3898 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003899 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3900 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003901 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3902 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003903 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3904 if (!argptr)
3905 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003906 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3907 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003908 }
3909 break;
3910 }
3911 break;
3912 default:
j_mayer32407102007-09-26 23:01:49 +00003913 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3914 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003915 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003916 break;
3917 }
3918 return ret;
3919}
3920
blueswir1b39bc502008-10-05 10:51:10 +00003921static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003922 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3923 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3924 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3925 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3926 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3927 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3928 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3929 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3930 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3931 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3932 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3933 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3934 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3935 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3936 { 0, 0, 0, 0 }
3937};
3938
blueswir1b39bc502008-10-05 10:51:10 +00003939static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003940 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3941 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3942 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3943 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3944 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3945 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3946 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3947 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3948 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3949 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3950 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3951 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3952 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3953 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3954 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3955 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3956 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3957 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3958 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3959 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3960 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3961 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3962 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3963 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3964 { 0, 0, 0, 0 }
3965};
3966
blueswir1b39bc502008-10-05 10:51:10 +00003967static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003968 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3969 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3970 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3971 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3972 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3973 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3974 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3975 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3976 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3977 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3978 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3979 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3980 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3981 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3982 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3983 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3984 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3985 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3986 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3987 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3988 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3989 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3990 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3991 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3992 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3993 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3994 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3995 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3996 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3997 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3998 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3999 { 0, 0, 0, 0 }
4000};
4001
blueswir1b39bc502008-10-05 10:51:10 +00004002static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004003 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4004 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4005 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4006 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4007 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4008 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4009 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4010 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4011 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4012 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4013 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4014 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4015 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4016 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4017 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4018 { 0, 0, 0, 0 }
4019};
4020
4021static void target_to_host_termios (void *dst, const void *src)
4022{
4023 struct host_termios *host = dst;
4024 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004025
ths5fafdf22007-09-16 21:08:06 +00004026 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004027 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004028 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004029 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004030 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004031 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004032 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004033 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4034 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004035
Arnaud Patard44607122009-04-21 17:39:08 +03004036 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004037 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4038 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004039 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004040 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004041 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004042 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004043 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004044 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004045 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004046 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4047 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004048 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4049 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4050 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4051 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4052 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004053 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004054}
ths3b46e622007-09-17 08:09:54 +00004055
bellard31e31b82003-02-18 22:55:36 +00004056static void host_to_target_termios (void *dst, const void *src)
4057{
4058 struct target_termios *target = dst;
4059 const struct host_termios *host = src;
4060
ths5fafdf22007-09-16 21:08:06 +00004061 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004062 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004063 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004064 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004065 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004066 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004067 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004068 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4069 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004070
Arnaud Patard44607122009-04-21 17:39:08 +03004071 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004072 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4073 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4074 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4075 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4076 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4077 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4078 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4079 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4080 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4081 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4082 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4083 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4084 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4085 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4086 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4087 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4088 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4089}
4090
blueswir18e853dc2008-10-05 10:49:32 +00004091static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004092 .convert = { host_to_target_termios, target_to_host_termios },
4093 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4094 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4095};
4096
bellard5286db72003-06-05 00:57:30 +00004097static bitmask_transtbl mmap_flags_tbl[] = {
4098 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4099 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4100 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4101 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4102 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4103 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4104 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4105 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004106 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4107 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004108 { 0, 0, 0, 0 }
4109};
4110
bellard2ab83ea2003-06-15 19:56:46 +00004111#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004112
4113/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004114static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004115
bellard03acab62007-11-11 14:57:14 +00004116static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004117{
4118 int size;
pbrook53a59602006-03-25 19:31:22 +00004119 void *p;
bellard6dbad632003-03-16 18:05:05 +00004120
4121 if (!ldt_table)
4122 return 0;
4123 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4124 if (size > bytecount)
4125 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004126 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4127 if (!p)
bellard03acab62007-11-11 14:57:14 +00004128 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004129 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004130 memcpy(p, ldt_table, size);
4131 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004132 return size;
4133}
4134
4135/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004136static abi_long write_ldt(CPUX86State *env,
4137 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004138{
4139 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004140 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004141 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004142 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004143 uint32_t *lp, entry_1, entry_2;
4144
4145 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004146 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004147 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004148 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004149 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004150 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004151 ldt_info.limit = tswap32(target_ldt_info->limit);
4152 ldt_info.flags = tswap32(target_ldt_info->flags);
4153 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004154
bellard6dbad632003-03-16 18:05:05 +00004155 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004156 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004157 seg_32bit = ldt_info.flags & 1;
4158 contents = (ldt_info.flags >> 1) & 3;
4159 read_exec_only = (ldt_info.flags >> 3) & 1;
4160 limit_in_pages = (ldt_info.flags >> 4) & 1;
4161 seg_not_present = (ldt_info.flags >> 5) & 1;
4162 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004163#ifdef TARGET_ABI32
4164 lm = 0;
4165#else
4166 lm = (ldt_info.flags >> 7) & 1;
4167#endif
bellard6dbad632003-03-16 18:05:05 +00004168 if (contents == 3) {
4169 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004170 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004171 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004172 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004173 }
4174 /* allocate the LDT */
4175 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004176 env->ldt.base = target_mmap(0,
4177 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4178 PROT_READ|PROT_WRITE,
4179 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4180 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004181 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004182 memset(g2h(env->ldt.base), 0,
4183 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004184 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004185 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004186 }
4187
4188 /* NOTE: same code as Linux kernel */
4189 /* Allow LDTs to be cleared by the user. */
4190 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4191 if (oldmode ||
4192 (contents == 0 &&
4193 read_exec_only == 1 &&
4194 seg_32bit == 0 &&
4195 limit_in_pages == 0 &&
4196 seg_not_present == 1 &&
4197 useable == 0 )) {
4198 entry_1 = 0;
4199 entry_2 = 0;
4200 goto install;
4201 }
4202 }
ths3b46e622007-09-17 08:09:54 +00004203
bellard6dbad632003-03-16 18:05:05 +00004204 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4205 (ldt_info.limit & 0x0ffff);
4206 entry_2 = (ldt_info.base_addr & 0xff000000) |
4207 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4208 (ldt_info.limit & 0xf0000) |
4209 ((read_exec_only ^ 1) << 9) |
4210 (contents << 10) |
4211 ((seg_not_present ^ 1) << 15) |
4212 (seg_32bit << 22) |
4213 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004214 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004215 0x7000;
4216 if (!oldmode)
4217 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004218
bellard6dbad632003-03-16 18:05:05 +00004219 /* Install the new entry ... */
4220install:
4221 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4222 lp[0] = tswap32(entry_1);
4223 lp[1] = tswap32(entry_2);
4224 return 0;
4225}
4226
4227/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004228static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4229 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004230{
bellard03acab62007-11-11 14:57:14 +00004231 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004232
bellard6dbad632003-03-16 18:05:05 +00004233 switch (func) {
4234 case 0:
4235 ret = read_ldt(ptr, bytecount);
4236 break;
4237 case 1:
4238 ret = write_ldt(env, ptr, bytecount, 1);
4239 break;
4240 case 0x11:
4241 ret = write_ldt(env, ptr, bytecount, 0);
4242 break;
bellard03acab62007-11-11 14:57:14 +00004243 default:
4244 ret = -TARGET_ENOSYS;
4245 break;
bellard6dbad632003-03-16 18:05:05 +00004246 }
4247 return ret;
4248}
bellard1b6b0292003-03-22 17:31:38 +00004249
blueswir14583f582008-08-24 10:35:55 +00004250#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004251abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004252{
4253 uint64_t *gdt_table = g2h(env->gdt.base);
4254 struct target_modify_ldt_ldt_s ldt_info;
4255 struct target_modify_ldt_ldt_s *target_ldt_info;
4256 int seg_32bit, contents, read_exec_only, limit_in_pages;
4257 int seg_not_present, useable, lm;
4258 uint32_t *lp, entry_1, entry_2;
4259 int i;
4260
4261 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4262 if (!target_ldt_info)
4263 return -TARGET_EFAULT;
4264 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004265 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004266 ldt_info.limit = tswap32(target_ldt_info->limit);
4267 ldt_info.flags = tswap32(target_ldt_info->flags);
4268 if (ldt_info.entry_number == -1) {
4269 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4270 if (gdt_table[i] == 0) {
4271 ldt_info.entry_number = i;
4272 target_ldt_info->entry_number = tswap32(i);
4273 break;
4274 }
4275 }
4276 }
4277 unlock_user_struct(target_ldt_info, ptr, 1);
4278
4279 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4280 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4281 return -TARGET_EINVAL;
4282 seg_32bit = ldt_info.flags & 1;
4283 contents = (ldt_info.flags >> 1) & 3;
4284 read_exec_only = (ldt_info.flags >> 3) & 1;
4285 limit_in_pages = (ldt_info.flags >> 4) & 1;
4286 seg_not_present = (ldt_info.flags >> 5) & 1;
4287 useable = (ldt_info.flags >> 6) & 1;
4288#ifdef TARGET_ABI32
4289 lm = 0;
4290#else
4291 lm = (ldt_info.flags >> 7) & 1;
4292#endif
4293
4294 if (contents == 3) {
4295 if (seg_not_present == 0)
4296 return -TARGET_EINVAL;
4297 }
4298
4299 /* NOTE: same code as Linux kernel */
4300 /* Allow LDTs to be cleared by the user. */
4301 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4302 if ((contents == 0 &&
4303 read_exec_only == 1 &&
4304 seg_32bit == 0 &&
4305 limit_in_pages == 0 &&
4306 seg_not_present == 1 &&
4307 useable == 0 )) {
4308 entry_1 = 0;
4309 entry_2 = 0;
4310 goto install;
4311 }
4312 }
4313
4314 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4315 (ldt_info.limit & 0x0ffff);
4316 entry_2 = (ldt_info.base_addr & 0xff000000) |
4317 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4318 (ldt_info.limit & 0xf0000) |
4319 ((read_exec_only ^ 1) << 9) |
4320 (contents << 10) |
4321 ((seg_not_present ^ 1) << 15) |
4322 (seg_32bit << 22) |
4323 (limit_in_pages << 23) |
4324 (useable << 20) |
4325 (lm << 21) |
4326 0x7000;
4327
4328 /* Install the new entry ... */
4329install:
4330 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4331 lp[0] = tswap32(entry_1);
4332 lp[1] = tswap32(entry_2);
4333 return 0;
4334}
4335
blueswir18fcd3692008-08-17 20:26:25 +00004336static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004337{
4338 struct target_modify_ldt_ldt_s *target_ldt_info;
4339 uint64_t *gdt_table = g2h(env->gdt.base);
4340 uint32_t base_addr, limit, flags;
4341 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4342 int seg_not_present, useable, lm;
4343 uint32_t *lp, entry_1, entry_2;
4344
4345 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4346 if (!target_ldt_info)
4347 return -TARGET_EFAULT;
4348 idx = tswap32(target_ldt_info->entry_number);
4349 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4350 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4351 unlock_user_struct(target_ldt_info, ptr, 1);
4352 return -TARGET_EINVAL;
4353 }
4354 lp = (uint32_t *)(gdt_table + idx);
4355 entry_1 = tswap32(lp[0]);
4356 entry_2 = tswap32(lp[1]);
4357
4358 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4359 contents = (entry_2 >> 10) & 3;
4360 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4361 seg_32bit = (entry_2 >> 22) & 1;
4362 limit_in_pages = (entry_2 >> 23) & 1;
4363 useable = (entry_2 >> 20) & 1;
4364#ifdef TARGET_ABI32
4365 lm = 0;
4366#else
4367 lm = (entry_2 >> 21) & 1;
4368#endif
4369 flags = (seg_32bit << 0) | (contents << 1) |
4370 (read_exec_only << 3) | (limit_in_pages << 4) |
4371 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4372 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4373 base_addr = (entry_1 >> 16) |
4374 (entry_2 & 0xff000000) |
4375 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004376 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004377 target_ldt_info->limit = tswap32(limit);
4378 target_ldt_info->flags = tswap32(flags);
4379 unlock_user_struct(target_ldt_info, ptr, 1);
4380 return 0;
4381}
blueswir14583f582008-08-24 10:35:55 +00004382#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004383
bellardd2fd1af2007-11-14 18:08:56 +00004384#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004385abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004386{
Juan Quintela1add8692011-06-16 17:37:09 +01004387 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004388 abi_ulong val;
4389 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004390
bellardd2fd1af2007-11-14 18:08:56 +00004391 switch(code) {
4392 case TARGET_ARCH_SET_GS:
4393 case TARGET_ARCH_SET_FS:
4394 if (code == TARGET_ARCH_SET_GS)
4395 idx = R_GS;
4396 else
4397 idx = R_FS;
4398 cpu_x86_load_seg(env, idx, 0);
4399 env->segs[idx].base = addr;
4400 break;
4401 case TARGET_ARCH_GET_GS:
4402 case TARGET_ARCH_GET_FS:
4403 if (code == TARGET_ARCH_GET_GS)
4404 idx = R_GS;
4405 else
4406 idx = R_FS;
4407 val = env->segs[idx].base;
4408 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004409 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004410 break;
4411 default:
4412 ret = -TARGET_EINVAL;
4413 break;
4414 }
Juan Quintela1add8692011-06-16 17:37:09 +01004415 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004416}
4417#endif
4418
bellard2ab83ea2003-06-15 19:56:46 +00004419#endif /* defined(TARGET_I386) */
4420
Riku Voipio05098a92011-03-04 15:27:29 +02004421#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004422
pbrookd865bab2008-06-07 22:12:17 +00004423
4424static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4425typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004426 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004427 pthread_mutex_t mutex;
4428 pthread_cond_t cond;
4429 pthread_t thread;
4430 uint32_t tid;
4431 abi_ulong child_tidptr;
4432 abi_ulong parent_tidptr;
4433 sigset_t sigmask;
4434} new_thread_info;
4435
4436static void *clone_func(void *arg)
4437{
4438 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004439 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004440 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004441 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004442
4443 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004444 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004445 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004446 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004447 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004448 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004449 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004450 if (info->child_tidptr)
4451 put_user_u32(info->tid, info->child_tidptr);
4452 if (info->parent_tidptr)
4453 put_user_u32(info->tid, info->parent_tidptr);
4454 /* Enable signals. */
4455 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4456 /* Signal to the parent that we're ready. */
4457 pthread_mutex_lock(&info->mutex);
4458 pthread_cond_broadcast(&info->cond);
4459 pthread_mutex_unlock(&info->mutex);
4460 /* Wait until the parent has finshed initializing the tls state. */
4461 pthread_mutex_lock(&clone_lock);
4462 pthread_mutex_unlock(&clone_lock);
4463 cpu_loop(env);
4464 /* never exits */
4465 return NULL;
4466}
bellard1b6b0292003-03-22 17:31:38 +00004467
ths0da46a62007-10-20 20:23:07 +00004468/* do_fork() Must return host values and target errnos (unlike most
4469 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004470static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004471 abi_ulong parent_tidptr, target_ulong newtls,
4472 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004473{
Andreas Färber0429a972013-08-26 18:14:44 +02004474 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004475 int ret;
bellard5cd43932003-03-29 16:54:36 +00004476 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004477 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004478 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004479 unsigned int nptl_flags;
4480 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004481
balrog436d1242008-09-21 02:39:45 +00004482 /* Emulate vfork() with fork() */
4483 if (flags & CLONE_VFORK)
4484 flags &= ~(CLONE_VFORK | CLONE_VM);
4485
bellard1b6b0292003-03-22 17:31:38 +00004486 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004487 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004488 new_thread_info info;
4489 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004490
Anthony Liguori7267c092011-08-20 22:09:37 -05004491 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004492 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004493 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004494 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004495 /* Init regs that differ from the parent. */
4496 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004497 new_cpu = ENV_GET_CPU(new_env);
4498 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004499 ts->bprm = parent_ts->bprm;
4500 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004501 nptl_flags = flags;
4502 flags &= ~CLONE_NPTL_FLAGS2;
4503
pbrookc2764712009-03-07 15:24:59 +00004504 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4505 ts->child_tidptr = child_tidptr;
4506 }
4507
pbrookd865bab2008-06-07 22:12:17 +00004508 if (nptl_flags & CLONE_SETTLS)
4509 cpu_set_tls (new_env, newtls);
4510
4511 /* Grab a mutex so that thread setup appears atomic. */
4512 pthread_mutex_lock(&clone_lock);
4513
4514 memset(&info, 0, sizeof(info));
4515 pthread_mutex_init(&info.mutex, NULL);
4516 pthread_mutex_lock(&info.mutex);
4517 pthread_cond_init(&info.cond, NULL);
4518 info.env = new_env;
4519 if (nptl_flags & CLONE_CHILD_SETTID)
4520 info.child_tidptr = child_tidptr;
4521 if (nptl_flags & CLONE_PARENT_SETTID)
4522 info.parent_tidptr = parent_tidptr;
4523
4524 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004525 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4526 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004527 /* It is not safe to deliver signals until the child has finished
4528 initializing, so temporarily block all signals. */
4529 sigfillset(&sigmask);
4530 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4531
4532 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004533 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004534
4535 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4536 pthread_attr_destroy(&attr);
4537 if (ret == 0) {
4538 /* Wait for the child to initialize. */
4539 pthread_cond_wait(&info.cond, &info.mutex);
4540 ret = info.tid;
4541 if (flags & CLONE_PARENT_SETTID)
4542 put_user_u32(ret, parent_tidptr);
4543 } else {
4544 ret = -1;
4545 }
4546 pthread_mutex_unlock(&info.mutex);
4547 pthread_cond_destroy(&info.cond);
4548 pthread_mutex_destroy(&info.mutex);
4549 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004550 } else {
4551 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004552 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004553 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004554 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004555 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004556 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004557 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004558 cpu_clone_regs(env, newsp);
4559 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004560 /* There is a race condition here. The parent process could
4561 theoretically read the TID in the child process before the child
4562 tid is set. This would require using either ptrace
4563 (not implemented) or having *_tidptr to point at a shared memory
4564 mapping. We can't repeat the spinlock hack used above because
4565 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004566 if (flags & CLONE_CHILD_SETTID)
4567 put_user_u32(gettid(), child_tidptr);
4568 if (flags & CLONE_PARENT_SETTID)
4569 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004570 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004571 if (flags & CLONE_SETTLS)
4572 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004573 if (flags & CLONE_CHILD_CLEARTID)
4574 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004575 } else {
4576 fork_end(0);
4577 }
bellard1b6b0292003-03-22 17:31:38 +00004578 }
4579 return ret;
4580}
4581
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004582/* warning : doesn't handle linux specific flags... */
4583static int target_to_host_fcntl_cmd(int cmd)
4584{
4585 switch(cmd) {
4586 case TARGET_F_DUPFD:
4587 case TARGET_F_GETFD:
4588 case TARGET_F_SETFD:
4589 case TARGET_F_GETFL:
4590 case TARGET_F_SETFL:
4591 return cmd;
4592 case TARGET_F_GETLK:
4593 return F_GETLK;
4594 case TARGET_F_SETLK:
4595 return F_SETLK;
4596 case TARGET_F_SETLKW:
4597 return F_SETLKW;
4598 case TARGET_F_GETOWN:
4599 return F_GETOWN;
4600 case TARGET_F_SETOWN:
4601 return F_SETOWN;
4602 case TARGET_F_GETSIG:
4603 return F_GETSIG;
4604 case TARGET_F_SETSIG:
4605 return F_SETSIG;
4606#if TARGET_ABI_BITS == 32
4607 case TARGET_F_GETLK64:
4608 return F_GETLK64;
4609 case TARGET_F_SETLK64:
4610 return F_SETLK64;
4611 case TARGET_F_SETLKW64:
4612 return F_SETLKW64;
4613#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004614 case TARGET_F_SETLEASE:
4615 return F_SETLEASE;
4616 case TARGET_F_GETLEASE:
4617 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004618#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004619 case TARGET_F_DUPFD_CLOEXEC:
4620 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004621#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004622 case TARGET_F_NOTIFY:
4623 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004624#ifdef F_GETOWN_EX
4625 case TARGET_F_GETOWN_EX:
4626 return F_GETOWN_EX;
4627#endif
4628#ifdef F_SETOWN_EX
4629 case TARGET_F_SETOWN_EX:
4630 return F_SETOWN_EX;
4631#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004632 default:
4633 return -TARGET_EINVAL;
4634 }
4635 return -TARGET_EINVAL;
4636}
4637
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004638#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4639static const bitmask_transtbl flock_tbl[] = {
4640 TRANSTBL_CONVERT(F_RDLCK),
4641 TRANSTBL_CONVERT(F_WRLCK),
4642 TRANSTBL_CONVERT(F_UNLCK),
4643 TRANSTBL_CONVERT(F_EXLCK),
4644 TRANSTBL_CONVERT(F_SHLCK),
4645 { 0, 0, 0, 0 }
4646};
4647
blueswir1992f48a2007-10-14 16:27:31 +00004648static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004649{
4650 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004651 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004652 struct flock64 fl64;
4653 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004654#ifdef F_GETOWN_EX
4655 struct f_owner_ex fox;
4656 struct target_f_owner_ex *target_fox;
4657#endif
blueswir1992f48a2007-10-14 16:27:31 +00004658 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004659 int host_cmd = target_to_host_fcntl_cmd(cmd);
4660
4661 if (host_cmd == -TARGET_EINVAL)
4662 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004663
bellard7775e9e2003-05-14 22:46:48 +00004664 switch(cmd) {
4665 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004666 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4667 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004668 fl.l_type =
4669 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004670 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004671 fl.l_start = tswapal(target_fl->l_start);
4672 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004673 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004674 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004675 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004676 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004677 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4678 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004679 target_fl->l_type =
4680 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004681 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004682 target_fl->l_start = tswapal(fl.l_start);
4683 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004684 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004685 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004686 }
4687 break;
ths3b46e622007-09-17 08:09:54 +00004688
bellard7775e9e2003-05-14 22:46:48 +00004689 case TARGET_F_SETLK:
4690 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004691 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4692 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004693 fl.l_type =
4694 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004695 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004696 fl.l_start = tswapal(target_fl->l_start);
4697 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004698 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004699 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004700 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004701 break;
ths3b46e622007-09-17 08:09:54 +00004702
bellard7775e9e2003-05-14 22:46:48 +00004703 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004704 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4705 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004706 fl64.l_type =
4707 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004708 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004709 fl64.l_start = tswap64(target_fl64->l_start);
4710 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004711 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004712 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004713 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004714 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004715 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4716 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004717 target_fl64->l_type =
4718 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004719 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004720 target_fl64->l_start = tswap64(fl64.l_start);
4721 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004722 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004723 unlock_user_struct(target_fl64, arg, 1);
4724 }
bellard9ee1fa22007-11-11 15:11:19 +00004725 break;
bellard7775e9e2003-05-14 22:46:48 +00004726 case TARGET_F_SETLK64:
4727 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004728 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4729 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004730 fl64.l_type =
4731 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004732 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004733 fl64.l_start = tswap64(target_fl64->l_start);
4734 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004735 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004736 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004737 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004738 break;
4739
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004740 case TARGET_F_GETFL:
4741 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004742 if (ret >= 0) {
4743 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4744 }
bellardffa65c32004-01-04 23:57:22 +00004745 break;
4746
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004747 case TARGET_F_SETFL:
4748 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4749 break;
4750
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004751#ifdef F_GETOWN_EX
4752 case TARGET_F_GETOWN_EX:
4753 ret = get_errno(fcntl(fd, host_cmd, &fox));
4754 if (ret >= 0) {
4755 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4756 return -TARGET_EFAULT;
4757 target_fox->type = tswap32(fox.type);
4758 target_fox->pid = tswap32(fox.pid);
4759 unlock_user_struct(target_fox, arg, 1);
4760 }
4761 break;
4762#endif
4763
4764#ifdef F_SETOWN_EX
4765 case TARGET_F_SETOWN_EX:
4766 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4767 return -TARGET_EFAULT;
4768 fox.type = tswap32(target_fox->type);
4769 fox.pid = tswap32(target_fox->pid);
4770 unlock_user_struct(target_fox, arg, 0);
4771 ret = get_errno(fcntl(fd, host_cmd, &fox));
4772 break;
4773#endif
4774
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004775 case TARGET_F_SETOWN:
4776 case TARGET_F_GETOWN:
4777 case TARGET_F_SETSIG:
4778 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004779 case TARGET_F_SETLEASE:
4780 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004781 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004782 break;
4783
bellard7775e9e2003-05-14 22:46:48 +00004784 default:
bellard9ee1fa22007-11-11 15:11:19 +00004785 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004786 break;
4787 }
4788 return ret;
4789}
4790
bellard67867302003-11-23 17:05:30 +00004791#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004792
bellard67867302003-11-23 17:05:30 +00004793static inline int high2lowuid(int uid)
4794{
4795 if (uid > 65535)
4796 return 65534;
4797 else
4798 return uid;
4799}
4800
4801static inline int high2lowgid(int gid)
4802{
4803 if (gid > 65535)
4804 return 65534;
4805 else
4806 return gid;
4807}
4808
4809static inline int low2highuid(int uid)
4810{
4811 if ((int16_t)uid == -1)
4812 return -1;
4813 else
4814 return uid;
4815}
4816
4817static inline int low2highgid(int gid)
4818{
4819 if ((int16_t)gid == -1)
4820 return -1;
4821 else
4822 return gid;
4823}
Riku Voipio0c866a72011-04-18 15:23:06 +03004824static inline int tswapid(int id)
4825{
4826 return tswap16(id);
4827}
Peter Maydell76ca3102014-03-02 19:36:41 +00004828
4829#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4830
Riku Voipio0c866a72011-04-18 15:23:06 +03004831#else /* !USE_UID16 */
4832static inline int high2lowuid(int uid)
4833{
4834 return uid;
4835}
4836static inline int high2lowgid(int gid)
4837{
4838 return gid;
4839}
4840static inline int low2highuid(int uid)
4841{
4842 return uid;
4843}
4844static inline int low2highgid(int gid)
4845{
4846 return gid;
4847}
4848static inline int tswapid(int id)
4849{
4850 return tswap32(id);
4851}
Peter Maydell76ca3102014-03-02 19:36:41 +00004852
4853#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4854
bellard67867302003-11-23 17:05:30 +00004855#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004856
bellard31e31b82003-02-18 22:55:36 +00004857void syscall_init(void)
4858{
bellard2ab83ea2003-06-15 19:56:46 +00004859 IOCTLEntry *ie;
4860 const argtype *arg_type;
4861 int size;
thsb92c47c2007-11-01 00:07:38 +00004862 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004863
Blue Swirl001faf32009-05-13 17:53:17 +00004864#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004865#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004866#include "syscall_types.h"
4867#undef STRUCT
4868#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004869
Peter Maydelldd6e9572012-07-23 08:07:22 +00004870 /* Build target_to_host_errno_table[] table from
4871 * host_to_target_errno_table[]. */
4872 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4873 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4874 }
4875
bellard2ab83ea2003-06-15 19:56:46 +00004876 /* we patch the ioctl size if necessary. We rely on the fact that
4877 no ioctl has all the bits at '1' in the size field */
4878 ie = ioctl_entries;
4879 while (ie->target_cmd != 0) {
4880 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4881 TARGET_IOC_SIZEMASK) {
4882 arg_type = ie->arg_type;
4883 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004884 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004885 ie->target_cmd);
4886 exit(1);
4887 }
4888 arg_type++;
4889 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004890 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004891 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4892 (size << TARGET_IOC_SIZESHIFT);
4893 }
thsb92c47c2007-11-01 00:07:38 +00004894
bellard2ab83ea2003-06-15 19:56:46 +00004895 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004896#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4897 (defined(__x86_64__) && defined(TARGET_X86_64))
4898 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4899 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4900 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004901 }
4902#endif
4903 ie++;
4904 }
bellard31e31b82003-02-18 22:55:36 +00004905}
bellardc573ff62004-01-04 15:51:36 +00004906
blueswir1992f48a2007-10-14 16:27:31 +00004907#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004908static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4909{
thsaf325d32008-06-10 15:29:15 +00004910#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004911 return ((uint64_t)word0 << 32) | word1;
4912#else
4913 return ((uint64_t)word1 << 32) | word0;
4914#endif
4915}
blueswir1992f48a2007-10-14 16:27:31 +00004916#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004917static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4918{
4919 return word0;
4920}
blueswir1992f48a2007-10-14 16:27:31 +00004921#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004922
4923#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004924static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4925 abi_long arg2,
4926 abi_long arg3,
4927 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004928{
Riku Voipio48e515d2011-07-12 15:40:51 +03004929 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004930 arg2 = arg3;
4931 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004932 }
pbrookce4defa2006-02-09 16:49:55 +00004933 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4934}
4935#endif
4936
4937#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004938static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4939 abi_long arg2,
4940 abi_long arg3,
4941 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004942{
Riku Voipio48e515d2011-07-12 15:40:51 +03004943 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004944 arg2 = arg3;
4945 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004946 }
pbrookce4defa2006-02-09 16:49:55 +00004947 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4948}
4949#endif
4950
bellard579a97f2007-11-11 14:26:47 +00004951static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4952 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004953{
4954 struct target_timespec *target_ts;
4955
bellard579a97f2007-11-11 14:26:47 +00004956 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4957 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004958 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4959 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004960 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004961 return 0;
pbrook53a59602006-03-25 19:31:22 +00004962}
4963
bellard579a97f2007-11-11 14:26:47 +00004964static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4965 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004966{
4967 struct target_timespec *target_ts;
4968
bellard579a97f2007-11-11 14:26:47 +00004969 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4970 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004971 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4972 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004973 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004974 return 0;
pbrook53a59602006-03-25 19:31:22 +00004975}
4976
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004977static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4978 abi_ulong target_addr)
4979{
4980 struct target_itimerspec *target_itspec;
4981
4982 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4983 return -TARGET_EFAULT;
4984 }
4985
4986 host_itspec->it_interval.tv_sec =
4987 tswapal(target_itspec->it_interval.tv_sec);
4988 host_itspec->it_interval.tv_nsec =
4989 tswapal(target_itspec->it_interval.tv_nsec);
4990 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4991 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4992
4993 unlock_user_struct(target_itspec, target_addr, 1);
4994 return 0;
4995}
4996
4997static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4998 struct itimerspec *host_its)
4999{
5000 struct target_itimerspec *target_itspec;
5001
5002 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5003 return -TARGET_EFAULT;
5004 }
5005
5006 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5007 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5008
5009 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5010 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5011
5012 unlock_user_struct(target_itspec, target_addr, 0);
5013 return 0;
5014}
5015
Peter Maydellc0659762014-08-09 15:42:32 +01005016static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5017 abi_ulong target_addr)
5018{
5019 struct target_sigevent *target_sevp;
5020
5021 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5022 return -TARGET_EFAULT;
5023 }
5024
5025 /* This union is awkward on 64 bit systems because it has a 32 bit
5026 * integer and a pointer in it; we follow the conversion approach
5027 * used for handling sigval types in signal.c so the guest should get
5028 * the correct value back even if we did a 64 bit byteswap and it's
5029 * using the 32 bit integer.
5030 */
5031 host_sevp->sigev_value.sival_ptr =
5032 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5033 host_sevp->sigev_signo =
5034 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5035 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5036 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5037
5038 unlock_user_struct(target_sevp, target_addr, 1);
5039 return 0;
5040}
5041
Tom Musta6f6a4032014-08-12 13:53:42 -05005042#if defined(TARGET_NR_mlockall)
5043static inline int target_to_host_mlockall_arg(int arg)
5044{
5045 int result = 0;
5046
5047 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5048 result |= MCL_CURRENT;
5049 }
5050 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5051 result |= MCL_FUTURE;
5052 }
5053 return result;
5054}
5055#endif
5056
aurel329d33b762009-04-08 23:07:05 +00005057#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00005058static inline abi_long host_to_target_stat64(void *cpu_env,
5059 abi_ulong target_addr,
5060 struct stat *host_st)
5061{
Alexander Graf09701192013-09-03 20:12:15 +01005062#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005063 if (((CPUARMState *)cpu_env)->eabi) {
5064 struct target_eabi_stat64 *target_st;
5065
5066 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5067 return -TARGET_EFAULT;
5068 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5069 __put_user(host_st->st_dev, &target_st->st_dev);
5070 __put_user(host_st->st_ino, &target_st->st_ino);
5071#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5072 __put_user(host_st->st_ino, &target_st->__st_ino);
5073#endif
5074 __put_user(host_st->st_mode, &target_st->st_mode);
5075 __put_user(host_st->st_nlink, &target_st->st_nlink);
5076 __put_user(host_st->st_uid, &target_st->st_uid);
5077 __put_user(host_st->st_gid, &target_st->st_gid);
5078 __put_user(host_st->st_rdev, &target_st->st_rdev);
5079 __put_user(host_st->st_size, &target_st->st_size);
5080 __put_user(host_st->st_blksize, &target_st->st_blksize);
5081 __put_user(host_st->st_blocks, &target_st->st_blocks);
5082 __put_user(host_st->st_atime, &target_st->target_st_atime);
5083 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5084 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5085 unlock_user_struct(target_st, target_addr, 1);
5086 } else
5087#endif
5088 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005089#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005090 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005091#else
5092 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005093#endif
balrog6a24a772008-09-20 02:23:36 +00005094
5095 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5096 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005097 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005098 __put_user(host_st->st_dev, &target_st->st_dev);
5099 __put_user(host_st->st_ino, &target_st->st_ino);
5100#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5101 __put_user(host_st->st_ino, &target_st->__st_ino);
5102#endif
5103 __put_user(host_st->st_mode, &target_st->st_mode);
5104 __put_user(host_st->st_nlink, &target_st->st_nlink);
5105 __put_user(host_st->st_uid, &target_st->st_uid);
5106 __put_user(host_st->st_gid, &target_st->st_gid);
5107 __put_user(host_st->st_rdev, &target_st->st_rdev);
5108 /* XXX: better use of kernel struct */
5109 __put_user(host_st->st_size, &target_st->st_size);
5110 __put_user(host_st->st_blksize, &target_st->st_blksize);
5111 __put_user(host_st->st_blocks, &target_st->st_blocks);
5112 __put_user(host_st->st_atime, &target_st->target_st_atime);
5113 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5114 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5115 unlock_user_struct(target_st, target_addr, 1);
5116 }
5117
5118 return 0;
5119}
5120#endif
5121
pbrookbd0c5662008-05-29 14:34:11 +00005122/* ??? Using host futex calls even when target atomic operations
5123 are not really atomic probably breaks things. However implementing
5124 futexes locally would make futexes shared between multiple processes
5125 tricky. However they're probably useless because guest atomic
5126 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005127static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5128 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005129{
5130 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005131 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005132
5133 /* ??? We assume FUTEX_* constants are the same on both host
5134 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005135#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005136 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005137#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005138 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005139#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005140 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005141 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005142 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005143 if (timeout) {
5144 pts = &ts;
5145 target_to_host_timespec(pts, timeout);
5146 } else {
5147 pts = NULL;
5148 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005149 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005150 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005151 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005152 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005153 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005154 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005155 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005156 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005157 case FUTEX_WAKE_OP:
5158 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5159 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5160 But the prototype takes a `struct timespec *'; insert casts
5161 to satisfy the compiler. We do not need to tswap TIMEOUT
5162 since it's not compared to guest memory. */
5163 pts = (struct timespec *)(uintptr_t) timeout;
5164 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5165 g2h(uaddr2),
5166 (base_op == FUTEX_CMP_REQUEUE
5167 ? tswap32(val3)
5168 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005169 default:
5170 return -TARGET_ENOSYS;
5171 }
5172}
pbrookbd0c5662008-05-29 14:34:11 +00005173
pbrook1d9d8b52009-04-16 15:17:02 +00005174/* Map host to target signal numbers for the wait family of syscalls.
5175 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005176int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005177{
5178 if (WIFSIGNALED(status)) {
5179 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5180 }
5181 if (WIFSTOPPED(status)) {
5182 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5183 | (status & 0xff);
5184 }
5185 return status;
5186}
5187
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005188static int open_self_cmdline(void *cpu_env, int fd)
5189{
5190 int fd_orig = -1;
5191 bool word_skipped = false;
5192
5193 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5194 if (fd_orig < 0) {
5195 return fd_orig;
5196 }
5197
5198 while (true) {
5199 ssize_t nb_read;
5200 char buf[128];
5201 char *cp_buf = buf;
5202
5203 nb_read = read(fd_orig, buf, sizeof(buf));
5204 if (nb_read < 0) {
5205 fd_orig = close(fd_orig);
5206 return -1;
5207 } else if (nb_read == 0) {
5208 break;
5209 }
5210
5211 if (!word_skipped) {
5212 /* Skip the first string, which is the path to qemu-*-static
5213 instead of the actual command. */
5214 cp_buf = memchr(buf, 0, sizeof(buf));
5215 if (cp_buf) {
5216 /* Null byte found, skip one string */
5217 cp_buf++;
5218 nb_read -= cp_buf - buf;
5219 word_skipped = true;
5220 }
5221 }
5222
5223 if (word_skipped) {
5224 if (write(fd, cp_buf, nb_read) != nb_read) {
zhanghailiang680dfde2014-08-22 16:23:51 +08005225 close(fd_orig);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005226 return -1;
5227 }
5228 }
5229 }
5230
5231 return close(fd_orig);
5232}
5233
Alexander Graf36c08d42011-11-02 20:23:24 +01005234static int open_self_maps(void *cpu_env, int fd)
5235{
Andreas Färber0429a972013-08-26 18:14:44 +02005236 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5237 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005238 FILE *fp;
5239 char *line = NULL;
5240 size_t len = 0;
5241 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005242
Alexander Graf1a49ef22012-05-01 16:30:28 +01005243 fp = fopen("/proc/self/maps", "r");
5244 if (fp == NULL) {
5245 return -EACCES;
5246 }
5247
5248 while ((read = getline(&line, &len, fp)) != -1) {
5249 int fields, dev_maj, dev_min, inode;
5250 uint64_t min, max, offset;
5251 char flag_r, flag_w, flag_x, flag_p;
5252 char path[512] = "";
5253 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5254 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5255 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5256
5257 if ((fields < 10) || (fields > 11)) {
5258 continue;
5259 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005260 if (h2g_valid(min)) {
5261 int flags = page_get_flags(h2g(min));
5262 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5263 if (page_check_range(h2g(min), max - min, flags) == -1) {
5264 continue;
5265 }
5266 if (h2g(min) == ts->info->stack_limit) {
5267 pstrcpy(path, sizeof(path), " [stack]");
5268 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005269 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005270 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005271 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005272 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005273 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005274 }
5275 }
5276
5277 free(line);
5278 fclose(fp);
5279
Alexander Graf36c08d42011-11-02 20:23:24 +01005280 return 0;
5281}
5282
Alexander Graf480b8e72011-11-02 20:23:25 +01005283static int open_self_stat(void *cpu_env, int fd)
5284{
Andreas Färber0429a972013-08-26 18:14:44 +02005285 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5286 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005287 abi_ulong start_stack = ts->info->start_stack;
5288 int i;
5289
5290 for (i = 0; i < 44; i++) {
5291 char buf[128];
5292 int len;
5293 uint64_t val = 0;
5294
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005295 if (i == 0) {
5296 /* pid */
5297 val = getpid();
5298 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5299 } else if (i == 1) {
5300 /* app name */
5301 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5302 } else if (i == 27) {
5303 /* stack bottom */
5304 val = start_stack;
5305 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5306 } else {
5307 /* for the rest, there is MasterCard */
5308 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005309 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005310
Alexander Graf480b8e72011-11-02 20:23:25 +01005311 len = strlen(buf);
5312 if (write(fd, buf, len) != len) {
5313 return -1;
5314 }
5315 }
5316
5317 return 0;
5318}
5319
Alexander Graf257450e2011-11-02 20:23:26 +01005320static int open_self_auxv(void *cpu_env, int fd)
5321{
Andreas Färber0429a972013-08-26 18:14:44 +02005322 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5323 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005324 abi_ulong auxv = ts->info->saved_auxv;
5325 abi_ulong len = ts->info->auxv_len;
5326 char *ptr;
5327
5328 /*
5329 * Auxiliary vector is stored in target process stack.
5330 * read in whole auxv vector and copy it to file
5331 */
5332 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5333 if (ptr != NULL) {
5334 while (len > 0) {
5335 ssize_t r;
5336 r = write(fd, ptr, len);
5337 if (r <= 0) {
5338 break;
5339 }
5340 len -= r;
5341 ptr += r;
5342 }
5343 lseek(fd, 0, SEEK_SET);
5344 unlock_user(ptr, auxv, len);
5345 }
5346
5347 return 0;
5348}
5349
Andreas Schwab463d8e72013-07-02 14:04:12 +01005350static int is_proc_myself(const char *filename, const char *entry)
5351{
5352 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5353 filename += strlen("/proc/");
5354 if (!strncmp(filename, "self/", strlen("self/"))) {
5355 filename += strlen("self/");
5356 } else if (*filename >= '1' && *filename <= '9') {
5357 char myself[80];
5358 snprintf(myself, sizeof(myself), "%d/", getpid());
5359 if (!strncmp(filename, myself, strlen(myself))) {
5360 filename += strlen(myself);
5361 } else {
5362 return 0;
5363 }
5364 } else {
5365 return 0;
5366 }
5367 if (!strcmp(filename, entry)) {
5368 return 1;
5369 }
5370 }
5371 return 0;
5372}
5373
Laurent Vivierde6b9932013-08-30 01:46:40 +02005374#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5375static int is_proc(const char *filename, const char *entry)
5376{
5377 return strcmp(filename, entry) == 0;
5378}
5379
5380static int open_net_route(void *cpu_env, int fd)
5381{
5382 FILE *fp;
5383 char *line = NULL;
5384 size_t len = 0;
5385 ssize_t read;
5386
5387 fp = fopen("/proc/net/route", "r");
5388 if (fp == NULL) {
5389 return -EACCES;
5390 }
5391
5392 /* read header */
5393
5394 read = getline(&line, &len, fp);
5395 dprintf(fd, "%s", line);
5396
5397 /* read routes */
5398
5399 while ((read = getline(&line, &len, fp)) != -1) {
5400 char iface[16];
5401 uint32_t dest, gw, mask;
5402 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5403 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5404 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5405 &mask, &mtu, &window, &irtt);
5406 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5407 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5408 metric, tswap32(mask), mtu, window, irtt);
5409 }
5410
5411 free(line);
5412 fclose(fp);
5413
5414 return 0;
5415}
5416#endif
5417
Riku Voipio0b2effd2014-08-06 10:36:37 +03005418static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005419{
5420 struct fake_open {
5421 const char *filename;
5422 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005423 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005424 };
5425 const struct fake_open *fake_open;
5426 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005427 { "maps", open_self_maps, is_proc_myself },
5428 { "stat", open_self_stat, is_proc_myself },
5429 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005430 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005431#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5432 { "/proc/net/route", open_net_route, is_proc },
5433#endif
5434 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005435 };
5436
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005437 if (is_proc_myself(pathname, "exe")) {
5438 int execfd = qemu_getauxval(AT_EXECFD);
Riku Voipio0b2effd2014-08-06 10:36:37 +03005439 return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005440 }
5441
Alexander Graf3be14d02011-11-02 20:23:23 +01005442 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005443 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005444 break;
5445 }
5446 }
5447
5448 if (fake_open->filename) {
5449 const char *tmpdir;
5450 char filename[PATH_MAX];
5451 int fd, r;
5452
5453 /* create temporary file to map stat to */
5454 tmpdir = getenv("TMPDIR");
5455 if (!tmpdir)
5456 tmpdir = "/tmp";
5457 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5458 fd = mkstemp(filename);
5459 if (fd < 0) {
5460 return fd;
5461 }
5462 unlink(filename);
5463
5464 if ((r = fake_open->fill(cpu_env, fd))) {
5465 close(fd);
5466 return r;
5467 }
5468 lseek(fd, 0, SEEK_SET);
5469
5470 return fd;
5471 }
5472
Riku Voipio0b2effd2014-08-06 10:36:37 +03005473 return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
Alexander Graf3be14d02011-11-02 20:23:23 +01005474}
5475
ths0da46a62007-10-20 20:23:07 +00005476/* do_syscall() should always have a single exit point at the end so
5477 that actions, such as logging of syscall results, can be performed.
5478 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005479abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5480 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005481 abi_long arg5, abi_long arg6, abi_long arg7,
5482 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005483{
Andreas Färber182735e2013-05-29 22:29:20 +02005484 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005485 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005486 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005487 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005488 void *p;
ths3b46e622007-09-17 08:09:54 +00005489
bellard72f03902003-02-18 23:33:18 +00005490#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005491 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005492#endif
thsb92c47c2007-11-01 00:07:38 +00005493 if(do_strace)
5494 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5495
bellard31e31b82003-02-18 22:55:36 +00005496 switch(num) {
5497 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005498 /* In old applications this may be used to implement _exit(2).
5499 However in threaded applictions it is used for thread termination,
5500 and _exit_group is used for application termination.
5501 Do thread termination if we have more then one thread. */
5502 /* FIXME: This probably breaks if a signal arrives. We should probably
5503 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005504 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005505 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005506
Andreas Färber9b056fc2013-06-24 23:53:10 +02005507 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005508 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005509 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005510 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005511 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005512 if (ts->child_tidptr) {
5513 put_user_u32(0, ts->child_tidptr);
5514 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5515 NULL, NULL, 0);
5516 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005517 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005518 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005519 g_free(ts);
5520 pthread_exit(NULL);
5521 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005522#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005523 _mcleanup();
5524#endif
bellarde9009672005-04-26 20:42:36 +00005525 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005526 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005527 ret = 0; /* avoid warning */
5528 break;
5529 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005530 if (arg3 == 0)
5531 ret = 0;
5532 else {
5533 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5534 goto efault;
5535 ret = get_errno(read(arg1, p, arg3));
5536 unlock_user(p, arg2, ret);
5537 }
bellard31e31b82003-02-18 22:55:36 +00005538 break;
5539 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005540 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5541 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005542 ret = get_errno(write(arg1, p, arg3));
5543 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005544 break;
5545 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005546 if (!(p = lock_user_string(arg1)))
5547 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005548 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
5549 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5550 arg3));
pbrook53a59602006-03-25 19:31:22 +00005551 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005552 break;
ths82424832007-09-24 09:21:55 +00005553 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005554 if (!(p = lock_user_string(arg2)))
5555 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005556 ret = get_errno(do_openat(cpu_env, arg1, p,
5557 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5558 arg4));
bellard579a97f2007-11-11 14:26:47 +00005559 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005560 break;
bellard31e31b82003-02-18 22:55:36 +00005561 case TARGET_NR_close:
5562 ret = get_errno(close(arg1));
5563 break;
5564 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005565 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005566 break;
5567 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005568 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005569 break;
thse5febef2007-04-01 18:31:35 +00005570#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005571 case TARGET_NR_waitpid:
5572 {
pbrook53a59602006-03-25 19:31:22 +00005573 int status;
5574 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005575 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005576 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005577 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005578 }
5579 break;
thse5febef2007-04-01 18:31:35 +00005580#endif
pbrookf0cbb612008-05-30 18:20:05 +00005581#ifdef TARGET_NR_waitid
5582 case TARGET_NR_waitid:
5583 {
5584 siginfo_t info;
5585 info.si_pid = 0;
5586 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5587 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005588 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005589 goto efault;
5590 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005591 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005592 }
5593 }
5594 break;
5595#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005596#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005597 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005598 if (!(p = lock_user_string(arg1)))
5599 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005600 ret = get_errno(creat(p, arg2));
5601 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005602 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005603#endif
bellard31e31b82003-02-18 22:55:36 +00005604 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005605 {
5606 void * p2;
5607 p = lock_user_string(arg1);
5608 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005609 if (!p || !p2)
5610 ret = -TARGET_EFAULT;
5611 else
5612 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005613 unlock_user(p2, arg2, 0);
5614 unlock_user(p, arg1, 0);
5615 }
bellard31e31b82003-02-18 22:55:36 +00005616 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005617#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005618 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005619 {
5620 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005621 if (!arg2 || !arg4)
5622 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005623 p = lock_user_string(arg2);
5624 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005625 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005626 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005627 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005628 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005629 unlock_user(p, arg2, 0);
5630 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005631 }
5632 break;
5633#endif
bellard31e31b82003-02-18 22:55:36 +00005634 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005635 if (!(p = lock_user_string(arg1)))
5636 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005637 ret = get_errno(unlink(p));
5638 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005639 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005640#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005641 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005642 if (!(p = lock_user_string(arg2)))
5643 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005644 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005645 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005646 break;
balrogb7d35e62007-12-12 00:40:24 +00005647#endif
bellard31e31b82003-02-18 22:55:36 +00005648 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005649 {
5650 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005651 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005652 abi_ulong gp;
5653 abi_ulong guest_argp;
5654 abi_ulong guest_envp;
5655 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005656 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005657 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005658
bellardf7341ff2003-03-30 21:00:25 +00005659 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005660 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005661 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005662 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005663 goto efault;
ths03aa1972007-12-02 06:28:08 +00005664 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005665 break;
bellard7854b052003-03-29 17:22:23 +00005666 argc++;
bellard2f619692007-11-16 10:46:05 +00005667 }
bellardf7341ff2003-03-30 21:00:25 +00005668 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005669 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005670 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005671 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005672 goto efault;
ths03aa1972007-12-02 06:28:08 +00005673 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005674 break;
bellard7854b052003-03-29 17:22:23 +00005675 envc++;
bellard2f619692007-11-16 10:46:05 +00005676 }
bellard7854b052003-03-29 17:22:23 +00005677
bellardf7341ff2003-03-30 21:00:25 +00005678 argp = alloca((argc + 1) * sizeof(void *));
5679 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005680
pbrookda94d262008-05-30 18:24:00 +00005681 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005682 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005683 if (get_user_ual(addr, gp))
5684 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005685 if (!addr)
5686 break;
bellard2f619692007-11-16 10:46:05 +00005687 if (!(*q = lock_user_string(addr)))
5688 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005689 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005690 }
bellardf7341ff2003-03-30 21:00:25 +00005691 *q = NULL;
5692
pbrookda94d262008-05-30 18:24:00 +00005693 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005694 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005695 if (get_user_ual(addr, gp))
5696 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005697 if (!addr)
5698 break;
bellard2f619692007-11-16 10:46:05 +00005699 if (!(*q = lock_user_string(addr)))
5700 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005701 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005702 }
bellardf7341ff2003-03-30 21:00:25 +00005703 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005704
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005705 /* This case will not be caught by the host's execve() if its
5706 page size is bigger than the target's. */
5707 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5708 ret = -TARGET_E2BIG;
5709 goto execve_end;
5710 }
bellard2f619692007-11-16 10:46:05 +00005711 if (!(p = lock_user_string(arg1)))
5712 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005713 ret = get_errno(execve(p, argp, envp));
5714 unlock_user(p, arg1, 0);
5715
bellard2f619692007-11-16 10:46:05 +00005716 goto execve_end;
5717
5718 execve_efault:
5719 ret = -TARGET_EFAULT;
5720
5721 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005722 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005723 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005724 if (get_user_ual(addr, gp)
5725 || !addr)
5726 break;
pbrook53a59602006-03-25 19:31:22 +00005727 unlock_user(*q, addr, 0);
5728 }
5729 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005730 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005731 if (get_user_ual(addr, gp)
5732 || !addr)
5733 break;
pbrook53a59602006-03-25 19:31:22 +00005734 unlock_user(*q, addr, 0);
5735 }
bellard7854b052003-03-29 17:22:23 +00005736 }
bellard31e31b82003-02-18 22:55:36 +00005737 break;
5738 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005739 if (!(p = lock_user_string(arg1)))
5740 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005741 ret = get_errno(chdir(p));
5742 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005743 break;
bellarda315a142005-01-30 22:59:18 +00005744#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005745 case TARGET_NR_time:
5746 {
pbrook53a59602006-03-25 19:31:22 +00005747 time_t host_time;
5748 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005749 if (!is_error(ret)
5750 && arg1
5751 && put_user_sal(host_time, arg1))
5752 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005753 }
5754 break;
bellarda315a142005-01-30 22:59:18 +00005755#endif
bellard31e31b82003-02-18 22:55:36 +00005756 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005757 if (!(p = lock_user_string(arg1)))
5758 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005759 ret = get_errno(mknod(p, arg2, arg3));
5760 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005761 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005762#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005763 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005764 if (!(p = lock_user_string(arg2)))
5765 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005766 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005767 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005768 break;
5769#endif
bellard31e31b82003-02-18 22:55:36 +00005770 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005771 if (!(p = lock_user_string(arg1)))
5772 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005773 ret = get_errno(chmod(p, arg2));
5774 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005775 break;
bellardebc05482003-09-30 21:08:41 +00005776#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005777 case TARGET_NR_break:
5778 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005779#endif
5780#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005781 case TARGET_NR_oldstat:
5782 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005783#endif
bellard31e31b82003-02-18 22:55:36 +00005784 case TARGET_NR_lseek:
5785 ret = get_errno(lseek(arg1, arg2, arg3));
5786 break;
Richard Henderson92317332010-05-03 10:07:53 -07005787#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5788 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005789 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005790 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005791 ret = get_errno(getpid());
5792 break;
Richard Henderson92317332010-05-03 10:07:53 -07005793#endif
5794#ifdef TARGET_NR_getpid
5795 case TARGET_NR_getpid:
5796 ret = get_errno(getpid());
5797 break;
5798#endif
bellard31e31b82003-02-18 22:55:36 +00005799 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01005800 {
5801 /* need to look at the data field */
5802 void *p2, *p3;
5803
5804 if (arg1) {
5805 p = lock_user_string(arg1);
5806 if (!p) {
5807 goto efault;
5808 }
5809 } else {
5810 p = NULL;
5811 }
5812
5813 p2 = lock_user_string(arg2);
5814 if (!p2) {
5815 if (arg1) {
5816 unlock_user(p, arg1, 0);
5817 }
5818 goto efault;
5819 }
5820
5821 if (arg3) {
5822 p3 = lock_user_string(arg3);
5823 if (!p3) {
5824 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005825 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01005826 }
5827 unlock_user(p2, arg2, 0);
5828 goto efault;
5829 }
5830 } else {
5831 p3 = NULL;
5832 }
5833
5834 /* FIXME - arg5 should be locked, but it isn't clear how to
5835 * do that since it's not guaranteed to be a NULL-terminated
5836 * string.
5837 */
5838 if (!arg5) {
5839 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
5840 } else {
5841 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
5842 }
5843 ret = get_errno(ret);
5844
5845 if (arg1) {
5846 unlock_user(p, arg1, 0);
5847 }
5848 unlock_user(p2, arg2, 0);
5849 if (arg3) {
5850 unlock_user(p3, arg3, 0);
5851 }
5852 }
5853 break;
thse5febef2007-04-01 18:31:35 +00005854#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005855 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005856 if (!(p = lock_user_string(arg1)))
5857 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005858 ret = get_errno(umount(p));
5859 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005860 break;
thse5febef2007-04-01 18:31:35 +00005861#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005862#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005863 case TARGET_NR_stime:
5864 {
pbrook53a59602006-03-25 19:31:22 +00005865 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005866 if (get_user_sal(host_time, arg1))
5867 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005868 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005869 }
5870 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005871#endif
bellard31e31b82003-02-18 22:55:36 +00005872 case TARGET_NR_ptrace:
5873 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005874#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005875 case TARGET_NR_alarm:
5876 ret = alarm(arg1);
5877 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005878#endif
bellardebc05482003-09-30 21:08:41 +00005879#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005880 case TARGET_NR_oldfstat:
5881 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005882#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005883#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005884 case TARGET_NR_pause:
5885 ret = get_errno(pause());
5886 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005887#endif
thse5febef2007-04-01 18:31:35 +00005888#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005889 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005890 {
pbrook53a59602006-03-25 19:31:22 +00005891 struct utimbuf tbuf, *host_tbuf;
5892 struct target_utimbuf *target_tbuf;
5893 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005894 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5895 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005896 tbuf.actime = tswapal(target_tbuf->actime);
5897 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005898 unlock_user_struct(target_tbuf, arg2, 0);
5899 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005900 } else {
pbrook53a59602006-03-25 19:31:22 +00005901 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005902 }
bellard579a97f2007-11-11 14:26:47 +00005903 if (!(p = lock_user_string(arg1)))
5904 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005905 ret = get_errno(utime(p, host_tbuf));
5906 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005907 }
5908 break;
thse5febef2007-04-01 18:31:35 +00005909#endif
bellard978a66f2004-12-06 22:58:05 +00005910 case TARGET_NR_utimes:
5911 {
bellard978a66f2004-12-06 22:58:05 +00005912 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005913 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005914 if (copy_from_user_timeval(&tv[0], arg2)
5915 || copy_from_user_timeval(&tv[1],
5916 arg2 + sizeof(struct target_timeval)))
5917 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005918 tvp = tv;
5919 } else {
5920 tvp = NULL;
5921 }
bellard579a97f2007-11-11 14:26:47 +00005922 if (!(p = lock_user_string(arg1)))
5923 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005924 ret = get_errno(utimes(p, tvp));
5925 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005926 }
5927 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005928#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005929 case TARGET_NR_futimesat:
5930 {
5931 struct timeval *tvp, tv[2];
5932 if (arg3) {
5933 if (copy_from_user_timeval(&tv[0], arg3)
5934 || copy_from_user_timeval(&tv[1],
5935 arg3 + sizeof(struct target_timeval)))
5936 goto efault;
5937 tvp = tv;
5938 } else {
5939 tvp = NULL;
5940 }
5941 if (!(p = lock_user_string(arg2)))
5942 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005943 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005944 unlock_user(p, arg2, 0);
5945 }
5946 break;
5947#endif
bellardebc05482003-09-30 21:08:41 +00005948#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005949 case TARGET_NR_stty:
5950 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005951#endif
5952#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005953 case TARGET_NR_gtty:
5954 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005955#endif
bellard31e31b82003-02-18 22:55:36 +00005956 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005957 if (!(p = lock_user_string(arg1)))
5958 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005959 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005960 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005961 break;
ths92a34c12007-09-24 09:27:49 +00005962#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5963 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005964 if (!(p = lock_user_string(arg2)))
5965 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005966 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005967 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005968 break;
5969#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005970#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005971 case TARGET_NR_nice:
5972 ret = get_errno(nice(arg1));
5973 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005974#endif
bellardebc05482003-09-30 21:08:41 +00005975#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005976 case TARGET_NR_ftime:
5977 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005978#endif
bellard31e31b82003-02-18 22:55:36 +00005979 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005980 sync();
5981 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005982 break;
5983 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005984 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005985 break;
5986 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005987 {
5988 void *p2;
5989 p = lock_user_string(arg1);
5990 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005991 if (!p || !p2)
5992 ret = -TARGET_EFAULT;
5993 else
5994 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005995 unlock_user(p2, arg2, 0);
5996 unlock_user(p, arg1, 0);
5997 }
bellard31e31b82003-02-18 22:55:36 +00005998 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005999#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006000 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006001 {
bellard579a97f2007-11-11 14:26:47 +00006002 void *p2;
ths722183f2007-09-24 09:24:37 +00006003 p = lock_user_string(arg2);
6004 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006005 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006006 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006007 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006008 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006009 unlock_user(p2, arg4, 0);
6010 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006011 }
6012 break;
6013#endif
bellard31e31b82003-02-18 22:55:36 +00006014 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006015 if (!(p = lock_user_string(arg1)))
6016 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006017 ret = get_errno(mkdir(p, arg2));
6018 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006019 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006020#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006021 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006022 if (!(p = lock_user_string(arg2)))
6023 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006024 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006025 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006026 break;
6027#endif
bellard31e31b82003-02-18 22:55:36 +00006028 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006029 if (!(p = lock_user_string(arg1)))
6030 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006031 ret = get_errno(rmdir(p));
6032 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006033 break;
6034 case TARGET_NR_dup:
6035 ret = get_errno(dup(arg1));
6036 break;
6037 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006038 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006039 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03006040#ifdef TARGET_NR_pipe2
6041 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006042 ret = do_pipe(cpu_env, arg1,
6043 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006044 break;
6045#endif
bellard31e31b82003-02-18 22:55:36 +00006046 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006047 {
pbrook53a59602006-03-25 19:31:22 +00006048 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006049 struct tms tms;
6050 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006051 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006052 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6053 if (!tmsp)
6054 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006055 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6056 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6057 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6058 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006059 }
bellardc596ed12003-07-13 17:32:31 +00006060 if (!is_error(ret))
6061 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006062 }
6063 break;
bellardebc05482003-09-30 21:08:41 +00006064#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006065 case TARGET_NR_prof:
6066 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006067#endif
thse5febef2007-04-01 18:31:35 +00006068#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006069 case TARGET_NR_signal:
6070 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006071#endif
bellard31e31b82003-02-18 22:55:36 +00006072 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006073 if (arg1 == 0) {
6074 ret = get_errno(acct(NULL));
6075 } else {
6076 if (!(p = lock_user_string(arg1)))
6077 goto efault;
6078 ret = get_errno(acct(path(p)));
6079 unlock_user(p, arg1, 0);
6080 }
pbrook24836682006-04-16 14:14:53 +00006081 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006082#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006083 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006084 if (!(p = lock_user_string(arg1)))
6085 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006086 ret = get_errno(umount2(p, arg2));
6087 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006088 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006089#endif
bellardebc05482003-09-30 21:08:41 +00006090#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006091 case TARGET_NR_lock:
6092 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006093#endif
bellard31e31b82003-02-18 22:55:36 +00006094 case TARGET_NR_ioctl:
6095 ret = do_ioctl(arg1, arg2, arg3);
6096 break;
6097 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006098 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006099 break;
bellardebc05482003-09-30 21:08:41 +00006100#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006101 case TARGET_NR_mpx:
6102 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006103#endif
bellard31e31b82003-02-18 22:55:36 +00006104 case TARGET_NR_setpgid:
6105 ret = get_errno(setpgid(arg1, arg2));
6106 break;
bellardebc05482003-09-30 21:08:41 +00006107#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006108 case TARGET_NR_ulimit:
6109 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006110#endif
6111#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006112 case TARGET_NR_oldolduname:
6113 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006114#endif
bellard31e31b82003-02-18 22:55:36 +00006115 case TARGET_NR_umask:
6116 ret = get_errno(umask(arg1));
6117 break;
6118 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006119 if (!(p = lock_user_string(arg1)))
6120 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006121 ret = get_errno(chroot(p));
6122 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006123 break;
6124 case TARGET_NR_ustat:
6125 goto unimplemented;
6126 case TARGET_NR_dup2:
6127 ret = get_errno(dup2(arg1, arg2));
6128 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03006129#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6130 case TARGET_NR_dup3:
6131 ret = get_errno(dup3(arg1, arg2, arg3));
6132 break;
6133#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006134#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006135 case TARGET_NR_getppid:
6136 ret = get_errno(getppid());
6137 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006138#endif
bellard31e31b82003-02-18 22:55:36 +00006139 case TARGET_NR_getpgrp:
6140 ret = get_errno(getpgrp());
6141 break;
6142 case TARGET_NR_setsid:
6143 ret = get_errno(setsid());
6144 break;
thse5febef2007-04-01 18:31:35 +00006145#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006146 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006147 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006148#if defined(TARGET_ALPHA)
6149 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006150 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006151 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006152 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6153 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006154 act._sa_handler = old_act->_sa_handler;
6155 target_siginitset(&act.sa_mask, old_act->sa_mask);
6156 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006157 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006158 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006159 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006160 }
6161 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006162 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006163 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6164 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006165 old_act->_sa_handler = oact._sa_handler;
6166 old_act->sa_mask = oact.sa_mask.sig[0];
6167 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006168 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006169 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006170#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006171 struct target_sigaction act, oact, *pact, *old_act;
6172
6173 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006174 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6175 goto efault;
bellard106ec872006-06-27 21:08:10 +00006176 act._sa_handler = old_act->_sa_handler;
6177 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6178 act.sa_flags = old_act->sa_flags;
6179 unlock_user_struct(old_act, arg2, 0);
6180 pact = &act;
6181 } else {
6182 pact = NULL;
6183 }
6184
6185 ret = get_errno(do_sigaction(arg1, pact, &oact));
6186
6187 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006188 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6189 goto efault;
bellard106ec872006-06-27 21:08:10 +00006190 old_act->_sa_handler = oact._sa_handler;
6191 old_act->sa_flags = oact.sa_flags;
6192 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6193 old_act->sa_mask.sig[1] = 0;
6194 old_act->sa_mask.sig[2] = 0;
6195 old_act->sa_mask.sig[3] = 0;
6196 unlock_user_struct(old_act, arg3, 1);
6197 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006198#else
6199 struct target_old_sigaction *old_act;
6200 struct target_sigaction act, oact, *pact;
6201 if (arg2) {
6202 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6203 goto efault;
6204 act._sa_handler = old_act->_sa_handler;
6205 target_siginitset(&act.sa_mask, old_act->sa_mask);
6206 act.sa_flags = old_act->sa_flags;
6207 act.sa_restorer = old_act->sa_restorer;
6208 unlock_user_struct(old_act, arg2, 0);
6209 pact = &act;
6210 } else {
6211 pact = NULL;
6212 }
6213 ret = get_errno(do_sigaction(arg1, pact, &oact));
6214 if (!is_error(ret) && arg3) {
6215 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6216 goto efault;
6217 old_act->_sa_handler = oact._sa_handler;
6218 old_act->sa_mask = oact.sa_mask.sig[0];
6219 old_act->sa_flags = oact.sa_flags;
6220 old_act->sa_restorer = oact.sa_restorer;
6221 unlock_user_struct(old_act, arg3, 1);
6222 }
ths388bb212007-05-13 13:58:00 +00006223#endif
bellard31e31b82003-02-18 22:55:36 +00006224 }
6225 break;
thse5febef2007-04-01 18:31:35 +00006226#endif
bellard66fb9762003-03-23 01:06:05 +00006227 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006228 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006229#if defined(TARGET_ALPHA)
6230 struct target_sigaction act, oact, *pact = 0;
6231 struct target_rt_sigaction *rt_act;
6232 /* ??? arg4 == sizeof(sigset_t). */
6233 if (arg2) {
6234 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6235 goto efault;
6236 act._sa_handler = rt_act->_sa_handler;
6237 act.sa_mask = rt_act->sa_mask;
6238 act.sa_flags = rt_act->sa_flags;
6239 act.sa_restorer = arg5;
6240 unlock_user_struct(rt_act, arg2, 0);
6241 pact = &act;
6242 }
6243 ret = get_errno(do_sigaction(arg1, pact, &oact));
6244 if (!is_error(ret) && arg3) {
6245 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6246 goto efault;
6247 rt_act->_sa_handler = oact._sa_handler;
6248 rt_act->sa_mask = oact.sa_mask;
6249 rt_act->sa_flags = oact.sa_flags;
6250 unlock_user_struct(rt_act, arg3, 1);
6251 }
6252#else
pbrook53a59602006-03-25 19:31:22 +00006253 struct target_sigaction *act;
6254 struct target_sigaction *oact;
6255
bellard579a97f2007-11-11 14:26:47 +00006256 if (arg2) {
6257 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6258 goto efault;
6259 } else
pbrook53a59602006-03-25 19:31:22 +00006260 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006261 if (arg3) {
6262 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6263 ret = -TARGET_EFAULT;
6264 goto rt_sigaction_fail;
6265 }
6266 } else
pbrook53a59602006-03-25 19:31:22 +00006267 oact = NULL;
6268 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006269 rt_sigaction_fail:
6270 if (act)
pbrook53a59602006-03-25 19:31:22 +00006271 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006272 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006273 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006274#endif
pbrook53a59602006-03-25 19:31:22 +00006275 }
bellard66fb9762003-03-23 01:06:05 +00006276 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006277#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006278 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006279 {
6280 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006281 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006282 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006283 host_to_target_old_sigset(&target_set, &cur_set);
6284 ret = target_set;
6285 }
6286 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006287#endif
6288#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006289 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006290 {
6291 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006292 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006293 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006294 target_to_host_old_sigset(&set, &target_set);
6295 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006296 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006297 host_to_target_old_sigset(&target_set, &oset);
6298 ret = target_set;
6299 }
6300 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006301#endif
thse5febef2007-04-01 18:31:35 +00006302#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006303 case TARGET_NR_sigprocmask:
6304 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006305#if defined(TARGET_ALPHA)
6306 sigset_t set, oldset;
6307 abi_ulong mask;
6308 int how;
6309
6310 switch (arg1) {
6311 case TARGET_SIG_BLOCK:
6312 how = SIG_BLOCK;
6313 break;
6314 case TARGET_SIG_UNBLOCK:
6315 how = SIG_UNBLOCK;
6316 break;
6317 case TARGET_SIG_SETMASK:
6318 how = SIG_SETMASK;
6319 break;
6320 default:
6321 ret = -TARGET_EINVAL;
6322 goto fail;
6323 }
6324 mask = arg2;
6325 target_to_host_old_sigset(&set, &mask);
6326
Alex Barcelo1c275922014-03-14 14:36:55 +00006327 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006328 if (!is_error(ret)) {
6329 host_to_target_old_sigset(&mask, &oldset);
6330 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006331 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006332 }
6333#else
bellard66fb9762003-03-23 01:06:05 +00006334 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006335 int how;
ths3b46e622007-09-17 08:09:54 +00006336
pbrook53a59602006-03-25 19:31:22 +00006337 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006338 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006339 case TARGET_SIG_BLOCK:
6340 how = SIG_BLOCK;
6341 break;
6342 case TARGET_SIG_UNBLOCK:
6343 how = SIG_UNBLOCK;
6344 break;
6345 case TARGET_SIG_SETMASK:
6346 how = SIG_SETMASK;
6347 break;
6348 default:
ths0da46a62007-10-20 20:23:07 +00006349 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006350 goto fail;
6351 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006352 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006353 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006354 target_to_host_old_sigset(&set, p);
6355 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006356 set_ptr = &set;
6357 } else {
6358 how = 0;
6359 set_ptr = NULL;
6360 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006361 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006362 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006363 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006364 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006365 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006366 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006367 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006368#endif
bellard66fb9762003-03-23 01:06:05 +00006369 }
6370 break;
thse5febef2007-04-01 18:31:35 +00006371#endif
bellard66fb9762003-03-23 01:06:05 +00006372 case TARGET_NR_rt_sigprocmask:
6373 {
6374 int how = arg1;
6375 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006376
pbrook53a59602006-03-25 19:31:22 +00006377 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006378 switch(how) {
6379 case TARGET_SIG_BLOCK:
6380 how = SIG_BLOCK;
6381 break;
6382 case TARGET_SIG_UNBLOCK:
6383 how = SIG_UNBLOCK;
6384 break;
6385 case TARGET_SIG_SETMASK:
6386 how = SIG_SETMASK;
6387 break;
6388 default:
ths0da46a62007-10-20 20:23:07 +00006389 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006390 goto fail;
6391 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006392 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006393 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006394 target_to_host_sigset(&set, p);
6395 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006396 set_ptr = &set;
6397 } else {
6398 how = 0;
6399 set_ptr = NULL;
6400 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006401 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006402 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006403 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006404 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006405 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006406 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006407 }
6408 }
6409 break;
thse5febef2007-04-01 18:31:35 +00006410#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006411 case TARGET_NR_sigpending:
6412 {
6413 sigset_t set;
6414 ret = get_errno(sigpending(&set));
6415 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006416 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006417 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006418 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006419 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006420 }
6421 }
6422 break;
thse5febef2007-04-01 18:31:35 +00006423#endif
bellard66fb9762003-03-23 01:06:05 +00006424 case TARGET_NR_rt_sigpending:
6425 {
6426 sigset_t set;
6427 ret = get_errno(sigpending(&set));
6428 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006429 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006430 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006431 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006432 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006433 }
6434 }
6435 break;
thse5febef2007-04-01 18:31:35 +00006436#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006437 case TARGET_NR_sigsuspend:
6438 {
6439 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006440#if defined(TARGET_ALPHA)
6441 abi_ulong mask = arg1;
6442 target_to_host_old_sigset(&set, &mask);
6443#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006444 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006445 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006446 target_to_host_old_sigset(&set, p);
6447 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006448#endif
bellard66fb9762003-03-23 01:06:05 +00006449 ret = get_errno(sigsuspend(&set));
6450 }
6451 break;
thse5febef2007-04-01 18:31:35 +00006452#endif
bellard66fb9762003-03-23 01:06:05 +00006453 case TARGET_NR_rt_sigsuspend:
6454 {
6455 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006456 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006457 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006458 target_to_host_sigset(&set, p);
6459 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006460 ret = get_errno(sigsuspend(&set));
6461 }
6462 break;
6463 case TARGET_NR_rt_sigtimedwait:
6464 {
bellard66fb9762003-03-23 01:06:05 +00006465 sigset_t set;
6466 struct timespec uts, *puts;
6467 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006468
Anthony Liguoric227f092009-10-01 16:12:16 -05006469 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006470 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006471 target_to_host_sigset(&set, p);
6472 unlock_user(p, arg1, 0);
6473 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006474 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006475 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006476 } else {
6477 puts = NULL;
6478 }
6479 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006480 if (!is_error(ret)) {
6481 if (arg2) {
6482 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6483 0);
6484 if (!p) {
6485 goto efault;
6486 }
6487 host_to_target_siginfo(p, &uinfo);
6488 unlock_user(p, arg2, sizeof(target_siginfo_t));
6489 }
6490 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006491 }
6492 }
6493 break;
6494 case TARGET_NR_rt_sigqueueinfo:
6495 {
6496 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006497 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006498 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006499 target_to_host_siginfo(&uinfo, p);
6500 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006501 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6502 }
6503 break;
thse5febef2007-04-01 18:31:35 +00006504#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006505 case TARGET_NR_sigreturn:
6506 /* NOTE: ret is eax, so not transcoding must be done */
6507 ret = do_sigreturn(cpu_env);
6508 break;
thse5febef2007-04-01 18:31:35 +00006509#endif
bellard66fb9762003-03-23 01:06:05 +00006510 case TARGET_NR_rt_sigreturn:
6511 /* NOTE: ret is eax, so not transcoding must be done */
6512 ret = do_rt_sigreturn(cpu_env);
6513 break;
bellard31e31b82003-02-18 22:55:36 +00006514 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006515 if (!(p = lock_user_string(arg1)))
6516 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006517 ret = get_errno(sethostname(p, arg2));
6518 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006519 break;
6520 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006521 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006522 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006523 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006524 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006525 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6526 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006527 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6528 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006529 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006530 ret = get_errno(setrlimit(resource, &rlim));
6531 }
6532 break;
bellard31e31b82003-02-18 22:55:36 +00006533 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006534 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006535 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006536 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006537 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006538
bellard9de5e442003-03-23 16:49:39 +00006539 ret = get_errno(getrlimit(resource, &rlim));
6540 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006541 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6542 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006543 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6544 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006545 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006546 }
6547 }
6548 break;
bellard31e31b82003-02-18 22:55:36 +00006549 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006550 {
6551 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006552 ret = get_errno(getrusage(arg1, &rusage));
6553 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006554 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006555 }
6556 }
6557 break;
bellard31e31b82003-02-18 22:55:36 +00006558 case TARGET_NR_gettimeofday:
6559 {
bellard31e31b82003-02-18 22:55:36 +00006560 struct timeval tv;
6561 ret = get_errno(gettimeofday(&tv, NULL));
6562 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006563 if (copy_to_user_timeval(arg1, &tv))
6564 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006565 }
6566 }
6567 break;
6568 case TARGET_NR_settimeofday:
6569 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006570 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006571 struct timezone tz, *ptz = NULL;
6572
Paul Burtonb67d8032014-06-22 11:25:41 +01006573 if (arg1) {
6574 if (copy_from_user_timeval(&tv, arg1)) {
6575 goto efault;
6576 }
6577 ptv = &tv;
6578 }
Paul Burtonef4467e2014-06-22 11:25:40 +01006579
6580 if (arg2) {
6581 if (copy_from_user_timezone(&tz, arg2)) {
6582 goto efault;
6583 }
6584 ptz = &tz;
6585 }
6586
Paul Burtonb67d8032014-06-22 11:25:41 +01006587 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00006588 }
6589 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006590#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006591 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006592#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6593 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6594#else
bellardf2674e32003-07-09 12:26:09 +00006595 {
pbrook53a59602006-03-25 19:31:22 +00006596 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006597 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006598 long nsel;
6599
bellard579a97f2007-11-11 14:26:47 +00006600 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6601 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006602 nsel = tswapal(sel->n);
6603 inp = tswapal(sel->inp);
6604 outp = tswapal(sel->outp);
6605 exp = tswapal(sel->exp);
6606 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006607 unlock_user_struct(sel, arg1, 0);
6608 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006609 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006610#endif
bellardf2674e32003-07-09 12:26:09 +00006611 break;
bellard048f6b42005-11-26 18:47:20 +00006612#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006613#ifdef TARGET_NR_pselect6
6614 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006615 {
6616 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6617 fd_set rfds, wfds, efds;
6618 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6619 struct timespec ts, *ts_ptr;
6620
6621 /*
6622 * The 6th arg is actually two args smashed together,
6623 * so we cannot use the C library.
6624 */
6625 sigset_t set;
6626 struct {
6627 sigset_t *set;
6628 size_t size;
6629 } sig, *sig_ptr;
6630
6631 abi_ulong arg_sigset, arg_sigsize, *arg7;
6632 target_sigset_t *target_sigset;
6633
6634 n = arg1;
6635 rfd_addr = arg2;
6636 wfd_addr = arg3;
6637 efd_addr = arg4;
6638 ts_addr = arg5;
6639
6640 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6641 if (ret) {
6642 goto fail;
6643 }
6644 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6645 if (ret) {
6646 goto fail;
6647 }
6648 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6649 if (ret) {
6650 goto fail;
6651 }
6652
6653 /*
6654 * This takes a timespec, and not a timeval, so we cannot
6655 * use the do_select() helper ...
6656 */
6657 if (ts_addr) {
6658 if (target_to_host_timespec(&ts, ts_addr)) {
6659 goto efault;
6660 }
6661 ts_ptr = &ts;
6662 } else {
6663 ts_ptr = NULL;
6664 }
6665
6666 /* Extract the two packed args for the sigset */
6667 if (arg6) {
6668 sig_ptr = &sig;
6669 sig.size = _NSIG / 8;
6670
6671 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6672 if (!arg7) {
6673 goto efault;
6674 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006675 arg_sigset = tswapal(arg7[0]);
6676 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006677 unlock_user(arg7, arg6, 0);
6678
6679 if (arg_sigset) {
6680 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006681 if (arg_sigsize != sizeof(*target_sigset)) {
6682 /* Like the kernel, we enforce correct size sigsets */
6683 ret = -TARGET_EINVAL;
6684 goto fail;
6685 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006686 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6687 sizeof(*target_sigset), 1);
6688 if (!target_sigset) {
6689 goto efault;
6690 }
6691 target_to_host_sigset(&set, target_sigset);
6692 unlock_user(target_sigset, arg_sigset, 0);
6693 } else {
6694 sig.set = NULL;
6695 }
6696 } else {
6697 sig_ptr = NULL;
6698 }
6699
6700 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6701 ts_ptr, sig_ptr));
6702
6703 if (!is_error(ret)) {
6704 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6705 goto efault;
6706 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6707 goto efault;
6708 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6709 goto efault;
6710
6711 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6712 goto efault;
6713 }
6714 }
6715 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006716#endif
bellard31e31b82003-02-18 22:55:36 +00006717 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006718 {
6719 void *p2;
6720 p = lock_user_string(arg1);
6721 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006722 if (!p || !p2)
6723 ret = -TARGET_EFAULT;
6724 else
6725 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006726 unlock_user(p2, arg2, 0);
6727 unlock_user(p, arg1, 0);
6728 }
bellard31e31b82003-02-18 22:55:36 +00006729 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006730#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006731 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006732 {
bellard579a97f2007-11-11 14:26:47 +00006733 void *p2;
thsf0b62432007-09-24 09:25:40 +00006734 p = lock_user_string(arg1);
6735 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006736 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006737 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006738 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006739 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006740 unlock_user(p2, arg3, 0);
6741 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006742 }
6743 break;
6744#endif
bellardebc05482003-09-30 21:08:41 +00006745#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006746 case TARGET_NR_oldlstat:
6747 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006748#endif
bellard31e31b82003-02-18 22:55:36 +00006749 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006750 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006751 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006752 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006753 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006754 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006755 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09006756 } else if (!arg3) {
6757 /* Short circuit this for the magic exe check. */
6758 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006759 } else if (is_proc_myself((const char *)p, "exe")) {
6760 char real[PATH_MAX], *temp;
6761 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09006762 /* Return value is # of bytes that we wrote to the buffer. */
6763 if (temp == NULL) {
6764 ret = get_errno(-1);
6765 } else {
6766 /* Don't worry about sign mismatch as earlier mapping
6767 * logic would have thrown a bad address error. */
6768 ret = MIN(strlen(real), arg3);
6769 /* We cannot NUL terminate the string. */
6770 memcpy(p2, real, ret);
6771 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01006772 } else {
6773 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006774 }
pbrook53a59602006-03-25 19:31:22 +00006775 unlock_user(p2, arg2, ret);
6776 unlock_user(p, arg1, 0);
6777 }
bellard31e31b82003-02-18 22:55:36 +00006778 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006779#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006780 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006781 {
bellard579a97f2007-11-11 14:26:47 +00006782 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006783 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006784 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006785 if (!p || !p2) {
6786 ret = -TARGET_EFAULT;
6787 } else if (is_proc_myself((const char *)p, "exe")) {
6788 char real[PATH_MAX], *temp;
6789 temp = realpath(exec_path, real);
6790 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6791 snprintf((char *)p2, arg4, "%s", real);
6792 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006793 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006794 }
bellard579a97f2007-11-11 14:26:47 +00006795 unlock_user(p2, arg3, ret);
6796 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006797 }
6798 break;
6799#endif
thse5febef2007-04-01 18:31:35 +00006800#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006801 case TARGET_NR_uselib:
6802 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006803#endif
6804#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006805 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006806 if (!(p = lock_user_string(arg1)))
6807 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006808 ret = get_errno(swapon(p, arg2));
6809 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006810 break;
thse5febef2007-04-01 18:31:35 +00006811#endif
bellard31e31b82003-02-18 22:55:36 +00006812 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006813 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6814 /* arg4 must be ignored in all other cases */
6815 p = lock_user_string(arg4);
6816 if (!p) {
6817 goto efault;
6818 }
6819 ret = get_errno(reboot(arg1, arg2, arg3, p));
6820 unlock_user(p, arg4, 0);
6821 } else {
6822 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6823 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006824 break;
thse5febef2007-04-01 18:31:35 +00006825#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006826 case TARGET_NR_readdir:
6827 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006828#endif
6829#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006830 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006831#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6832 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006833 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6834 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006835 {
blueswir1992f48a2007-10-14 16:27:31 +00006836 abi_ulong *v;
6837 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006838 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6839 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006840 v1 = tswapal(v[0]);
6841 v2 = tswapal(v[1]);
6842 v3 = tswapal(v[2]);
6843 v4 = tswapal(v[3]);
6844 v5 = tswapal(v[4]);
6845 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006846 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006847 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006848 target_to_host_bitmask(v4, mmap_flags_tbl),
6849 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006850 }
bellard31e31b82003-02-18 22:55:36 +00006851#else
ths5fafdf22007-09-16 21:08:06 +00006852 ret = get_errno(target_mmap(arg1, arg2, arg3,
6853 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006854 arg5,
6855 arg6));
bellard31e31b82003-02-18 22:55:36 +00006856#endif
bellard6fb883e2003-07-09 17:12:39 +00006857 break;
thse5febef2007-04-01 18:31:35 +00006858#endif
bellarda315a142005-01-30 22:59:18 +00006859#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006860 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006861#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006862#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006863#endif
ths5fafdf22007-09-16 21:08:06 +00006864 ret = get_errno(target_mmap(arg1, arg2, arg3,
6865 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006866 arg5,
bellardc573ff62004-01-04 15:51:36 +00006867 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006868 break;
bellarda315a142005-01-30 22:59:18 +00006869#endif
bellard31e31b82003-02-18 22:55:36 +00006870 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006871 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006872 break;
bellard9de5e442003-03-23 16:49:39 +00006873 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006874 {
Andreas Färber0429a972013-08-26 18:14:44 +02006875 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006876 /* Special hack to detect libc making the stack executable. */
6877 if ((arg3 & PROT_GROWSDOWN)
6878 && arg1 >= ts->info->stack_limit
6879 && arg1 <= ts->info->start_stack) {
6880 arg3 &= ~PROT_GROWSDOWN;
6881 arg2 = arg2 + arg1 - ts->info->stack_limit;
6882 arg1 = ts->info->stack_limit;
6883 }
6884 }
bellard54936002003-05-13 00:25:15 +00006885 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006886 break;
thse5febef2007-04-01 18:31:35 +00006887#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006888 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006889 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006890 break;
thse5febef2007-04-01 18:31:35 +00006891#endif
pbrook53a59602006-03-25 19:31:22 +00006892 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006893#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006894 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006895 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006896 break;
thse5febef2007-04-01 18:31:35 +00006897#endif
6898#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006899 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006900 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006901 break;
thse5febef2007-04-01 18:31:35 +00006902#endif
6903#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006904 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006905 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006906 break;
thse5febef2007-04-01 18:31:35 +00006907#endif
6908#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006909 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05006910 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00006911 break;
thse5febef2007-04-01 18:31:35 +00006912#endif
6913#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006914 case TARGET_NR_munlockall:
6915 ret = get_errno(munlockall());
6916 break;
thse5febef2007-04-01 18:31:35 +00006917#endif
bellard31e31b82003-02-18 22:55:36 +00006918 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006919 if (!(p = lock_user_string(arg1)))
6920 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006921 ret = get_errno(truncate(p, arg2));
6922 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006923 break;
6924 case TARGET_NR_ftruncate:
6925 ret = get_errno(ftruncate(arg1, arg2));
6926 break;
6927 case TARGET_NR_fchmod:
6928 ret = get_errno(fchmod(arg1, arg2));
6929 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006930#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006931 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006932 if (!(p = lock_user_string(arg2)))
6933 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006934 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006935 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006936 break;
6937#endif
bellard31e31b82003-02-18 22:55:36 +00006938 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006939 /* Note that negative values are valid for getpriority, so we must
6940 differentiate based on errno settings. */
6941 errno = 0;
6942 ret = getpriority(arg1, arg2);
6943 if (ret == -1 && errno != 0) {
6944 ret = -host_to_target_errno(errno);
6945 break;
6946 }
6947#ifdef TARGET_ALPHA
6948 /* Return value is the unbiased priority. Signal no error. */
6949 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6950#else
6951 /* Return value is a biased priority to avoid negative numbers. */
6952 ret = 20 - ret;
6953#endif
bellard31e31b82003-02-18 22:55:36 +00006954 break;
6955 case TARGET_NR_setpriority:
6956 ret = get_errno(setpriority(arg1, arg2, arg3));
6957 break;
bellardebc05482003-09-30 21:08:41 +00006958#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006959 case TARGET_NR_profil:
6960 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006961#endif
bellard31e31b82003-02-18 22:55:36 +00006962 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006963 if (!(p = lock_user_string(arg1)))
6964 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006965 ret = get_errno(statfs(path(p), &stfs));
6966 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006967 convert_statfs:
6968 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006969 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006970
bellard579a97f2007-11-11 14:26:47 +00006971 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6972 goto efault;
6973 __put_user(stfs.f_type, &target_stfs->f_type);
6974 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6975 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6976 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6977 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6978 __put_user(stfs.f_files, &target_stfs->f_files);
6979 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6980 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6981 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6982 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006983 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6984 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006985 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006986 }
6987 break;
6988 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006989 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006990 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006991#ifdef TARGET_NR_statfs64
6992 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006993 if (!(p = lock_user_string(arg1)))
6994 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006995 ret = get_errno(statfs(path(p), &stfs));
6996 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006997 convert_statfs64:
6998 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006999 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007000
bellard579a97f2007-11-11 14:26:47 +00007001 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7002 goto efault;
7003 __put_user(stfs.f_type, &target_stfs->f_type);
7004 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7005 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7006 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7007 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7008 __put_user(stfs.f_files, &target_stfs->f_files);
7009 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7010 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7011 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7012 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007013 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7014 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007015 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007016 }
7017 break;
7018 case TARGET_NR_fstatfs64:
7019 ret = get_errno(fstatfs(arg1, &stfs));
7020 goto convert_statfs64;
7021#endif
bellardebc05482003-09-30 21:08:41 +00007022#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007023 case TARGET_NR_ioperm:
7024 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007025#endif
thse5febef2007-04-01 18:31:35 +00007026#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007027 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007028 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007029 break;
thse5febef2007-04-01 18:31:35 +00007030#endif
bellard3532fa72006-06-24 15:06:03 +00007031#ifdef TARGET_NR_accept
7032 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007033 ret = do_accept4(arg1, arg2, arg3, 0);
7034 break;
7035#endif
7036#ifdef TARGET_NR_accept4
7037 case TARGET_NR_accept4:
7038#ifdef CONFIG_ACCEPT4
7039 ret = do_accept4(arg1, arg2, arg3, arg4);
7040#else
7041 goto unimplemented;
7042#endif
bellard3532fa72006-06-24 15:06:03 +00007043 break;
7044#endif
7045#ifdef TARGET_NR_bind
7046 case TARGET_NR_bind:
7047 ret = do_bind(arg1, arg2, arg3);
7048 break;
7049#endif
7050#ifdef TARGET_NR_connect
7051 case TARGET_NR_connect:
7052 ret = do_connect(arg1, arg2, arg3);
7053 break;
7054#endif
7055#ifdef TARGET_NR_getpeername
7056 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007057 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007058 break;
7059#endif
7060#ifdef TARGET_NR_getsockname
7061 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007062 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007063 break;
7064#endif
7065#ifdef TARGET_NR_getsockopt
7066 case TARGET_NR_getsockopt:
7067 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7068 break;
7069#endif
7070#ifdef TARGET_NR_listen
7071 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007072 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007073 break;
7074#endif
7075#ifdef TARGET_NR_recv
7076 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007077 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007078 break;
7079#endif
7080#ifdef TARGET_NR_recvfrom
7081 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007082 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007083 break;
7084#endif
7085#ifdef TARGET_NR_recvmsg
7086 case TARGET_NR_recvmsg:
7087 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7088 break;
7089#endif
7090#ifdef TARGET_NR_send
7091 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007092 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007093 break;
7094#endif
7095#ifdef TARGET_NR_sendmsg
7096 case TARGET_NR_sendmsg:
7097 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7098 break;
7099#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007100#ifdef TARGET_NR_sendmmsg
7101 case TARGET_NR_sendmmsg:
7102 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7103 break;
7104 case TARGET_NR_recvmmsg:
7105 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7106 break;
7107#endif
bellard3532fa72006-06-24 15:06:03 +00007108#ifdef TARGET_NR_sendto
7109 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007110 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007111 break;
7112#endif
7113#ifdef TARGET_NR_shutdown
7114 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007115 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007116 break;
7117#endif
7118#ifdef TARGET_NR_socket
7119 case TARGET_NR_socket:
7120 ret = do_socket(arg1, arg2, arg3);
7121 break;
7122#endif
7123#ifdef TARGET_NR_socketpair
7124 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007125 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007126 break;
7127#endif
7128#ifdef TARGET_NR_setsockopt
7129 case TARGET_NR_setsockopt:
7130 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7131 break;
7132#endif
ths7494b0f2007-02-11 18:26:53 +00007133
bellard31e31b82003-02-18 22:55:36 +00007134 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007135 if (!(p = lock_user_string(arg2)))
7136 goto efault;
thse5574482007-02-11 20:03:13 +00007137 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7138 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007139 break;
7140
bellard31e31b82003-02-18 22:55:36 +00007141 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007142 {
bellard66fb9762003-03-23 01:06:05 +00007143 struct itimerval value, ovalue, *pvalue;
7144
pbrook53a59602006-03-25 19:31:22 +00007145 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007146 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007147 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7148 || copy_from_user_timeval(&pvalue->it_value,
7149 arg2 + sizeof(struct target_timeval)))
7150 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007151 } else {
7152 pvalue = NULL;
7153 }
7154 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007155 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007156 if (copy_to_user_timeval(arg3,
7157 &ovalue.it_interval)
7158 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7159 &ovalue.it_value))
7160 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007161 }
7162 }
7163 break;
bellard31e31b82003-02-18 22:55:36 +00007164 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007165 {
bellard66fb9762003-03-23 01:06:05 +00007166 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007167
bellard66fb9762003-03-23 01:06:05 +00007168 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007169 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007170 if (copy_to_user_timeval(arg2,
7171 &value.it_interval)
7172 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7173 &value.it_value))
7174 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007175 }
7176 }
7177 break;
bellard31e31b82003-02-18 22:55:36 +00007178 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007179 if (!(p = lock_user_string(arg1)))
7180 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007181 ret = get_errno(stat(path(p), &st));
7182 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007183 goto do_stat;
7184 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007185 if (!(p = lock_user_string(arg1)))
7186 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007187 ret = get_errno(lstat(path(p), &st));
7188 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007189 goto do_stat;
7190 case TARGET_NR_fstat:
7191 {
7192 ret = get_errno(fstat(arg1, &st));
7193 do_stat:
7194 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007195 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007196
bellard579a97f2007-11-11 14:26:47 +00007197 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7198 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007199 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007200 __put_user(st.st_dev, &target_st->st_dev);
7201 __put_user(st.st_ino, &target_st->st_ino);
7202 __put_user(st.st_mode, &target_st->st_mode);
7203 __put_user(st.st_uid, &target_st->st_uid);
7204 __put_user(st.st_gid, &target_st->st_gid);
7205 __put_user(st.st_nlink, &target_st->st_nlink);
7206 __put_user(st.st_rdev, &target_st->st_rdev);
7207 __put_user(st.st_size, &target_st->st_size);
7208 __put_user(st.st_blksize, &target_st->st_blksize);
7209 __put_user(st.st_blocks, &target_st->st_blocks);
7210 __put_user(st.st_atime, &target_st->target_st_atime);
7211 __put_user(st.st_mtime, &target_st->target_st_mtime);
7212 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007213 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007214 }
7215 }
7216 break;
bellardebc05482003-09-30 21:08:41 +00007217#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_olduname:
7219 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007220#endif
7221#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007222 case TARGET_NR_iopl:
7223 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007224#endif
bellard31e31b82003-02-18 22:55:36 +00007225 case TARGET_NR_vhangup:
7226 ret = get_errno(vhangup());
7227 break;
bellardebc05482003-09-30 21:08:41 +00007228#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007229 case TARGET_NR_idle:
7230 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007231#endif
bellard42ad6ae2005-01-03 22:48:11 +00007232#ifdef TARGET_NR_syscall
7233 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007234 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7235 arg6, arg7, arg8, 0);
7236 break;
bellard42ad6ae2005-01-03 22:48:11 +00007237#endif
bellard31e31b82003-02-18 22:55:36 +00007238 case TARGET_NR_wait4:
7239 {
7240 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007241 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007242 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007243 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007244 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007245 if (target_rusage)
7246 rusage_ptr = &rusage;
7247 else
7248 rusage_ptr = NULL;
7249 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7250 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007251 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007252 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007253 if (put_user_s32(status, status_ptr))
7254 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007255 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007256 if (target_rusage) {
7257 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7258 if (rusage_err) {
7259 ret = rusage_err;
7260 }
7261 }
bellard31e31b82003-02-18 22:55:36 +00007262 }
7263 }
7264 break;
thse5febef2007-04-01 18:31:35 +00007265#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007266 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007267 if (!(p = lock_user_string(arg1)))
7268 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007269 ret = get_errno(swapoff(p));
7270 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007271 break;
thse5febef2007-04-01 18:31:35 +00007272#endif
bellard31e31b82003-02-18 22:55:36 +00007273 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007274 {
pbrook53a59602006-03-25 19:31:22 +00007275 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007276 struct sysinfo value;
7277 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007278 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007279 {
bellard579a97f2007-11-11 14:26:47 +00007280 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7281 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007282 __put_user(value.uptime, &target_value->uptime);
7283 __put_user(value.loads[0], &target_value->loads[0]);
7284 __put_user(value.loads[1], &target_value->loads[1]);
7285 __put_user(value.loads[2], &target_value->loads[2]);
7286 __put_user(value.totalram, &target_value->totalram);
7287 __put_user(value.freeram, &target_value->freeram);
7288 __put_user(value.sharedram, &target_value->sharedram);
7289 __put_user(value.bufferram, &target_value->bufferram);
7290 __put_user(value.totalswap, &target_value->totalswap);
7291 __put_user(value.freeswap, &target_value->freeswap);
7292 __put_user(value.procs, &target_value->procs);
7293 __put_user(value.totalhigh, &target_value->totalhigh);
7294 __put_user(value.freehigh, &target_value->freehigh);
7295 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007296 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007297 }
7298 }
7299 break;
thse5febef2007-04-01 18:31:35 +00007300#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007301 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007302 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7303 break;
thse5febef2007-04-01 18:31:35 +00007304#endif
aurel32e5289082009-04-18 16:16:12 +00007305#ifdef TARGET_NR_semget
7306 case TARGET_NR_semget:
7307 ret = get_errno(semget(arg1, arg2, arg3));
7308 break;
7309#endif
7310#ifdef TARGET_NR_semop
7311 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007312 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007313 break;
7314#endif
7315#ifdef TARGET_NR_semctl
7316 case TARGET_NR_semctl:
7317 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7318 break;
7319#endif
aurel32eeb438c2008-10-13 21:08:55 +00007320#ifdef TARGET_NR_msgctl
7321 case TARGET_NR_msgctl:
7322 ret = do_msgctl(arg1, arg2, arg3);
7323 break;
7324#endif
7325#ifdef TARGET_NR_msgget
7326 case TARGET_NR_msgget:
7327 ret = get_errno(msgget(arg1, arg2));
7328 break;
7329#endif
7330#ifdef TARGET_NR_msgrcv
7331 case TARGET_NR_msgrcv:
7332 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7333 break;
7334#endif
7335#ifdef TARGET_NR_msgsnd
7336 case TARGET_NR_msgsnd:
7337 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7338 break;
7339#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007340#ifdef TARGET_NR_shmget
7341 case TARGET_NR_shmget:
7342 ret = get_errno(shmget(arg1, arg2, arg3));
7343 break;
7344#endif
7345#ifdef TARGET_NR_shmctl
7346 case TARGET_NR_shmctl:
7347 ret = do_shmctl(arg1, arg2, arg3);
7348 break;
7349#endif
7350#ifdef TARGET_NR_shmat
7351 case TARGET_NR_shmat:
7352 ret = do_shmat(arg1, arg2, arg3);
7353 break;
7354#endif
7355#ifdef TARGET_NR_shmdt
7356 case TARGET_NR_shmdt:
7357 ret = do_shmdt(arg1);
7358 break;
7359#endif
bellard31e31b82003-02-18 22:55:36 +00007360 case TARGET_NR_fsync:
7361 ret = get_errno(fsync(arg1));
7362 break;
bellard31e31b82003-02-18 22:55:36 +00007363 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007364 /* Linux manages to have three different orderings for its
7365 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7366 * match the kernel's CONFIG_CLONE_* settings.
7367 * Microblaze is further special in that it uses a sixth
7368 * implicit argument to clone for the TLS pointer.
7369 */
7370#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007371 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007372#elif defined(TARGET_CLONE_BACKWARDS)
7373 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7374#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007375 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007376#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007377 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007378#endif
bellard1b6b0292003-03-22 17:31:38 +00007379 break;
bellardec86b0f2003-04-11 00:15:04 +00007380#ifdef __NR_exit_group
7381 /* new thread calls */
7382 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007383#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007384 _mcleanup();
7385#endif
bellarde9009672005-04-26 20:42:36 +00007386 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007387 ret = get_errno(exit_group(arg1));
7388 break;
7389#endif
bellard31e31b82003-02-18 22:55:36 +00007390 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007391 if (!(p = lock_user_string(arg1)))
7392 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007393 ret = get_errno(setdomainname(p, arg2));
7394 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007395 break;
7396 case TARGET_NR_uname:
7397 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007398 {
7399 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007400
bellard579a97f2007-11-11 14:26:47 +00007401 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7402 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007403 ret = get_errno(sys_uname(buf));
7404 if (!is_error(ret)) {
7405 /* Overrite the native machine name with whatever is being
7406 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007407 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007408 /* Allow the user to override the reported release. */
7409 if (qemu_uname_release && *qemu_uname_release)
7410 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007411 }
pbrook53a59602006-03-25 19:31:22 +00007412 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007413 }
bellard31e31b82003-02-18 22:55:36 +00007414 break;
bellard6dbad632003-03-16 18:05:05 +00007415#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007416 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007417 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007418 break;
j_mayer84409dd2007-04-06 08:56:50 +00007419#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007420 case TARGET_NR_vm86old:
7421 goto unimplemented;
7422 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007423 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007424 break;
7425#endif
j_mayer84409dd2007-04-06 08:56:50 +00007426#endif
bellard31e31b82003-02-18 22:55:36 +00007427 case TARGET_NR_adjtimex:
7428 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007429#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007430 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007431#endif
bellard31e31b82003-02-18 22:55:36 +00007432 case TARGET_NR_init_module:
7433 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007434#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007435 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007436#endif
bellard31e31b82003-02-18 22:55:36 +00007437 goto unimplemented;
7438 case TARGET_NR_quotactl:
7439 goto unimplemented;
7440 case TARGET_NR_getpgid:
7441 ret = get_errno(getpgid(arg1));
7442 break;
7443 case TARGET_NR_fchdir:
7444 ret = get_errno(fchdir(arg1));
7445 break;
j_mayer84409dd2007-04-06 08:56:50 +00007446#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007447 case TARGET_NR_bdflush:
7448 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007449#endif
thse5febef2007-04-01 18:31:35 +00007450#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007451 case TARGET_NR_sysfs:
7452 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007453#endif
bellard31e31b82003-02-18 22:55:36 +00007454 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007455 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007456 break;
thse5febef2007-04-01 18:31:35 +00007457#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007458 case TARGET_NR_afs_syscall:
7459 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007460#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007461#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007462 case TARGET_NR__llseek:
7463 {
7464 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007465#if !defined(__NR_llseek)
7466 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7467 if (res == -1) {
7468 ret = get_errno(res);
7469 } else {
7470 ret = 0;
7471 }
7472#else
bellard31e31b82003-02-18 22:55:36 +00007473 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007474#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007475 if ((ret == 0) && put_user_s64(res, arg4)) {
7476 goto efault;
7477 }
bellard31e31b82003-02-18 22:55:36 +00007478 }
7479 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007480#endif
bellard31e31b82003-02-18 22:55:36 +00007481 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007482#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007483#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007484 {
pbrook53a59602006-03-25 19:31:22 +00007485 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007486 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007487 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007488
7489 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007490 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007491 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007492 goto fail;
7493 }
ths3b46e622007-09-17 08:09:54 +00007494
bellard4add45b2003-06-05 01:52:59 +00007495 ret = get_errno(sys_getdents(arg1, dirp, count));
7496 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007497 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007498 struct target_dirent *tde;
7499 int len = ret;
7500 int reclen, treclen;
7501 int count1, tnamelen;
7502
7503 count1 = 0;
7504 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007505 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7506 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007507 tde = target_dirp;
7508 while (len > 0) {
7509 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007510 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7511 assert(tnamelen >= 0);
7512 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7513 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007514 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007515 tde->d_ino = tswapal(de->d_ino);
7516 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007517 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007518 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007519 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007520 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007521 count1 += treclen;
7522 }
7523 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007524 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007525 }
7526 free(dirp);
7527 }
7528#else
bellard31e31b82003-02-18 22:55:36 +00007529 {
aurel326556a832008-10-13 21:08:17 +00007530 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007531 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007532
bellard579a97f2007-11-11 14:26:47 +00007533 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7534 goto efault;
bellard72f03902003-02-18 23:33:18 +00007535 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007536 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007537 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007538 int len = ret;
7539 int reclen;
7540 de = dirp;
7541 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007542 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007543 if (reclen > len)
7544 break;
bellard8083a3e2003-03-24 23:12:16 +00007545 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007546 tswapls(&de->d_ino);
7547 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007548 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007549 len -= reclen;
7550 }
7551 }
pbrook53a59602006-03-25 19:31:22 +00007552 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007553 }
bellard4add45b2003-06-05 01:52:59 +00007554#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007555#else
7556 /* Implement getdents in terms of getdents64 */
7557 {
7558 struct linux_dirent64 *dirp;
7559 abi_long count = arg3;
7560
7561 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7562 if (!dirp) {
7563 goto efault;
7564 }
7565 ret = get_errno(sys_getdents64(arg1, dirp, count));
7566 if (!is_error(ret)) {
7567 /* Convert the dirent64 structs to target dirent. We do this
7568 * in-place, since we can guarantee that a target_dirent is no
7569 * larger than a dirent64; however this means we have to be
7570 * careful to read everything before writing in the new format.
7571 */
7572 struct linux_dirent64 *de;
7573 struct target_dirent *tde;
7574 int len = ret;
7575 int tlen = 0;
7576
7577 de = dirp;
7578 tde = (struct target_dirent *)dirp;
7579 while (len > 0) {
7580 int namelen, treclen;
7581 int reclen = de->d_reclen;
7582 uint64_t ino = de->d_ino;
7583 int64_t off = de->d_off;
7584 uint8_t type = de->d_type;
7585
7586 namelen = strlen(de->d_name);
7587 treclen = offsetof(struct target_dirent, d_name)
7588 + namelen + 2;
7589 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7590
7591 memmove(tde->d_name, de->d_name, namelen + 1);
7592 tde->d_ino = tswapal(ino);
7593 tde->d_off = tswapal(off);
7594 tde->d_reclen = tswap16(treclen);
7595 /* The target_dirent type is in what was formerly a padding
7596 * byte at the end of the structure:
7597 */
7598 *(((char *)tde) + treclen - 1) = type;
7599
7600 de = (struct linux_dirent64 *)((char *)de + reclen);
7601 tde = (struct target_dirent *)((char *)tde + treclen);
7602 len -= reclen;
7603 tlen += treclen;
7604 }
7605 ret = tlen;
7606 }
7607 unlock_user(dirp, arg2, ret);
7608 }
7609#endif
bellard31e31b82003-02-18 22:55:36 +00007610 break;
ths3ae43202007-09-16 21:39:48 +00007611#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007612 case TARGET_NR_getdents64:
7613 {
aurel326556a832008-10-13 21:08:17 +00007614 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007615 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007616 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7617 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007618 ret = get_errno(sys_getdents64(arg1, dirp, count));
7619 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007620 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007621 int len = ret;
7622 int reclen;
7623 de = dirp;
7624 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007625 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007626 if (reclen > len)
7627 break;
bellard8083a3e2003-03-24 23:12:16 +00007628 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007629 tswap64s((uint64_t *)&de->d_ino);
7630 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007631 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007632 len -= reclen;
7633 }
7634 }
pbrook53a59602006-03-25 19:31:22 +00007635 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007636 }
7637 break;
bellarda541f292004-04-12 20:39:29 +00007638#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007639#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007640 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007641 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007642 break;
thse5febef2007-04-01 18:31:35 +00007643#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007644#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7645# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007646 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007647# endif
7648# ifdef TARGET_NR_ppoll
7649 case TARGET_NR_ppoll:
7650# endif
bellard9de5e442003-03-23 16:49:39 +00007651 {
pbrook53a59602006-03-25 19:31:22 +00007652 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007653 unsigned int nfds = arg2;
7654 int timeout = arg3;
7655 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007656 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007657
bellard579a97f2007-11-11 14:26:47 +00007658 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7659 if (!target_pfd)
7660 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007661
bellard9de5e442003-03-23 16:49:39 +00007662 pfd = alloca(sizeof(struct pollfd) * nfds);
7663 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007664 pfd[i].fd = tswap32(target_pfd[i].fd);
7665 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007666 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007667
7668# ifdef TARGET_NR_ppoll
7669 if (num == TARGET_NR_ppoll) {
7670 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7671 target_sigset_t *target_set;
7672 sigset_t _set, *set = &_set;
7673
7674 if (arg3) {
7675 if (target_to_host_timespec(timeout_ts, arg3)) {
7676 unlock_user(target_pfd, arg1, 0);
7677 goto efault;
7678 }
7679 } else {
7680 timeout_ts = NULL;
7681 }
7682
7683 if (arg4) {
7684 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7685 if (!target_set) {
7686 unlock_user(target_pfd, arg1, 0);
7687 goto efault;
7688 }
7689 target_to_host_sigset(set, target_set);
7690 } else {
7691 set = NULL;
7692 }
7693
7694 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7695
7696 if (!is_error(ret) && arg3) {
7697 host_to_target_timespec(arg3, timeout_ts);
7698 }
7699 if (arg4) {
7700 unlock_user(target_set, arg4, 0);
7701 }
7702 } else
7703# endif
7704 ret = get_errno(poll(pfd, nfds, timeout));
7705
bellard9de5e442003-03-23 16:49:39 +00007706 if (!is_error(ret)) {
7707 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007708 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007709 }
7710 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007711 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007712 }
7713 break;
thse5febef2007-04-01 18:31:35 +00007714#endif
bellard31e31b82003-02-18 22:55:36 +00007715 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007716 /* NOTE: the flock constant seems to be the same for every
7717 Linux platform */
7718 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007719 break;
7720 case TARGET_NR_readv:
7721 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007722 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7723 if (vec != NULL) {
7724 ret = get_errno(readv(arg1, vec, arg3));
7725 unlock_iovec(vec, arg2, arg3, 1);
7726 } else {
7727 ret = -host_to_target_errno(errno);
7728 }
bellard31e31b82003-02-18 22:55:36 +00007729 }
7730 break;
7731 case TARGET_NR_writev:
7732 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007733 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7734 if (vec != NULL) {
7735 ret = get_errno(writev(arg1, vec, arg3));
7736 unlock_iovec(vec, arg2, arg3, 0);
7737 } else {
7738 ret = -host_to_target_errno(errno);
7739 }
bellard31e31b82003-02-18 22:55:36 +00007740 }
7741 break;
7742 case TARGET_NR_getsid:
7743 ret = get_errno(getsid(arg1));
7744 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007745#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007746 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007747 ret = get_errno(fdatasync(arg1));
7748 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007749#endif
bellard31e31b82003-02-18 22:55:36 +00007750 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007751 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007752 return value. */
ths0da46a62007-10-20 20:23:07 +00007753 ret = -TARGET_ENOTDIR;
7754 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007755 case TARGET_NR_sched_getaffinity:
7756 {
7757 unsigned int mask_size;
7758 unsigned long *mask;
7759
7760 /*
7761 * sched_getaffinity needs multiples of ulong, so need to take
7762 * care of mismatches between target ulong and host ulong sizes.
7763 */
7764 if (arg2 & (sizeof(abi_ulong) - 1)) {
7765 ret = -TARGET_EINVAL;
7766 break;
7767 }
7768 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7769
7770 mask = alloca(mask_size);
7771 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7772
7773 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007774 if (ret > arg2) {
7775 /* More data returned than the caller's buffer will fit.
7776 * This only happens if sizeof(abi_long) < sizeof(long)
7777 * and the caller passed us a buffer holding an odd number
7778 * of abi_longs. If the host kernel is actually using the
7779 * extra 4 bytes then fail EINVAL; otherwise we can just
7780 * ignore them and only copy the interesting part.
7781 */
7782 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7783 if (numcpus > arg2 * 8) {
7784 ret = -TARGET_EINVAL;
7785 break;
7786 }
7787 ret = arg2;
7788 }
7789
Mike McCormackcd18f052011-04-18 14:43:36 +09007790 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007791 goto efault;
7792 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007793 }
7794 }
7795 break;
7796 case TARGET_NR_sched_setaffinity:
7797 {
7798 unsigned int mask_size;
7799 unsigned long *mask;
7800
7801 /*
7802 * sched_setaffinity needs multiples of ulong, so need to take
7803 * care of mismatches between target ulong and host ulong sizes.
7804 */
7805 if (arg2 & (sizeof(abi_ulong) - 1)) {
7806 ret = -TARGET_EINVAL;
7807 break;
7808 }
7809 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7810
7811 mask = alloca(mask_size);
7812 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7813 goto efault;
7814 }
7815 memcpy(mask, p, arg2);
7816 unlock_user_struct(p, arg2, 0);
7817
7818 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7819 }
7820 break;
bellard31e31b82003-02-18 22:55:36 +00007821 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007822 {
pbrook53a59602006-03-25 19:31:22 +00007823 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007824 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007825
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007826 if (arg2 == 0) {
7827 return -TARGET_EINVAL;
7828 }
bellard579a97f2007-11-11 14:26:47 +00007829 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7830 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007831 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007832 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007833 ret = get_errno(sched_setparam(arg1, &schp));
7834 }
7835 break;
bellard31e31b82003-02-18 22:55:36 +00007836 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007837 {
pbrook53a59602006-03-25 19:31:22 +00007838 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007839 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007840
7841 if (arg2 == 0) {
7842 return -TARGET_EINVAL;
7843 }
bellard5cd43932003-03-29 16:54:36 +00007844 ret = get_errno(sched_getparam(arg1, &schp));
7845 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007846 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7847 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007848 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007849 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007850 }
7851 }
7852 break;
bellard31e31b82003-02-18 22:55:36 +00007853 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007854 {
pbrook53a59602006-03-25 19:31:22 +00007855 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007856 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007857 if (arg3 == 0) {
7858 return -TARGET_EINVAL;
7859 }
bellard579a97f2007-11-11 14:26:47 +00007860 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7861 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007862 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007863 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007864 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7865 }
7866 break;
bellard31e31b82003-02-18 22:55:36 +00007867 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007868 ret = get_errno(sched_getscheduler(arg1));
7869 break;
bellard31e31b82003-02-18 22:55:36 +00007870 case TARGET_NR_sched_yield:
7871 ret = get_errno(sched_yield());
7872 break;
7873 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007874 ret = get_errno(sched_get_priority_max(arg1));
7875 break;
bellard31e31b82003-02-18 22:55:36 +00007876 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007877 ret = get_errno(sched_get_priority_min(arg1));
7878 break;
bellard31e31b82003-02-18 22:55:36 +00007879 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007880 {
bellard5cd43932003-03-29 16:54:36 +00007881 struct timespec ts;
7882 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7883 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05007884 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007885 }
7886 }
7887 break;
bellard31e31b82003-02-18 22:55:36 +00007888 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007889 {
bellard1b6b0292003-03-22 17:31:38 +00007890 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007891 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007892 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007893 if (is_error(ret) && arg2) {
7894 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007895 }
7896 }
7897 break;
thse5febef2007-04-01 18:31:35 +00007898#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007899 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007900 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007901#endif
7902#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007903 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007904 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007905#endif
bellard31e31b82003-02-18 22:55:36 +00007906 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007907 switch (arg1) {
7908 case PR_GET_PDEATHSIG:
7909 {
7910 int deathsig;
7911 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7912 if (!is_error(ret) && arg2
7913 && put_user_ual(deathsig, arg2)) {
7914 goto efault;
thse5574482007-02-11 20:03:13 +00007915 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007916 break;
7917 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007918#ifdef PR_GET_NAME
7919 case PR_GET_NAME:
7920 {
7921 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7922 if (!name) {
7923 goto efault;
7924 }
7925 ret = get_errno(prctl(arg1, (unsigned long)name,
7926 arg3, arg4, arg5));
7927 unlock_user(name, arg2, 16);
7928 break;
7929 }
7930 case PR_SET_NAME:
7931 {
7932 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7933 if (!name) {
7934 goto efault;
7935 }
7936 ret = get_errno(prctl(arg1, (unsigned long)name,
7937 arg3, arg4, arg5));
7938 unlock_user(name, arg2, 0);
7939 break;
7940 }
7941#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007942 default:
7943 /* Most prctl options have no pointer arguments */
7944 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7945 break;
7946 }
ths39b9aae2007-02-11 18:36:44 +00007947 break;
bellardd2fd1af2007-11-14 18:08:56 +00007948#ifdef TARGET_NR_arch_prctl
7949 case TARGET_NR_arch_prctl:
7950#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7951 ret = do_arch_prctl(cpu_env, arg1, arg2);
7952 break;
7953#else
7954 goto unimplemented;
7955#endif
7956#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007957#ifdef TARGET_NR_pread64
7958 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007959 if (regpairs_aligned(cpu_env)) {
7960 arg4 = arg5;
7961 arg5 = arg6;
7962 }
aurel32f2c7ba12008-03-28 22:32:06 +00007963 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7964 goto efault;
7965 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7966 unlock_user(p, arg2, ret);
7967 break;
7968 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007969 if (regpairs_aligned(cpu_env)) {
7970 arg4 = arg5;
7971 arg5 = arg6;
7972 }
aurel32f2c7ba12008-03-28 22:32:06 +00007973 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7974 goto efault;
7975 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7976 unlock_user(p, arg2, 0);
7977 break;
7978#endif
bellard31e31b82003-02-18 22:55:36 +00007979 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007980 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7981 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007982 ret = get_errno(sys_getcwd1(p, arg2));
7983 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007984 break;
7985 case TARGET_NR_capget:
7986 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007987 {
7988 struct target_user_cap_header *target_header;
7989 struct target_user_cap_data *target_data = NULL;
7990 struct __user_cap_header_struct header;
7991 struct __user_cap_data_struct data[2];
7992 struct __user_cap_data_struct *dataptr = NULL;
7993 int i, target_datalen;
7994 int data_items = 1;
7995
7996 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7997 goto efault;
7998 }
7999 header.version = tswap32(target_header->version);
8000 header.pid = tswap32(target_header->pid);
8001
Peter Maydellec864872014-03-19 16:07:30 +00008002 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008003 /* Version 2 and up takes pointer to two user_data structs */
8004 data_items = 2;
8005 }
8006
8007 target_datalen = sizeof(*target_data) * data_items;
8008
8009 if (arg2) {
8010 if (num == TARGET_NR_capget) {
8011 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8012 } else {
8013 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8014 }
8015 if (!target_data) {
8016 unlock_user_struct(target_header, arg1, 0);
8017 goto efault;
8018 }
8019
8020 if (num == TARGET_NR_capset) {
8021 for (i = 0; i < data_items; i++) {
8022 data[i].effective = tswap32(target_data[i].effective);
8023 data[i].permitted = tswap32(target_data[i].permitted);
8024 data[i].inheritable = tswap32(target_data[i].inheritable);
8025 }
8026 }
8027
8028 dataptr = data;
8029 }
8030
8031 if (num == TARGET_NR_capget) {
8032 ret = get_errno(capget(&header, dataptr));
8033 } else {
8034 ret = get_errno(capset(&header, dataptr));
8035 }
8036
8037 /* The kernel always updates version for both capget and capset */
8038 target_header->version = tswap32(header.version);
8039 unlock_user_struct(target_header, arg1, 1);
8040
8041 if (arg2) {
8042 if (num == TARGET_NR_capget) {
8043 for (i = 0; i < data_items; i++) {
8044 target_data[i].effective = tswap32(data[i].effective);
8045 target_data[i].permitted = tswap32(data[i].permitted);
8046 target_data[i].inheritable = tswap32(data[i].inheritable);
8047 }
8048 unlock_user(target_data, arg2, target_datalen);
8049 } else {
8050 unlock_user(target_data, arg2, 0);
8051 }
8052 }
8053 break;
8054 }
bellard31e31b82003-02-18 22:55:36 +00008055 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00008056#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02008057 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08008058 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01008059 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008060 break;
8061#else
bellard5cd43932003-03-29 16:54:36 +00008062 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00008063#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008064
8065#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008066 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008067 {
8068 off_t *offp = NULL;
8069 off_t off;
8070 if (arg3) {
8071 ret = get_user_sal(off, arg3);
8072 if (is_error(ret)) {
8073 break;
8074 }
8075 offp = &off;
8076 }
8077 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8078 if (!is_error(ret) && arg3) {
8079 abi_long ret2 = put_user_sal(off, arg3);
8080 if (is_error(ret2)) {
8081 ret = ret2;
8082 }
8083 }
8084 break;
8085 }
8086#ifdef TARGET_NR_sendfile64
8087 case TARGET_NR_sendfile64:
8088 {
8089 off_t *offp = NULL;
8090 off_t off;
8091 if (arg3) {
8092 ret = get_user_s64(off, arg3);
8093 if (is_error(ret)) {
8094 break;
8095 }
8096 offp = &off;
8097 }
8098 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8099 if (!is_error(ret) && arg3) {
8100 abi_long ret2 = put_user_s64(off, arg3);
8101 if (is_error(ret2)) {
8102 ret = ret2;
8103 }
8104 }
8105 break;
8106 }
8107#endif
8108#else
8109 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008110#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008111 case TARGET_NR_sendfile64:
8112#endif
bellard5cd43932003-03-29 16:54:36 +00008113 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008114#endif
8115
bellardebc05482003-09-30 21:08:41 +00008116#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008117 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008118 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008119#endif
8120#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008121 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008122 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008123#endif
bellard048f6b42005-11-26 18:47:20 +00008124#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008125 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008126 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8127 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008128 break;
bellard048f6b42005-11-26 18:47:20 +00008129#endif
bellardebc05482003-09-30 21:08:41 +00008130#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008131 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008132 {
8133 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008134 int resource = target_to_host_resource(arg1);
8135 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008136 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008137 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008138 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8139 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008140 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8141 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008142 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008143 }
8144 break;
8145 }
bellardebc05482003-09-30 21:08:41 +00008146#endif
bellarda315a142005-01-30 22:59:18 +00008147#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008148 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008149 if (!(p = lock_user_string(arg1)))
8150 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008151 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8152 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008153 break;
bellarda315a142005-01-30 22:59:18 +00008154#endif
8155#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008156 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008157 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008158 break;
bellarda315a142005-01-30 22:59:18 +00008159#endif
8160#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008161 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008162 if (!(p = lock_user_string(arg1)))
8163 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008164 ret = get_errno(stat(path(p), &st));
8165 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008166 if (!is_error(ret))
8167 ret = host_to_target_stat64(cpu_env, arg2, &st);
8168 break;
bellarda315a142005-01-30 22:59:18 +00008169#endif
8170#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008171 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008172 if (!(p = lock_user_string(arg1)))
8173 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008174 ret = get_errno(lstat(path(p), &st));
8175 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008176 if (!is_error(ret))
8177 ret = host_to_target_stat64(cpu_env, arg2, &st);
8178 break;
bellarda315a142005-01-30 22:59:18 +00008179#endif
8180#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008181 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008182 ret = get_errno(fstat(arg1, &st));
8183 if (!is_error(ret))
8184 ret = host_to_target_stat64(cpu_env, arg2, &st);
8185 break;
bellardec86b0f2003-04-11 00:15:04 +00008186#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008187#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008188#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008189 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008190#endif
8191#ifdef TARGET_NR_newfstatat
8192 case TARGET_NR_newfstatat:
8193#endif
balrog6a24a772008-09-20 02:23:36 +00008194 if (!(p = lock_user_string(arg2)))
8195 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008196 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008197 if (!is_error(ret))
8198 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008199 break;
bellarda315a142005-01-30 22:59:18 +00008200#endif
bellard67867302003-11-23 17:05:30 +00008201 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008202 if (!(p = lock_user_string(arg1)))
8203 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008204 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8205 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008206 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008207#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008208 case TARGET_NR_getuid:
8209 ret = get_errno(high2lowuid(getuid()));
8210 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008211#endif
8212#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008213 case TARGET_NR_getgid:
8214 ret = get_errno(high2lowgid(getgid()));
8215 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008216#endif
8217#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008218 case TARGET_NR_geteuid:
8219 ret = get_errno(high2lowuid(geteuid()));
8220 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008221#endif
8222#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008223 case TARGET_NR_getegid:
8224 ret = get_errno(high2lowgid(getegid()));
8225 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008226#endif
bellard67867302003-11-23 17:05:30 +00008227 case TARGET_NR_setreuid:
8228 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8229 break;
8230 case TARGET_NR_setregid:
8231 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8232 break;
8233 case TARGET_NR_getgroups:
8234 {
8235 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008236 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008237 gid_t *grouplist;
8238 int i;
8239
8240 grouplist = alloca(gidsetsize * sizeof(gid_t));
8241 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008242 if (gidsetsize == 0)
8243 break;
bellard67867302003-11-23 17:05:30 +00008244 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008245 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008246 if (!target_grouplist)
8247 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008248 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008249 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008250 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008251 }
8252 }
8253 break;
8254 case TARGET_NR_setgroups:
8255 {
8256 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008257 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008258 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008259 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008260 if (gidsetsize) {
8261 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008262 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008263 if (!target_grouplist) {
8264 ret = -TARGET_EFAULT;
8265 goto fail;
8266 }
8267 for (i = 0; i < gidsetsize; i++) {
8268 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8269 }
8270 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008271 }
bellard67867302003-11-23 17:05:30 +00008272 ret = get_errno(setgroups(gidsetsize, grouplist));
8273 }
8274 break;
8275 case TARGET_NR_fchown:
8276 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8277 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008278#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008279 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008280 if (!(p = lock_user_string(arg2)))
8281 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008282 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8283 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008284 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008285 break;
8286#endif
bellard67867302003-11-23 17:05:30 +00008287#ifdef TARGET_NR_setresuid
8288 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008289 ret = get_errno(setresuid(low2highuid(arg1),
8290 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008291 low2highuid(arg3)));
8292 break;
8293#endif
8294#ifdef TARGET_NR_getresuid
8295 case TARGET_NR_getresuid:
8296 {
pbrook53a59602006-03-25 19:31:22 +00008297 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008298 ret = get_errno(getresuid(&ruid, &euid, &suid));
8299 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008300 if (put_user_id(high2lowuid(ruid), arg1)
8301 || put_user_id(high2lowuid(euid), arg2)
8302 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008303 goto efault;
bellard67867302003-11-23 17:05:30 +00008304 }
8305 }
8306 break;
8307#endif
8308#ifdef TARGET_NR_getresgid
8309 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008310 ret = get_errno(setresgid(low2highgid(arg1),
8311 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008312 low2highgid(arg3)));
8313 break;
8314#endif
8315#ifdef TARGET_NR_getresgid
8316 case TARGET_NR_getresgid:
8317 {
pbrook53a59602006-03-25 19:31:22 +00008318 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008319 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8320 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008321 if (put_user_id(high2lowgid(rgid), arg1)
8322 || put_user_id(high2lowgid(egid), arg2)
8323 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008324 goto efault;
bellard67867302003-11-23 17:05:30 +00008325 }
8326 }
8327 break;
8328#endif
8329 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008330 if (!(p = lock_user_string(arg1)))
8331 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008332 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8333 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008334 break;
8335 case TARGET_NR_setuid:
8336 ret = get_errno(setuid(low2highuid(arg1)));
8337 break;
8338 case TARGET_NR_setgid:
8339 ret = get_errno(setgid(low2highgid(arg1)));
8340 break;
8341 case TARGET_NR_setfsuid:
8342 ret = get_errno(setfsuid(arg1));
8343 break;
8344 case TARGET_NR_setfsgid:
8345 ret = get_errno(setfsgid(arg1));
8346 break;
bellard67867302003-11-23 17:05:30 +00008347
bellarda315a142005-01-30 22:59:18 +00008348#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008349 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008350 if (!(p = lock_user_string(arg1)))
8351 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008352 ret = get_errno(lchown(p, arg2, arg3));
8353 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008354 break;
bellarda315a142005-01-30 22:59:18 +00008355#endif
8356#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008357 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008358 ret = get_errno(getuid());
8359 break;
bellarda315a142005-01-30 22:59:18 +00008360#endif
aurel3264b4d282008-11-14 17:20:15 +00008361
8362#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8363 /* Alpha specific */
8364 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008365 {
8366 uid_t euid;
8367 euid=geteuid();
8368 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8369 }
aurel3264b4d282008-11-14 17:20:15 +00008370 ret = get_errno(getuid());
8371 break;
8372#endif
8373#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8374 /* Alpha specific */
8375 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008376 {
8377 uid_t egid;
8378 egid=getegid();
8379 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8380 }
aurel3264b4d282008-11-14 17:20:15 +00008381 ret = get_errno(getgid());
8382 break;
8383#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008384#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8385 /* Alpha specific */
8386 case TARGET_NR_osf_getsysinfo:
8387 ret = -TARGET_EOPNOTSUPP;
8388 switch (arg1) {
8389 case TARGET_GSI_IEEE_FP_CONTROL:
8390 {
8391 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8392
8393 /* Copied from linux ieee_fpcr_to_swcr. */
8394 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8395 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8396 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8397 | SWCR_TRAP_ENABLE_DZE
8398 | SWCR_TRAP_ENABLE_OVF);
8399 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8400 | SWCR_TRAP_ENABLE_INE);
8401 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8402 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8403
8404 if (put_user_u64 (swcr, arg2))
8405 goto efault;
8406 ret = 0;
8407 }
8408 break;
8409
8410 /* case GSI_IEEE_STATE_AT_SIGNAL:
8411 -- Not implemented in linux kernel.
8412 case GSI_UACPROC:
8413 -- Retrieves current unaligned access state; not much used.
8414 case GSI_PROC_TYPE:
8415 -- Retrieves implver information; surely not used.
8416 case GSI_GET_HWRPB:
8417 -- Grabs a copy of the HWRPB; surely not used.
8418 */
8419 }
8420 break;
8421#endif
8422#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8423 /* Alpha specific */
8424 case TARGET_NR_osf_setsysinfo:
8425 ret = -TARGET_EOPNOTSUPP;
8426 switch (arg1) {
8427 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008428 {
8429 uint64_t swcr, fpcr, orig_fpcr;
8430
Richard Henderson6e06d512012-06-01 09:08:21 -07008431 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008432 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008433 }
8434 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008435 fpcr = orig_fpcr & FPCR_DYN_MASK;
8436
8437 /* Copied from linux ieee_swcr_to_fpcr. */
8438 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8439 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8440 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8441 | SWCR_TRAP_ENABLE_DZE
8442 | SWCR_TRAP_ENABLE_OVF)) << 48;
8443 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8444 | SWCR_TRAP_ENABLE_INE)) << 57;
8445 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8446 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8447
Richard Henderson6e06d512012-06-01 09:08:21 -07008448 cpu_alpha_store_fpcr(cpu_env, fpcr);
8449 ret = 0;
8450 }
8451 break;
8452
8453 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8454 {
8455 uint64_t exc, fpcr, orig_fpcr;
8456 int si_code;
8457
8458 if (get_user_u64(exc, arg2)) {
8459 goto efault;
8460 }
8461
8462 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8463
8464 /* We only add to the exception status here. */
8465 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8466
8467 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008468 ret = 0;
8469
Richard Henderson6e06d512012-06-01 09:08:21 -07008470 /* Old exceptions are not signaled. */
8471 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008472
Richard Henderson6e06d512012-06-01 09:08:21 -07008473 /* If any exceptions set by this call,
8474 and are unmasked, send a signal. */
8475 si_code = 0;
8476 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8477 si_code = TARGET_FPE_FLTRES;
8478 }
8479 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8480 si_code = TARGET_FPE_FLTUND;
8481 }
8482 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8483 si_code = TARGET_FPE_FLTOVF;
8484 }
8485 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8486 si_code = TARGET_FPE_FLTDIV;
8487 }
8488 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8489 si_code = TARGET_FPE_FLTINV;
8490 }
8491 if (si_code != 0) {
8492 target_siginfo_t info;
8493 info.si_signo = SIGFPE;
8494 info.si_errno = 0;
8495 info.si_code = si_code;
8496 info._sifields._sigfault._addr
8497 = ((CPUArchState *)cpu_env)->pc;
8498 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008499 }
8500 }
8501 break;
8502
8503 /* case SSI_NVPAIRS:
8504 -- Used with SSIN_UACPROC to enable unaligned accesses.
8505 case SSI_IEEE_STATE_AT_SIGNAL:
8506 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8507 -- Not implemented in linux kernel
8508 */
8509 }
8510 break;
8511#endif
8512#ifdef TARGET_NR_osf_sigprocmask
8513 /* Alpha specific. */
8514 case TARGET_NR_osf_sigprocmask:
8515 {
8516 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008517 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008518 sigset_t set, oldset;
8519
8520 switch(arg1) {
8521 case TARGET_SIG_BLOCK:
8522 how = SIG_BLOCK;
8523 break;
8524 case TARGET_SIG_UNBLOCK:
8525 how = SIG_UNBLOCK;
8526 break;
8527 case TARGET_SIG_SETMASK:
8528 how = SIG_SETMASK;
8529 break;
8530 default:
8531 ret = -TARGET_EINVAL;
8532 goto fail;
8533 }
8534 mask = arg2;
8535 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008536 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008537 host_to_target_old_sigset(&mask, &oldset);
8538 ret = mask;
8539 }
8540 break;
8541#endif
aurel3264b4d282008-11-14 17:20:15 +00008542
bellarda315a142005-01-30 22:59:18 +00008543#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008544 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008545 ret = get_errno(getgid());
8546 break;
bellarda315a142005-01-30 22:59:18 +00008547#endif
8548#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008549 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008550 ret = get_errno(geteuid());
8551 break;
bellarda315a142005-01-30 22:59:18 +00008552#endif
8553#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008554 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008555 ret = get_errno(getegid());
8556 break;
bellarda315a142005-01-30 22:59:18 +00008557#endif
8558#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008559 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008560 ret = get_errno(setreuid(arg1, arg2));
8561 break;
bellarda315a142005-01-30 22:59:18 +00008562#endif
8563#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008564 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008565 ret = get_errno(setregid(arg1, arg2));
8566 break;
bellarda315a142005-01-30 22:59:18 +00008567#endif
8568#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008569 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008570 {
8571 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008572 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008573 gid_t *grouplist;
8574 int i;
8575
8576 grouplist = alloca(gidsetsize * sizeof(gid_t));
8577 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008578 if (gidsetsize == 0)
8579 break;
bellard99c475a2005-01-31 20:45:13 +00008580 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008581 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8582 if (!target_grouplist) {
8583 ret = -TARGET_EFAULT;
8584 goto fail;
8585 }
balroga2155fc2008-09-20 02:12:08 +00008586 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008587 target_grouplist[i] = tswap32(grouplist[i]);
8588 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008589 }
8590 }
8591 break;
bellarda315a142005-01-30 22:59:18 +00008592#endif
8593#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008594 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008595 {
8596 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008597 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008598 gid_t *grouplist;
8599 int i;
ths3b46e622007-09-17 08:09:54 +00008600
bellard99c475a2005-01-31 20:45:13 +00008601 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008602 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8603 if (!target_grouplist) {
8604 ret = -TARGET_EFAULT;
8605 goto fail;
8606 }
bellard99c475a2005-01-31 20:45:13 +00008607 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008608 grouplist[i] = tswap32(target_grouplist[i]);
8609 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008610 ret = get_errno(setgroups(gidsetsize, grouplist));
8611 }
8612 break;
bellarda315a142005-01-30 22:59:18 +00008613#endif
8614#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008615 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008616 ret = get_errno(fchown(arg1, arg2, arg3));
8617 break;
bellarda315a142005-01-30 22:59:18 +00008618#endif
8619#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008620 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008621 ret = get_errno(setresuid(arg1, arg2, arg3));
8622 break;
bellarda315a142005-01-30 22:59:18 +00008623#endif
8624#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008625 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008626 {
pbrook53a59602006-03-25 19:31:22 +00008627 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008628 ret = get_errno(getresuid(&ruid, &euid, &suid));
8629 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008630 if (put_user_u32(ruid, arg1)
8631 || put_user_u32(euid, arg2)
8632 || put_user_u32(suid, arg3))
8633 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008634 }
8635 }
8636 break;
bellarda315a142005-01-30 22:59:18 +00008637#endif
8638#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008639 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008640 ret = get_errno(setresgid(arg1, arg2, arg3));
8641 break;
bellarda315a142005-01-30 22:59:18 +00008642#endif
8643#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008644 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008645 {
pbrook53a59602006-03-25 19:31:22 +00008646 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008647 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8648 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008649 if (put_user_u32(rgid, arg1)
8650 || put_user_u32(egid, arg2)
8651 || put_user_u32(sgid, arg3))
8652 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008653 }
8654 }
8655 break;
bellarda315a142005-01-30 22:59:18 +00008656#endif
8657#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008658 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008659 if (!(p = lock_user_string(arg1)))
8660 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008661 ret = get_errno(chown(p, arg2, arg3));
8662 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008663 break;
bellarda315a142005-01-30 22:59:18 +00008664#endif
8665#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008666 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008667 ret = get_errno(setuid(arg1));
8668 break;
bellarda315a142005-01-30 22:59:18 +00008669#endif
8670#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008671 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008672 ret = get_errno(setgid(arg1));
8673 break;
bellarda315a142005-01-30 22:59:18 +00008674#endif
8675#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008676 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008677 ret = get_errno(setfsuid(arg1));
8678 break;
bellarda315a142005-01-30 22:59:18 +00008679#endif
8680#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008681 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008682 ret = get_errno(setfsgid(arg1));
8683 break;
bellarda315a142005-01-30 22:59:18 +00008684#endif
bellard67867302003-11-23 17:05:30 +00008685
bellard31e31b82003-02-18 22:55:36 +00008686 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008687 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008688#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008689 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008690 {
8691 void *a;
8692 ret = -TARGET_EFAULT;
8693 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8694 goto efault;
8695 if (!(p = lock_user_string(arg3)))
8696 goto mincore_fail;
8697 ret = get_errno(mincore(a, arg2, p));
8698 unlock_user(p, arg3, ret);
8699 mincore_fail:
8700 unlock_user(a, arg1, 0);
8701 }
8702 break;
bellardffa65c32004-01-04 23:57:22 +00008703#endif
aurel32408321b2008-10-01 21:46:32 +00008704#ifdef TARGET_NR_arm_fadvise64_64
8705 case TARGET_NR_arm_fadvise64_64:
8706 {
8707 /*
8708 * arm_fadvise64_64 looks like fadvise64_64 but
8709 * with different argument order
8710 */
8711 abi_long temp;
8712 temp = arg3;
8713 arg3 = arg4;
8714 arg4 = temp;
8715 }
8716#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008717#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008718#ifdef TARGET_NR_fadvise64_64
8719 case TARGET_NR_fadvise64_64:
8720#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008721#ifdef TARGET_NR_fadvise64
8722 case TARGET_NR_fadvise64:
8723#endif
8724#ifdef TARGET_S390X
8725 switch (arg4) {
8726 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8727 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8728 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8729 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8730 default: break;
8731 }
8732#endif
8733 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008734 break;
8735#endif
bellardffa65c32004-01-04 23:57:22 +00008736#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008737 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008738 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008739 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008740 This will break MADV_DONTNEED.
8741 This is a hint, so ignoring and returning success is ok. */
8742 ret = get_errno(0);
8743 break;
bellardffa65c32004-01-04 23:57:22 +00008744#endif
blueswir1992f48a2007-10-14 16:27:31 +00008745#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008746 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008747 {
thsb1e341e2007-03-20 21:50:52 +00008748 int cmd;
bellard77e46722003-04-29 20:39:06 +00008749 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008750 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008751#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008752 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008753#endif
bellard77e46722003-04-29 20:39:06 +00008754
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008755 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008756 if (cmd == -TARGET_EINVAL) {
8757 ret = cmd;
8758 break;
8759 }
thsb1e341e2007-03-20 21:50:52 +00008760
bellard60cd49d2003-03-16 22:53:56 +00008761 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008762 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008763#ifdef TARGET_ARM
8764 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008765 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8766 goto efault;
ths58134272007-03-31 18:59:32 +00008767 fl.l_type = tswap16(target_efl->l_type);
8768 fl.l_whence = tswap16(target_efl->l_whence);
8769 fl.l_start = tswap64(target_efl->l_start);
8770 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008771 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008772 unlock_user_struct(target_efl, arg3, 0);
8773 } else
8774#endif
8775 {
bellard9ee1fa22007-11-11 15:11:19 +00008776 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8777 goto efault;
ths58134272007-03-31 18:59:32 +00008778 fl.l_type = tswap16(target_fl->l_type);
8779 fl.l_whence = tswap16(target_fl->l_whence);
8780 fl.l_start = tswap64(target_fl->l_start);
8781 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008782 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008783 unlock_user_struct(target_fl, arg3, 0);
8784 }
thsb1e341e2007-03-20 21:50:52 +00008785 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008786 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008787#ifdef TARGET_ARM
8788 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008789 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8790 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008791 target_efl->l_type = tswap16(fl.l_type);
8792 target_efl->l_whence = tswap16(fl.l_whence);
8793 target_efl->l_start = tswap64(fl.l_start);
8794 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008795 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008796 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008797 } else
8798#endif
8799 {
bellard9ee1fa22007-11-11 15:11:19 +00008800 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8801 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008802 target_fl->l_type = tswap16(fl.l_type);
8803 target_fl->l_whence = tswap16(fl.l_whence);
8804 target_fl->l_start = tswap64(fl.l_start);
8805 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008806 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008807 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008808 }
bellard77e46722003-04-29 20:39:06 +00008809 }
8810 break;
8811
thsb1e341e2007-03-20 21:50:52 +00008812 case TARGET_F_SETLK64:
8813 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008814#ifdef TARGET_ARM
8815 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008816 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8817 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008818 fl.l_type = tswap16(target_efl->l_type);
8819 fl.l_whence = tswap16(target_efl->l_whence);
8820 fl.l_start = tswap64(target_efl->l_start);
8821 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008822 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008823 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008824 } else
8825#endif
8826 {
bellard9ee1fa22007-11-11 15:11:19 +00008827 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8828 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008829 fl.l_type = tswap16(target_fl->l_type);
8830 fl.l_whence = tswap16(target_fl->l_whence);
8831 fl.l_start = tswap64(target_fl->l_start);
8832 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008833 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008834 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008835 }
thsb1e341e2007-03-20 21:50:52 +00008836 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008837 break;
bellard60cd49d2003-03-16 22:53:56 +00008838 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008839 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008840 break;
8841 }
bellard77e46722003-04-29 20:39:06 +00008842 break;
8843 }
bellard60cd49d2003-03-16 22:53:56 +00008844#endif
ths7d600c82006-12-08 01:32:58 +00008845#ifdef TARGET_NR_cacheflush
8846 case TARGET_NR_cacheflush:
8847 /* self-modifying code is handled automatically, so nothing needed */
8848 ret = 0;
8849 break;
8850#endif
bellardebc05482003-09-30 21:08:41 +00008851#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008852 case TARGET_NR_security:
8853 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008854#endif
bellardc573ff62004-01-04 15:51:36 +00008855#ifdef TARGET_NR_getpagesize
8856 case TARGET_NR_getpagesize:
8857 ret = TARGET_PAGE_SIZE;
8858 break;
8859#endif
bellard31e31b82003-02-18 22:55:36 +00008860 case TARGET_NR_gettid:
8861 ret = get_errno(gettid());
8862 break;
thse5febef2007-04-01 18:31:35 +00008863#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008864 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008865#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008866 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008867 arg2 = arg3;
8868 arg3 = arg4;
8869 arg4 = arg5;
8870 }
aurel322054ac92008-10-13 21:08:07 +00008871 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8872#else
8873 ret = get_errno(readahead(arg1, arg2, arg3));
8874#endif
8875 break;
thse5febef2007-04-01 18:31:35 +00008876#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008877#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008878#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008879 case TARGET_NR_listxattr:
8880 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008881 {
8882 void *p, *b = 0;
8883 if (arg2) {
8884 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8885 if (!b) {
8886 ret = -TARGET_EFAULT;
8887 break;
8888 }
8889 }
8890 p = lock_user_string(arg1);
8891 if (p) {
8892 if (num == TARGET_NR_listxattr) {
8893 ret = get_errno(listxattr(p, b, arg3));
8894 } else {
8895 ret = get_errno(llistxattr(p, b, arg3));
8896 }
8897 } else {
8898 ret = -TARGET_EFAULT;
8899 }
8900 unlock_user(p, arg1, 0);
8901 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008902 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008903 }
8904 case TARGET_NR_flistxattr:
8905 {
8906 void *b = 0;
8907 if (arg2) {
8908 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8909 if (!b) {
8910 ret = -TARGET_EFAULT;
8911 break;
8912 }
8913 }
8914 ret = get_errno(flistxattr(arg1, b, arg3));
8915 unlock_user(b, arg2, arg3);
8916 break;
8917 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008918 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008919 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008920 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008921 void *p, *n, *v = 0;
8922 if (arg3) {
8923 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8924 if (!v) {
8925 ret = -TARGET_EFAULT;
8926 break;
8927 }
8928 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008929 p = lock_user_string(arg1);
8930 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008931 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008932 if (num == TARGET_NR_setxattr) {
8933 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8934 } else {
8935 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8936 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008937 } else {
8938 ret = -TARGET_EFAULT;
8939 }
8940 unlock_user(p, arg1, 0);
8941 unlock_user(n, arg2, 0);
8942 unlock_user(v, arg3, 0);
8943 }
8944 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008945 case TARGET_NR_fsetxattr:
8946 {
8947 void *n, *v = 0;
8948 if (arg3) {
8949 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8950 if (!v) {
8951 ret = -TARGET_EFAULT;
8952 break;
8953 }
8954 }
8955 n = lock_user_string(arg2);
8956 if (n) {
8957 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8958 } else {
8959 ret = -TARGET_EFAULT;
8960 }
8961 unlock_user(n, arg2, 0);
8962 unlock_user(v, arg3, 0);
8963 }
8964 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008965 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008966 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008967 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008968 void *p, *n, *v = 0;
8969 if (arg3) {
8970 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8971 if (!v) {
8972 ret = -TARGET_EFAULT;
8973 break;
8974 }
8975 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008976 p = lock_user_string(arg1);
8977 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008978 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008979 if (num == TARGET_NR_getxattr) {
8980 ret = get_errno(getxattr(p, n, v, arg4));
8981 } else {
8982 ret = get_errno(lgetxattr(p, n, v, arg4));
8983 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008984 } else {
8985 ret = -TARGET_EFAULT;
8986 }
8987 unlock_user(p, arg1, 0);
8988 unlock_user(n, arg2, 0);
8989 unlock_user(v, arg3, arg4);
8990 }
8991 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008992 case TARGET_NR_fgetxattr:
8993 {
8994 void *n, *v = 0;
8995 if (arg3) {
8996 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8997 if (!v) {
8998 ret = -TARGET_EFAULT;
8999 break;
9000 }
9001 }
9002 n = lock_user_string(arg2);
9003 if (n) {
9004 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9005 } else {
9006 ret = -TARGET_EFAULT;
9007 }
9008 unlock_user(n, arg2, 0);
9009 unlock_user(v, arg3, arg4);
9010 }
9011 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009012 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009013 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009014 {
9015 void *p, *n;
9016 p = lock_user_string(arg1);
9017 n = lock_user_string(arg2);
9018 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009019 if (num == TARGET_NR_removexattr) {
9020 ret = get_errno(removexattr(p, n));
9021 } else {
9022 ret = get_errno(lremovexattr(p, n));
9023 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009024 } else {
9025 ret = -TARGET_EFAULT;
9026 }
9027 unlock_user(p, arg1, 0);
9028 unlock_user(n, arg2, 0);
9029 }
9030 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009031 case TARGET_NR_fremovexattr:
9032 {
9033 void *n;
9034 n = lock_user_string(arg2);
9035 if (n) {
9036 ret = get_errno(fremovexattr(arg1, n));
9037 } else {
9038 ret = -TARGET_EFAULT;
9039 }
9040 unlock_user(n, arg2, 0);
9041 }
9042 break;
bellardebc05482003-09-30 21:08:41 +00009043#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009044#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009045#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009046 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009047#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009048 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009049 ret = 0;
9050 break;
edgar_iglef967792009-01-07 14:19:38 +00009051#elif defined(TARGET_CRIS)
9052 if (arg1 & 0xff)
9053 ret = -TARGET_EINVAL;
9054 else {
9055 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9056 ret = 0;
9057 }
9058 break;
bellard8d18e892007-11-14 15:18:40 +00009059#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9060 ret = do_set_thread_area(cpu_env, arg1);
9061 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009062#elif defined(TARGET_M68K)
9063 {
Andreas Färber0429a972013-08-26 18:14:44 +02009064 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009065 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009066 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009067 break;
9068 }
ths6f5b89a2007-03-02 20:48:00 +00009069#else
9070 goto unimplemented_nowarn;
9071#endif
9072#endif
9073#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009074 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009075#if defined(TARGET_I386) && defined(TARGET_ABI32)
9076 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009077 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009078#elif defined(TARGET_M68K)
9079 {
Andreas Färber0429a972013-08-26 18:14:44 +02009080 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009081 ret = ts->tp_value;
9082 break;
9083 }
bellard8d18e892007-11-14 15:18:40 +00009084#else
bellard5cd43932003-03-29 16:54:36 +00009085 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009086#endif
bellard8d18e892007-11-14 15:18:40 +00009087#endif
bellard48dc41e2006-06-21 18:15:50 +00009088#ifdef TARGET_NR_getdomainname
9089 case TARGET_NR_getdomainname:
9090 goto unimplemented_nowarn;
9091#endif
ths6f5b89a2007-03-02 20:48:00 +00009092
thsb5906f92007-03-19 13:32:45 +00009093#ifdef TARGET_NR_clock_gettime
9094 case TARGET_NR_clock_gettime:
9095 {
9096 struct timespec ts;
9097 ret = get_errno(clock_gettime(arg1, &ts));
9098 if (!is_error(ret)) {
9099 host_to_target_timespec(arg2, &ts);
9100 }
9101 break;
9102 }
9103#endif
9104#ifdef TARGET_NR_clock_getres
9105 case TARGET_NR_clock_getres:
9106 {
9107 struct timespec ts;
9108 ret = get_errno(clock_getres(arg1, &ts));
9109 if (!is_error(ret)) {
9110 host_to_target_timespec(arg2, &ts);
9111 }
9112 break;
9113 }
9114#endif
pbrook63d76512008-05-29 13:43:29 +00009115#ifdef TARGET_NR_clock_nanosleep
9116 case TARGET_NR_clock_nanosleep:
9117 {
9118 struct timespec ts;
9119 target_to_host_timespec(&ts, arg3);
9120 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9121 if (arg4)
9122 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009123
9124#if defined(TARGET_PPC)
9125 /* clock_nanosleep is odd in that it returns positive errno values.
9126 * On PPC, CR0 bit 3 should be set in such a situation. */
9127 if (ret) {
9128 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9129 }
9130#endif
pbrook63d76512008-05-29 13:43:29 +00009131 break;
9132 }
9133#endif
thsb5906f92007-03-19 13:32:45 +00009134
ths6f5b89a2007-03-02 20:48:00 +00009135#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9136 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009137 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9138 break;
ths6f5b89a2007-03-02 20:48:00 +00009139#endif
9140
ths3ae43202007-09-16 21:39:48 +00009141#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009142 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009143 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009144 break;
9145#endif
9146
ths3ae43202007-09-16 21:39:48 +00009147#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009148 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009149 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9150 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009151 break;
9152#endif
9153
ths4f2b1fe2007-06-21 21:57:12 +00009154#ifdef TARGET_NR_set_robust_list
9155 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009156 case TARGET_NR_get_robust_list:
9157 /* The ABI for supporting robust futexes has userspace pass
9158 * the kernel a pointer to a linked list which is updated by
9159 * userspace after the syscall; the list is walked by the kernel
9160 * when the thread exits. Since the linked list in QEMU guest
9161 * memory isn't a valid linked list for the host and we have
9162 * no way to reliably intercept the thread-death event, we can't
9163 * support these. Silently return ENOSYS so that guest userspace
9164 * falls back to a non-robust futex implementation (which should
9165 * be OK except in the corner case of the guest crashing while
9166 * holding a mutex that is shared with another process via
9167 * shared memory).
9168 */
9169 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009170#endif
9171
Peter Maydell1acae9f2013-07-02 14:04:12 +01009172#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009173 case TARGET_NR_utimensat:
9174 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009175 struct timespec *tsp, ts[2];
9176 if (!arg3) {
9177 tsp = NULL;
9178 } else {
9179 target_to_host_timespec(ts, arg3);
9180 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9181 tsp = ts;
9182 }
ths9007f0e2007-09-25 17:50:37 +00009183 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009184 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009185 else {
bellard579a97f2007-11-11 14:26:47 +00009186 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009187 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009188 goto fail;
9189 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009190 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009191 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009192 }
9193 }
9194 break;
9195#endif
pbrookbd0c5662008-05-29 14:34:11 +00009196 case TARGET_NR_futex:
9197 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9198 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009199#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009200 case TARGET_NR_inotify_init:
9201 ret = get_errno(sys_inotify_init());
9202 break;
9203#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009204#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009205#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9206 case TARGET_NR_inotify_init1:
9207 ret = get_errno(sys_inotify_init1(arg1));
9208 break;
9209#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009210#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009211#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009212 case TARGET_NR_inotify_add_watch:
9213 p = lock_user_string(arg2);
9214 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9215 unlock_user(p, arg2, 0);
9216 break;
9217#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009218#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009219 case TARGET_NR_inotify_rm_watch:
9220 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9221 break;
9222#endif
ths9007f0e2007-09-25 17:50:37 +00009223
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009224#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009225 case TARGET_NR_mq_open:
9226 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009227 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009228
9229 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009230 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009231 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009232 attrp = &posix_mq_attr;
9233 } else {
9234 attrp = 0;
9235 }
9236 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009237 unlock_user (p, arg1, 0);
9238 }
9239 break;
9240
9241 case TARGET_NR_mq_unlink:
9242 p = lock_user_string(arg1 - 1);
9243 ret = get_errno(mq_unlink(p));
9244 unlock_user (p, arg1, 0);
9245 break;
9246
9247 case TARGET_NR_mq_timedsend:
9248 {
9249 struct timespec ts;
9250
9251 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9252 if (arg5 != 0) {
9253 target_to_host_timespec(&ts, arg5);
9254 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9255 host_to_target_timespec(arg5, &ts);
9256 }
9257 else
9258 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9259 unlock_user (p, arg2, arg3);
9260 }
9261 break;
9262
9263 case TARGET_NR_mq_timedreceive:
9264 {
9265 struct timespec ts;
9266 unsigned int prio;
9267
9268 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9269 if (arg5 != 0) {
9270 target_to_host_timespec(&ts, arg5);
9271 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9272 host_to_target_timespec(arg5, &ts);
9273 }
9274 else
9275 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9276 unlock_user (p, arg2, arg3);
9277 if (arg4 != 0)
9278 put_user_u32(prio, arg4);
9279 }
9280 break;
9281
9282 /* Not implemented for now... */
9283/* case TARGET_NR_mq_notify: */
9284/* break; */
9285
9286 case TARGET_NR_mq_getsetattr:
9287 {
9288 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9289 ret = 0;
9290 if (arg3 != 0) {
9291 ret = mq_getattr(arg1, &posix_mq_attr_out);
9292 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9293 }
9294 if (arg2 != 0) {
9295 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9296 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9297 }
9298
9299 }
9300 break;
9301#endif
9302
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309303#ifdef CONFIG_SPLICE
9304#ifdef TARGET_NR_tee
9305 case TARGET_NR_tee:
9306 {
9307 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9308 }
9309 break;
9310#endif
9311#ifdef TARGET_NR_splice
9312 case TARGET_NR_splice:
9313 {
9314 loff_t loff_in, loff_out;
9315 loff_t *ploff_in = NULL, *ploff_out = NULL;
9316 if(arg2) {
9317 get_user_u64(loff_in, arg2);
9318 ploff_in = &loff_in;
9319 }
9320 if(arg4) {
9321 get_user_u64(loff_out, arg2);
9322 ploff_out = &loff_out;
9323 }
9324 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9325 }
9326 break;
9327#endif
9328#ifdef TARGET_NR_vmsplice
9329 case TARGET_NR_vmsplice:
9330 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009331 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9332 if (vec != NULL) {
9333 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9334 unlock_iovec(vec, arg2, arg3, 0);
9335 } else {
9336 ret = -host_to_target_errno(errno);
9337 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309338 }
9339 break;
9340#endif
9341#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009342#ifdef CONFIG_EVENTFD
9343#if defined(TARGET_NR_eventfd)
9344 case TARGET_NR_eventfd:
9345 ret = get_errno(eventfd(arg1, 0));
9346 break;
9347#endif
9348#if defined(TARGET_NR_eventfd2)
9349 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009350 {
9351 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9352 if (arg2 & TARGET_O_NONBLOCK) {
9353 host_flags |= O_NONBLOCK;
9354 }
9355 if (arg2 & TARGET_O_CLOEXEC) {
9356 host_flags |= O_CLOEXEC;
9357 }
9358 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009359 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009360 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009361#endif
9362#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009363#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9364 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009365#if TARGET_ABI_BITS == 32
9366 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9367 target_offset64(arg5, arg6)));
9368#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009369 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009370#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009371 break;
9372#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009373#if defined(CONFIG_SYNC_FILE_RANGE)
9374#if defined(TARGET_NR_sync_file_range)
9375 case TARGET_NR_sync_file_range:
9376#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009377#if defined(TARGET_MIPS)
9378 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9379 target_offset64(arg5, arg6), arg7));
9380#else
Peter Maydellc727f472011-01-06 11:05:10 +00009381 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9382 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009383#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009384#else
9385 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9386#endif
9387 break;
9388#endif
9389#if defined(TARGET_NR_sync_file_range2)
9390 case TARGET_NR_sync_file_range2:
9391 /* This is like sync_file_range but the arguments are reordered */
9392#if TARGET_ABI_BITS == 32
9393 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9394 target_offset64(arg5, arg6), arg2));
9395#else
9396 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9397#endif
9398 break;
9399#endif
9400#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009401#if defined(CONFIG_EPOLL)
9402#if defined(TARGET_NR_epoll_create)
9403 case TARGET_NR_epoll_create:
9404 ret = get_errno(epoll_create(arg1));
9405 break;
9406#endif
9407#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9408 case TARGET_NR_epoll_create1:
9409 ret = get_errno(epoll_create1(arg1));
9410 break;
9411#endif
9412#if defined(TARGET_NR_epoll_ctl)
9413 case TARGET_NR_epoll_ctl:
9414 {
9415 struct epoll_event ep;
9416 struct epoll_event *epp = 0;
9417 if (arg4) {
9418 struct target_epoll_event *target_ep;
9419 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9420 goto efault;
9421 }
9422 ep.events = tswap32(target_ep->events);
9423 /* The epoll_data_t union is just opaque data to the kernel,
9424 * so we transfer all 64 bits across and need not worry what
9425 * actual data type it is.
9426 */
9427 ep.data.u64 = tswap64(target_ep->data.u64);
9428 unlock_user_struct(target_ep, arg4, 0);
9429 epp = &ep;
9430 }
9431 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9432 break;
9433 }
9434#endif
9435
9436#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9437#define IMPLEMENT_EPOLL_PWAIT
9438#endif
9439#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9440#if defined(TARGET_NR_epoll_wait)
9441 case TARGET_NR_epoll_wait:
9442#endif
9443#if defined(IMPLEMENT_EPOLL_PWAIT)
9444 case TARGET_NR_epoll_pwait:
9445#endif
9446 {
9447 struct target_epoll_event *target_ep;
9448 struct epoll_event *ep;
9449 int epfd = arg1;
9450 int maxevents = arg3;
9451 int timeout = arg4;
9452
9453 target_ep = lock_user(VERIFY_WRITE, arg2,
9454 maxevents * sizeof(struct target_epoll_event), 1);
9455 if (!target_ep) {
9456 goto efault;
9457 }
9458
9459 ep = alloca(maxevents * sizeof(struct epoll_event));
9460
9461 switch (num) {
9462#if defined(IMPLEMENT_EPOLL_PWAIT)
9463 case TARGET_NR_epoll_pwait:
9464 {
9465 target_sigset_t *target_set;
9466 sigset_t _set, *set = &_set;
9467
9468 if (arg5) {
9469 target_set = lock_user(VERIFY_READ, arg5,
9470 sizeof(target_sigset_t), 1);
9471 if (!target_set) {
9472 unlock_user(target_ep, arg2, 0);
9473 goto efault;
9474 }
9475 target_to_host_sigset(set, target_set);
9476 unlock_user(target_set, arg5, 0);
9477 } else {
9478 set = NULL;
9479 }
9480
9481 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9482 break;
9483 }
9484#endif
9485#if defined(TARGET_NR_epoll_wait)
9486 case TARGET_NR_epoll_wait:
9487 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9488 break;
9489#endif
9490 default:
9491 ret = -TARGET_ENOSYS;
9492 }
9493 if (!is_error(ret)) {
9494 int i;
9495 for (i = 0; i < ret; i++) {
9496 target_ep[i].events = tswap32(ep[i].events);
9497 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9498 }
9499 }
9500 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9501 break;
9502 }
9503#endif
9504#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009505#ifdef TARGET_NR_prlimit64
9506 case TARGET_NR_prlimit64:
9507 {
9508 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9509 struct target_rlimit64 *target_rnew, *target_rold;
9510 struct host_rlimit64 rnew, rold, *rnewp = 0;
9511 if (arg3) {
9512 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9513 goto efault;
9514 }
9515 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9516 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9517 unlock_user_struct(target_rnew, arg3, 0);
9518 rnewp = &rnew;
9519 }
9520
9521 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9522 if (!is_error(ret) && arg4) {
9523 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9524 goto efault;
9525 }
9526 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9527 target_rold->rlim_max = tswap64(rold.rlim_max);
9528 unlock_user_struct(target_rold, arg4, 1);
9529 }
9530 break;
9531 }
9532#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009533#ifdef TARGET_NR_gethostname
9534 case TARGET_NR_gethostname:
9535 {
9536 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9537 if (name) {
9538 ret = get_errno(gethostname(name, arg2));
9539 unlock_user(name, arg1, arg2);
9540 } else {
9541 ret = -TARGET_EFAULT;
9542 }
9543 break;
9544 }
9545#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009546#ifdef TARGET_NR_atomic_cmpxchg_32
9547 case TARGET_NR_atomic_cmpxchg_32:
9548 {
9549 /* should use start_exclusive from main.c */
9550 abi_ulong mem_value;
9551 if (get_user_u32(mem_value, arg6)) {
9552 target_siginfo_t info;
9553 info.si_signo = SIGSEGV;
9554 info.si_errno = 0;
9555 info.si_code = TARGET_SEGV_MAPERR;
9556 info._sifields._sigfault._addr = arg6;
9557 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9558 ret = 0xdeadbeef;
9559
9560 }
9561 if (mem_value == arg2)
9562 put_user_u32(arg1, arg6);
9563 ret = mem_value;
9564 break;
9565 }
9566#endif
9567#ifdef TARGET_NR_atomic_barrier
9568 case TARGET_NR_atomic_barrier:
9569 {
9570 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009571 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009572 break;
9573 }
9574#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009575
9576#ifdef TARGET_NR_timer_create
9577 case TARGET_NR_timer_create:
9578 {
9579 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9580
9581 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009582 struct target_timer_t *ptarget_timer;
9583
9584 int clkid = arg1;
9585 int timer_index = next_free_host_timer();
9586
9587 if (timer_index < 0) {
9588 ret = -TARGET_EAGAIN;
9589 } else {
9590 timer_t *phtimer = g_posix_timers + timer_index;
9591
9592 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009593 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +01009594 ret = target_to_host_sigevent(phost_sevp, arg2);
9595 if (ret != 0) {
9596 break;
9597 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009598 }
9599
9600 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9601 if (ret) {
9602 phtimer = NULL;
9603 } else {
9604 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9605 goto efault;
9606 }
9607 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9608 unlock_user_struct(ptarget_timer, arg3, 1);
9609 }
9610 }
9611 break;
9612 }
9613#endif
9614
9615#ifdef TARGET_NR_timer_settime
9616 case TARGET_NR_timer_settime:
9617 {
9618 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9619 * struct itimerspec * old_value */
Alexander Grafe52a99f2014-08-22 13:56:18 +02009620 target_ulong timerid = arg1;
9621
9622 if (arg3 == 0 || timerid >= ARRAY_SIZE(g_posix_timers)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009623 ret = -TARGET_EINVAL;
9624 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009625 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009626 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9627
9628 target_to_host_itimerspec(&hspec_new, arg3);
9629 ret = get_errno(
9630 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9631 host_to_target_itimerspec(arg2, &hspec_old);
9632 }
9633 break;
9634 }
9635#endif
9636
9637#ifdef TARGET_NR_timer_gettime
9638 case TARGET_NR_timer_gettime:
9639 {
9640 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafe52a99f2014-08-22 13:56:18 +02009641 target_ulong timerid = arg1;
9642
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009643 if (!arg2) {
9644 return -TARGET_EFAULT;
Alexander Grafe52a99f2014-08-22 13:56:18 +02009645 } else if (timerid >= ARRAY_SIZE(g_posix_timers)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009646 ret = -TARGET_EINVAL;
9647 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009648 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009649 struct itimerspec hspec;
9650 ret = get_errno(timer_gettime(htimer, &hspec));
9651
9652 if (host_to_target_itimerspec(arg2, &hspec)) {
9653 ret = -TARGET_EFAULT;
9654 }
9655 }
9656 break;
9657 }
9658#endif
9659
9660#ifdef TARGET_NR_timer_getoverrun
9661 case TARGET_NR_timer_getoverrun:
9662 {
9663 /* args: timer_t timerid */
Alexander Grafe52a99f2014-08-22 13:56:18 +02009664 target_ulong timerid = arg1;
9665
9666 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009667 ret = -TARGET_EINVAL;
9668 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009669 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009670 ret = get_errno(timer_getoverrun(htimer));
9671 }
9672 break;
9673 }
9674#endif
9675
9676#ifdef TARGET_NR_timer_delete
9677 case TARGET_NR_timer_delete:
9678 {
9679 /* args: timer_t timerid */
Alexander Grafe52a99f2014-08-22 13:56:18 +02009680 target_ulong timerid = arg1;
9681
9682 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009683 ret = -TARGET_EINVAL;
9684 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009685 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009686 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +02009687 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009688 }
9689 break;
9690 }
9691#endif
9692
Riku Voipio51834342014-06-22 11:25:42 +01009693#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
9694 case TARGET_NR_timerfd_create:
9695 ret = get_errno(timerfd_create(arg1,
9696 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
9697 break;
9698#endif
9699
9700#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
9701 case TARGET_NR_timerfd_gettime:
9702 {
9703 struct itimerspec its_curr;
9704
9705 ret = get_errno(timerfd_gettime(arg1, &its_curr));
9706
9707 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
9708 goto efault;
9709 }
9710 }
9711 break;
9712#endif
9713
9714#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
9715 case TARGET_NR_timerfd_settime:
9716 {
9717 struct itimerspec its_new, its_old, *p_new;
9718
9719 if (arg3) {
9720 if (target_to_host_itimerspec(&its_new, arg3)) {
9721 goto efault;
9722 }
9723 p_new = &its_new;
9724 } else {
9725 p_new = NULL;
9726 }
9727
9728 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
9729
9730 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
9731 goto efault;
9732 }
9733 }
9734 break;
9735#endif
9736
Paul Burtonab31cda2014-06-22 11:25:43 +01009737#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
9738 case TARGET_NR_ioprio_get:
9739 ret = get_errno(ioprio_get(arg1, arg2));
9740 break;
9741#endif
9742
9743#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
9744 case TARGET_NR_ioprio_set:
9745 ret = get_errno(ioprio_set(arg1, arg2, arg3));
9746 break;
9747#endif
9748
Riku Voipio9af5c902014-08-12 15:58:57 +03009749#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
9750 case TARGET_NR_setns:
9751 ret = get_errno(setns(arg1, arg2));
9752 break;
9753#endif
9754#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
9755 case TARGET_NR_unshare:
9756 ret = get_errno(unshare(arg1));
9757 break;
9758#endif
9759
bellard31e31b82003-02-18 22:55:36 +00009760 default:
9761 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009762 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009763#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 +00009764 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009765#endif
ths0da46a62007-10-20 20:23:07 +00009766 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009767 break;
9768 }
bellard579a97f2007-11-11 14:26:47 +00009769fail:
bellardc573ff62004-01-04 15:51:36 +00009770#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009771 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009772#endif
thsb92c47c2007-11-01 00:07:38 +00009773 if(do_strace)
9774 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009775 return ret;
bellard579a97f2007-11-11 14:26:47 +00009776efault:
9777 ret = -TARGET_EFAULT;
9778 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009779}