blob: 54ce14a6113151ba925f50cd90b4343ab9b052d7 [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
Peter Maydelld39594e2016-01-26 18:17:02 +000020#include "qemu/osdep.h"
bellard31e31b82003-02-18 22:55:36 +000021#include <elf.h>
22#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010023#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000024#include <sys/ipc.h>
25#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000027#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010028#include <sys/file.h>
29#include <sys/fsuid.h>
30#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000031#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000032#include <sys/resource.h>
33#include <sys/mman.h>
34#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000035#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000036#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020037#ifdef __ia64__
38int __clone2(int (*fn)(void *), void *child_stack_base,
39 size_t stack_size, int flags, void *arg, ...);
40#endif
bellard31e31b82003-02-18 22:55:36 +000041#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000042#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000044#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000045#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000046#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000047#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000048#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000049#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000050#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020051#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000052//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000053#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000054#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020055#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000056#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020057#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030058#ifdef CONFIG_TIMERFD
59#include <sys/timerfd.h>
60#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020061#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000062#include <sys/gmon.h>
63#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030064#ifdef CONFIG_EVENTFD
65#include <sys/eventfd.h>
66#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000067#ifdef CONFIG_EPOLL
68#include <sys/epoll.h>
69#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070070#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010071#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070072#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000073#ifdef CONFIG_SENDFILE
74#include <sys/sendfile.h>
75#endif
bellard31e31b82003-02-18 22:55:36 +000076
77#define termios host_termios
78#define winsize host_winsize
79#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000080#define sgttyb host_sgttyb /* same as target */
81#define tchars host_tchars /* same as target */
82#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000083
84#include <linux/termios.h>
85#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000086#include <linux/cdrom.h>
87#include <linux/hdreg.h>
88#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000089#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000090#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030091#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000092#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000093#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000094#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020095#include <linux/fb.h>
96#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010097#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +000098#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +010099#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200100#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100101#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000102#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200103#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000104
bellard3ef693a2003-03-23 20:17:16 +0000105#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000106
pbrookd865bab2008-06-07 22:12:17 +0000107#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
108 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000109
bellard72f03902003-02-18 23:33:18 +0000110//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000111
bellard1a9353d2003-03-16 20:28:50 +0000112//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000113#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
114#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000115
bellard70a194b2003-08-11 22:20:16 +0000116
bellard70a194b2003-08-11 22:20:16 +0000117#undef _syscall0
118#undef _syscall1
119#undef _syscall2
120#undef _syscall3
121#undef _syscall4
122#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000123#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000124
bellard83fcb512006-06-14 13:37:16 +0000125#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000126static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000127{ \
128 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000129}
130
bellard83fcb512006-06-14 13:37:16 +0000131#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000132static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000133{ \
134 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000135}
136
bellard83fcb512006-06-14 13:37:16 +0000137#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000138static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000139{ \
140 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000141}
142
bellard83fcb512006-06-14 13:37:16 +0000143#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000144static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000145{ \
146 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000147}
148
bellard83fcb512006-06-14 13:37:16 +0000149#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000150static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000151{ \
152 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000153}
154
bellard83fcb512006-06-14 13:37:16 +0000155#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
156 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000157static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000158{ \
159 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000160}
bellard83fcb512006-06-14 13:37:16 +0000161
162
163#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
164 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000165static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
166 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000167{ \
168 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
169}
170
bellard70a194b2003-08-11 22:20:16 +0000171
bellard31e31b82003-02-18 22:55:36 +0000172#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000173#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000174#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000175#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000176#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000177#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000178#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000179#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000180#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000181#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000182#define __NR_sys_inotify_init __NR_inotify_init
183#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
184#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000185
Alexander Graf42a39fb2011-04-15 17:32:45 +0200186#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
187 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000188#define __NR__llseek __NR_lseek
189#endif
190
James Hogana29e5ba2014-03-25 21:51:08 +0000191/* Newer kernel ports have llseek() instead of _llseek() */
192#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
193#define TARGET_NR__llseek TARGET_NR_llseek
194#endif
195
bellard72f03902003-02-18 23:33:18 +0000196#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000197_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000198#else
ths0da46a62007-10-20 20:23:07 +0000199/* This is a replacement for the host gettid() and must return a host
200 errno. */
bellard72f03902003-02-18 23:33:18 +0000201static int gettid(void) {
202 return -ENOSYS;
203}
204#endif
Chen Gang704eff62015-08-21 05:37:33 +0800205#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000206_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100207#endif
208#if !defined(__NR_getdents) || \
209 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000210_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
211#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700212#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000213_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
214 loff_t *, res, uint, wh);
215#endif
216_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
217_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
218#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
219_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
220#endif
221#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
222_syscall2(int,sys_tkill,int,tid,int,sig)
223#endif
224#ifdef __NR_exit_group
225_syscall1(int,exit_group,int,error_code)
226#endif
227#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
228_syscall1(int,set_tid_address,int *,tidptr)
229#endif
aurel323b3f24a2009-04-15 16:12:13 +0000230#if defined(TARGET_NR_futex) && defined(__NR_futex)
231_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
232 const struct timespec *,timeout,int *,uaddr2,int,val3)
233#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500234#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
235_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
236 unsigned long *, user_mask_ptr);
237#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
238_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
239 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200240_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
241 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000242_syscall2(int, capget, struct __user_cap_header_struct *, header,
243 struct __user_cap_data_struct *, data);
244_syscall2(int, capset, struct __user_cap_header_struct *, header,
245 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100246#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
247_syscall2(int, ioprio_get, int, which, int, who)
248#endif
249#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
250_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
251#endif
aurel323b3f24a2009-04-15 16:12:13 +0000252
253static bitmask_transtbl fcntl_flags_tbl[] = {
254 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
255 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
256 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
257 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
258 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
259 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
260 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
261 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700262 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000263 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
264 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
265 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
266 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000267#if defined(O_DIRECT)
268 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
269#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700270#if defined(O_NOATIME)
271 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
272#endif
273#if defined(O_CLOEXEC)
274 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
275#endif
276#if defined(O_PATH)
277 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
278#endif
279 /* Don't terminate the list prematurely on 64-bit host+guest. */
280#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
281 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
282#endif
aurel323b3f24a2009-04-15 16:12:13 +0000283 { 0, 0, 0, 0 }
284};
285
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100286typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100287typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200288typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100289 TargetFdDataFunc host_to_target_data;
290 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100291 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200292} TargetFdTrans;
293
294static TargetFdTrans **target_fd_trans;
295
296static unsigned int target_fd_max;
297
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100298static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200299{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100300 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100301 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200302 }
303 return NULL;
304}
305
Laurent Vivier7b36f782015-10-28 21:40:44 +0100306static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
307{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100308 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100309 return target_fd_trans[fd]->target_to_host_addr;
310 }
311 return NULL;
312}
313
Laurent Viviere36800c2015-10-02 14:48:09 +0200314static void fd_trans_register(int fd, TargetFdTrans *trans)
315{
316 unsigned int oldmax;
317
318 if (fd >= target_fd_max) {
319 oldmax = target_fd_max;
320 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
321 target_fd_trans = g_realloc(target_fd_trans,
322 target_fd_max * sizeof(TargetFdTrans));
323 memset((void *)(target_fd_trans + oldmax), 0,
324 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
325 }
326 target_fd_trans[fd] = trans;
327}
328
329static void fd_trans_unregister(int fd)
330{
331 if (fd >= 0 && fd < target_fd_max) {
332 target_fd_trans[fd] = NULL;
333 }
334}
335
336static void fd_trans_dup(int oldfd, int newfd)
337{
338 fd_trans_unregister(newfd);
339 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
340 fd_trans_register(newfd, target_fd_trans[oldfd]);
341 }
342}
343
aurel323b3f24a2009-04-15 16:12:13 +0000344static int sys_getcwd1(char *buf, size_t size)
345{
346 if (getcwd(buf, size) == NULL) {
347 /* getcwd() sets errno */
348 return (-1);
349 }
aurel32aaf4ad32009-04-16 14:17:14 +0000350 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000351}
352
Alexander Graff4c69012011-09-25 06:25:35 +0200353static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000354{
355 /*
356 * open(2) has extra parameter 'mode' when called with
357 * flag O_CREAT.
358 */
359 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000360 return (openat(dirfd, pathname, flags, mode));
361 }
362 return (openat(dirfd, pathname, flags));
363}
Riku Voipioebc996f2009-04-21 15:01:51 +0300364
Peter Maydell1acae9f2013-07-02 14:04:12 +0100365#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300366#ifdef CONFIG_UTIMENSAT
367static int sys_utimensat(int dirfd, const char *pathname,
368 const struct timespec times[2], int flags)
369{
370 if (pathname == NULL)
371 return futimens(dirfd, times);
372 else
373 return utimensat(dirfd, pathname, times, flags);
374}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100375#elif defined(__NR_utimensat)
376#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000377_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
378 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100379#else
380static int sys_utimensat(int dirfd, const char *pathname,
381 const struct timespec times[2], int flags)
382{
383 errno = ENOSYS;
384 return -1;
385}
ths9007f0e2007-09-25 17:50:37 +0000386#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100387#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000388
389#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000390#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000391
aurel3239b59762008-10-01 21:46:50 +0000392#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000393static int sys_inotify_init(void)
394{
395 return (inotify_init());
396}
aurel3239b59762008-10-01 21:46:50 +0000397#endif
398#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000399static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
400{
401 return (inotify_add_watch(fd, pathname, mask));
402}
aurel3239b59762008-10-01 21:46:50 +0000403#endif
404#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000405static int sys_inotify_rm_watch(int fd, int32_t wd)
406{
aurel328690e422009-04-17 13:50:32 +0000407 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000408}
aurel3239b59762008-10-01 21:46:50 +0000409#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000410#ifdef CONFIG_INOTIFY1
411#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
412static int sys_inotify_init1(int flags)
413{
414 return (inotify_init1(flags));
415}
416#endif
417#endif
aurel323b3f24a2009-04-15 16:12:13 +0000418#else
419/* Userspace can usually survive runtime without inotify */
420#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000421#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000422#undef TARGET_NR_inotify_add_watch
423#undef TARGET_NR_inotify_rm_watch
424#endif /* CONFIG_INOTIFY */
425
Mike Frysingerd8035d42011-02-07 01:05:51 -0500426#if defined(TARGET_NR_ppoll)
427#ifndef __NR_ppoll
428# define __NR_ppoll -1
429#endif
430#define __NR_sys_ppoll __NR_ppoll
431_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200432 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500433 size_t, sigsetsize)
434#endif
bellard66fb9762003-03-23 01:06:05 +0000435
Mike Frysinger055e0902011-06-03 17:01:49 -0400436#if defined(TARGET_NR_pselect6)
437#ifndef __NR_pselect6
438# define __NR_pselect6 -1
439#endif
440#define __NR_sys_pselect6 __NR_pselect6
441_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
442 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
443#endif
444
Peter Maydell163a05a2011-06-27 17:44:52 +0100445#if defined(TARGET_NR_prlimit64)
446#ifndef __NR_prlimit64
447# define __NR_prlimit64 -1
448#endif
449#define __NR_sys_prlimit64 __NR_prlimit64
450/* The glibc rlimit structure may not be that used by the underlying syscall */
451struct host_rlimit64 {
452 uint64_t rlim_cur;
453 uint64_t rlim_max;
454};
455_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
456 const struct host_rlimit64 *, new_limit,
457 struct host_rlimit64 *, old_limit)
458#endif
459
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100460
461#if defined(TARGET_NR_timer_create)
462/* Maxiumum of 32 active POSIX timers allowed at any one time. */
463static timer_t g_posix_timers[32] = { 0, } ;
464
465static inline int next_free_host_timer(void)
466{
467 int k ;
468 /* FIXME: Does finding the next free slot require a lock? */
469 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
470 if (g_posix_timers[k] == 0) {
471 g_posix_timers[k] = (timer_t) 1;
472 return k;
473 }
474 }
475 return -1;
476}
477#endif
478
Riku Voipio48e515d2011-07-12 15:40:51 +0300479/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000480#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300481static inline int regpairs_aligned(void *cpu_env) {
482 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
483}
484#elif defined(TARGET_MIPS)
485static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000486#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
487/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
488 * of registers which translates to the same as ARM/MIPS, because we start with
489 * r3 as arg1 */
490static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300491#else
492static inline int regpairs_aligned(void *cpu_env) { return 0; }
493#endif
494
thsb92c47c2007-11-01 00:07:38 +0000495#define ERRNO_TABLE_SIZE 1200
496
497/* target_to_host_errno_table[] is initialized from
498 * host_to_target_errno_table[] in syscall_init(). */
499static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
500};
501
ths637947f2007-06-01 12:09:19 +0000502/*
thsfe8f0962007-07-12 10:59:21 +0000503 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000504 * minus the errnos that are not actually generic to all archs.
505 */
thsb92c47c2007-11-01 00:07:38 +0000506static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800507 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000508 [EIDRM] = TARGET_EIDRM,
509 [ECHRNG] = TARGET_ECHRNG,
510 [EL2NSYNC] = TARGET_EL2NSYNC,
511 [EL3HLT] = TARGET_EL3HLT,
512 [EL3RST] = TARGET_EL3RST,
513 [ELNRNG] = TARGET_ELNRNG,
514 [EUNATCH] = TARGET_EUNATCH,
515 [ENOCSI] = TARGET_ENOCSI,
516 [EL2HLT] = TARGET_EL2HLT,
517 [EDEADLK] = TARGET_EDEADLK,
518 [ENOLCK] = TARGET_ENOLCK,
519 [EBADE] = TARGET_EBADE,
520 [EBADR] = TARGET_EBADR,
521 [EXFULL] = TARGET_EXFULL,
522 [ENOANO] = TARGET_ENOANO,
523 [EBADRQC] = TARGET_EBADRQC,
524 [EBADSLT] = TARGET_EBADSLT,
525 [EBFONT] = TARGET_EBFONT,
526 [ENOSTR] = TARGET_ENOSTR,
527 [ENODATA] = TARGET_ENODATA,
528 [ETIME] = TARGET_ETIME,
529 [ENOSR] = TARGET_ENOSR,
530 [ENONET] = TARGET_ENONET,
531 [ENOPKG] = TARGET_ENOPKG,
532 [EREMOTE] = TARGET_EREMOTE,
533 [ENOLINK] = TARGET_ENOLINK,
534 [EADV] = TARGET_EADV,
535 [ESRMNT] = TARGET_ESRMNT,
536 [ECOMM] = TARGET_ECOMM,
537 [EPROTO] = TARGET_EPROTO,
538 [EDOTDOT] = TARGET_EDOTDOT,
539 [EMULTIHOP] = TARGET_EMULTIHOP,
540 [EBADMSG] = TARGET_EBADMSG,
541 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
542 [EOVERFLOW] = TARGET_EOVERFLOW,
543 [ENOTUNIQ] = TARGET_ENOTUNIQ,
544 [EBADFD] = TARGET_EBADFD,
545 [EREMCHG] = TARGET_EREMCHG,
546 [ELIBACC] = TARGET_ELIBACC,
547 [ELIBBAD] = TARGET_ELIBBAD,
548 [ELIBSCN] = TARGET_ELIBSCN,
549 [ELIBMAX] = TARGET_ELIBMAX,
550 [ELIBEXEC] = TARGET_ELIBEXEC,
551 [EILSEQ] = TARGET_EILSEQ,
552 [ENOSYS] = TARGET_ENOSYS,
553 [ELOOP] = TARGET_ELOOP,
554 [ERESTART] = TARGET_ERESTART,
555 [ESTRPIPE] = TARGET_ESTRPIPE,
556 [ENOTEMPTY] = TARGET_ENOTEMPTY,
557 [EUSERS] = TARGET_EUSERS,
558 [ENOTSOCK] = TARGET_ENOTSOCK,
559 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
560 [EMSGSIZE] = TARGET_EMSGSIZE,
561 [EPROTOTYPE] = TARGET_EPROTOTYPE,
562 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
563 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
564 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
565 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
566 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
567 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
568 [EADDRINUSE] = TARGET_EADDRINUSE,
569 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
570 [ENETDOWN] = TARGET_ENETDOWN,
571 [ENETUNREACH] = TARGET_ENETUNREACH,
572 [ENETRESET] = TARGET_ENETRESET,
573 [ECONNABORTED] = TARGET_ECONNABORTED,
574 [ECONNRESET] = TARGET_ECONNRESET,
575 [ENOBUFS] = TARGET_ENOBUFS,
576 [EISCONN] = TARGET_EISCONN,
577 [ENOTCONN] = TARGET_ENOTCONN,
578 [EUCLEAN] = TARGET_EUCLEAN,
579 [ENOTNAM] = TARGET_ENOTNAM,
580 [ENAVAIL] = TARGET_ENAVAIL,
581 [EISNAM] = TARGET_EISNAM,
582 [EREMOTEIO] = TARGET_EREMOTEIO,
583 [ESHUTDOWN] = TARGET_ESHUTDOWN,
584 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
585 [ETIMEDOUT] = TARGET_ETIMEDOUT,
586 [ECONNREFUSED] = TARGET_ECONNREFUSED,
587 [EHOSTDOWN] = TARGET_EHOSTDOWN,
588 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
589 [EALREADY] = TARGET_EALREADY,
590 [EINPROGRESS] = TARGET_EINPROGRESS,
591 [ESTALE] = TARGET_ESTALE,
592 [ECANCELED] = TARGET_ECANCELED,
593 [ENOMEDIUM] = TARGET_ENOMEDIUM,
594 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000595#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000596 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000597#endif
598#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000599 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000600#endif
601#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000602 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000603#endif
604#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000605 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000606#endif
607#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000608 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000609#endif
610#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000611 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000612#endif
thsb92c47c2007-11-01 00:07:38 +0000613};
ths637947f2007-06-01 12:09:19 +0000614
615static inline int host_to_target_errno(int err)
616{
617 if(host_to_target_errno_table[err])
618 return host_to_target_errno_table[err];
619 return err;
620}
621
thsb92c47c2007-11-01 00:07:38 +0000622static inline int target_to_host_errno(int err)
623{
624 if (target_to_host_errno_table[err])
625 return target_to_host_errno_table[err];
626 return err;
627}
628
blueswir1992f48a2007-10-14 16:27:31 +0000629static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000630{
631 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000632 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000633 else
634 return ret;
635}
636
blueswir1992f48a2007-10-14 16:27:31 +0000637static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000638{
blueswir1992f48a2007-10-14 16:27:31 +0000639 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000640}
641
thsb92c47c2007-11-01 00:07:38 +0000642char *target_strerror(int err)
643{
Alexander Graf962b2892011-11-21 12:04:07 +0100644 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
645 return NULL;
646 }
thsb92c47c2007-11-01 00:07:38 +0000647 return strerror(target_to_host_errno(err));
648}
649
Paul Burton8289d112014-06-22 11:25:33 +0100650static inline int host_to_target_sock_type(int host_type)
651{
652 int target_type;
653
654 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
655 case SOCK_DGRAM:
656 target_type = TARGET_SOCK_DGRAM;
657 break;
658 case SOCK_STREAM:
659 target_type = TARGET_SOCK_STREAM;
660 break;
661 default:
662 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
663 break;
664 }
665
666#if defined(SOCK_CLOEXEC)
667 if (host_type & SOCK_CLOEXEC) {
668 target_type |= TARGET_SOCK_CLOEXEC;
669 }
670#endif
671
672#if defined(SOCK_NONBLOCK)
673 if (host_type & SOCK_NONBLOCK) {
674 target_type |= TARGET_SOCK_NONBLOCK;
675 }
676#endif
677
678 return target_type;
679}
680
blueswir1992f48a2007-10-14 16:27:31 +0000681static abi_ulong target_brk;
682static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000683static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000684
blueswir1992f48a2007-10-14 16:27:31 +0000685void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000686{
blueswir14c1de732007-07-07 20:45:44 +0000687 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000688 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000689}
690
vincent4d1de872011-06-14 21:56:33 +0000691//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
692#define DEBUGF_BRK(message, args...)
693
ths0da46a62007-10-20 20:23:07 +0000694/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000695abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000696{
blueswir1992f48a2007-10-14 16:27:31 +0000697 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000698 int new_alloc_size;
699
Paul Brook3a0c6c42012-02-09 19:04:27 +0000700 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000701
vincent4d1de872011-06-14 21:56:33 +0000702 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000703 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000704 return target_brk;
705 }
706 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000707 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
708 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000709 return target_brk;
710 }
bellard31e31b82003-02-18 22:55:36 +0000711
vincent4d1de872011-06-14 21:56:33 +0000712 /* If the new brk is less than the highest page reserved to the
713 * target heap allocation, set it and we're almost done... */
714 if (new_brk <= brk_page) {
715 /* Heap contents are initialized to zero, as for anonymous
716 * mapped pages. */
717 if (new_brk > target_brk) {
718 memset(g2h(target_brk), 0, new_brk - target_brk);
719 }
bellard31e31b82003-02-18 22:55:36 +0000720 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000721 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000722 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000723 }
724
Peter Maydell00faf082011-04-18 16:34:24 +0100725 /* We need to allocate more memory after the brk... Note that
726 * we don't use MAP_FIXED because that will map over the top of
727 * any existing mapping (like the one with the host libc or qemu
728 * itself); instead we treat "mapped but at wrong address" as
729 * a failure and unmap again.
730 */
vincent4d1de872011-06-14 21:56:33 +0000731 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000732 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000733 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100734 MAP_ANON|MAP_PRIVATE, 0, 0));
735
736 if (mapped_addr == brk_page) {
CĂ©dric VINCENT70afc342011-08-26 10:56:50 +0200737 /* Heap contents are initialized to zero, as for anonymous
738 * mapped pages. Technically the new pages are already
739 * initialized to zero since they *are* anonymous mapped
740 * pages, however we have to take care with the contents that
741 * come from the remaining part of the previous page: it may
742 * contains garbage data due to a previous heap usage (grown
743 * then shrunken). */
744 memset(g2h(target_brk), 0, brk_page - target_brk);
745
Peter Maydell00faf082011-04-18 16:34:24 +0100746 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000747 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000748 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
749 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100750 return target_brk;
751 } else if (mapped_addr != -1) {
752 /* Mapped but at wrong address, meaning there wasn't actually
753 * enough space for this brk.
754 */
755 target_munmap(mapped_addr, new_alloc_size);
756 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000757 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000758 }
759 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000760 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100761 }
balrog7ab240a2008-04-26 12:17:34 +0000762
Richard Henderson7dd46c02010-05-03 10:07:49 -0700763#if defined(TARGET_ALPHA)
764 /* We (partially) emulate OSF/1 on Alpha, which requires we
765 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100766 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700767#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100768 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000769 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000770}
771
ths26edcf42007-12-09 02:25:24 +0000772static inline abi_long copy_from_user_fdset(fd_set *fds,
773 abi_ulong target_fds_addr,
774 int n)
bellard31e31b82003-02-18 22:55:36 +0000775{
ths26edcf42007-12-09 02:25:24 +0000776 int i, nw, j, k;
777 abi_ulong b, *target_fds;
778
779 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
780 if (!(target_fds = lock_user(VERIFY_READ,
781 target_fds_addr,
782 sizeof(abi_ulong) * nw,
783 1)))
784 return -TARGET_EFAULT;
785
786 FD_ZERO(fds);
787 k = 0;
788 for (i = 0; i < nw; i++) {
789 /* grab the abi_ulong */
790 __get_user(b, &target_fds[i]);
791 for (j = 0; j < TARGET_ABI_BITS; j++) {
792 /* check the bit inside the abi_ulong */
793 if ((b >> j) & 1)
794 FD_SET(k, fds);
795 k++;
bellard31e31b82003-02-18 22:55:36 +0000796 }
bellard31e31b82003-02-18 22:55:36 +0000797 }
ths26edcf42007-12-09 02:25:24 +0000798
799 unlock_user(target_fds, target_fds_addr, 0);
800
801 return 0;
bellard31e31b82003-02-18 22:55:36 +0000802}
803
Mike Frysinger055e0902011-06-03 17:01:49 -0400804static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
805 abi_ulong target_fds_addr,
806 int n)
807{
808 if (target_fds_addr) {
809 if (copy_from_user_fdset(fds, target_fds_addr, n))
810 return -TARGET_EFAULT;
811 *fds_ptr = fds;
812 } else {
813 *fds_ptr = NULL;
814 }
815 return 0;
816}
817
ths26edcf42007-12-09 02:25:24 +0000818static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
819 const fd_set *fds,
820 int n)
bellard31e31b82003-02-18 22:55:36 +0000821{
bellard31e31b82003-02-18 22:55:36 +0000822 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000823 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000824 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000825
ths26edcf42007-12-09 02:25:24 +0000826 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
827 if (!(target_fds = lock_user(VERIFY_WRITE,
828 target_fds_addr,
829 sizeof(abi_ulong) * nw,
830 0)))
831 return -TARGET_EFAULT;
832
833 k = 0;
834 for (i = 0; i < nw; i++) {
835 v = 0;
836 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000837 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000838 k++;
bellard31e31b82003-02-18 22:55:36 +0000839 }
ths26edcf42007-12-09 02:25:24 +0000840 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000841 }
ths26edcf42007-12-09 02:25:24 +0000842
843 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
844
845 return 0;
bellard31e31b82003-02-18 22:55:36 +0000846}
847
bellardc596ed12003-07-13 17:32:31 +0000848#if defined(__alpha__)
849#define HOST_HZ 1024
850#else
851#define HOST_HZ 100
852#endif
853
blueswir1992f48a2007-10-14 16:27:31 +0000854static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000855{
856#if HOST_HZ == TARGET_HZ
857 return ticks;
858#else
859 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
860#endif
861}
862
bellard579a97f2007-11-11 14:26:47 +0000863static inline abi_long host_to_target_rusage(abi_ulong target_addr,
864 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000865{
pbrook53a59602006-03-25 19:31:22 +0000866 struct target_rusage *target_rusage;
867
bellard579a97f2007-11-11 14:26:47 +0000868 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
869 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200870 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
871 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
872 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
873 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
874 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
875 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
876 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
877 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
878 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
879 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
880 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
881 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
882 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
883 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
884 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
885 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
886 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
887 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000888 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000889
890 return 0;
bellardb4091862003-05-16 15:39:34 +0000891}
892
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200893static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900894{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200895 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300896 rlim_t result;
897
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200898 target_rlim_swap = tswapal(target_rlim);
899 if (target_rlim_swap == TARGET_RLIM_INFINITY)
900 return RLIM_INFINITY;
901
902 result = target_rlim_swap;
903 if (target_rlim_swap != (rlim_t)result)
904 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300905
906 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900907}
908
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200909static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900910{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200911 abi_ulong target_rlim_swap;
912 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300913
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200914 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300915 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900916 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300917 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200918 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300919
920 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900921}
922
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300923static inline int target_to_host_resource(int code)
924{
925 switch (code) {
926 case TARGET_RLIMIT_AS:
927 return RLIMIT_AS;
928 case TARGET_RLIMIT_CORE:
929 return RLIMIT_CORE;
930 case TARGET_RLIMIT_CPU:
931 return RLIMIT_CPU;
932 case TARGET_RLIMIT_DATA:
933 return RLIMIT_DATA;
934 case TARGET_RLIMIT_FSIZE:
935 return RLIMIT_FSIZE;
936 case TARGET_RLIMIT_LOCKS:
937 return RLIMIT_LOCKS;
938 case TARGET_RLIMIT_MEMLOCK:
939 return RLIMIT_MEMLOCK;
940 case TARGET_RLIMIT_MSGQUEUE:
941 return RLIMIT_MSGQUEUE;
942 case TARGET_RLIMIT_NICE:
943 return RLIMIT_NICE;
944 case TARGET_RLIMIT_NOFILE:
945 return RLIMIT_NOFILE;
946 case TARGET_RLIMIT_NPROC:
947 return RLIMIT_NPROC;
948 case TARGET_RLIMIT_RSS:
949 return RLIMIT_RSS;
950 case TARGET_RLIMIT_RTPRIO:
951 return RLIMIT_RTPRIO;
952 case TARGET_RLIMIT_SIGPENDING:
953 return RLIMIT_SIGPENDING;
954 case TARGET_RLIMIT_STACK:
955 return RLIMIT_STACK;
956 default:
957 return code;
958 }
959}
960
ths788f5ec2007-12-09 02:37:05 +0000961static inline abi_long copy_from_user_timeval(struct timeval *tv,
962 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000963{
pbrook53a59602006-03-25 19:31:22 +0000964 struct target_timeval *target_tv;
965
ths788f5ec2007-12-09 02:37:05 +0000966 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000967 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000968
969 __get_user(tv->tv_sec, &target_tv->tv_sec);
970 __get_user(tv->tv_usec, &target_tv->tv_usec);
971
972 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000973
974 return 0;
bellard31e31b82003-02-18 22:55:36 +0000975}
976
ths788f5ec2007-12-09 02:37:05 +0000977static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
978 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000979{
pbrook53a59602006-03-25 19:31:22 +0000980 struct target_timeval *target_tv;
981
ths788f5ec2007-12-09 02:37:05 +0000982 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000983 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000984
985 __put_user(tv->tv_sec, &target_tv->tv_sec);
986 __put_user(tv->tv_usec, &target_tv->tv_usec);
987
988 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000989
990 return 0;
bellard31e31b82003-02-18 22:55:36 +0000991}
992
Paul Burtonef4467e2014-06-22 11:25:40 +0100993static inline abi_long copy_from_user_timezone(struct timezone *tz,
994 abi_ulong target_tz_addr)
995{
996 struct target_timezone *target_tz;
997
998 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
999 return -TARGET_EFAULT;
1000 }
1001
1002 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1003 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1004
1005 unlock_user_struct(target_tz, target_tz_addr, 0);
1006
1007 return 0;
1008}
1009
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001010#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1011#include <mqueue.h>
1012
aurel3224e10032009-04-15 16:11:43 +00001013static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1014 abi_ulong target_mq_attr_addr)
1015{
1016 struct target_mq_attr *target_mq_attr;
1017
1018 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1019 target_mq_attr_addr, 1))
1020 return -TARGET_EFAULT;
1021
1022 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1023 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1024 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1025 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1026
1027 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1028
1029 return 0;
1030}
1031
1032static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1033 const struct mq_attr *attr)
1034{
1035 struct target_mq_attr *target_mq_attr;
1036
1037 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1038 target_mq_attr_addr, 0))
1039 return -TARGET_EFAULT;
1040
1041 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1042 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1043 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1044 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1045
1046 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1047
1048 return 0;
1049}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001050#endif
bellard31e31b82003-02-18 22:55:36 +00001051
Mike Frysinger055e0902011-06-03 17:01:49 -04001052#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001053/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001054static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001055 abi_ulong rfd_addr, abi_ulong wfd_addr,
1056 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001057{
1058 fd_set rfds, wfds, efds;
1059 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1060 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001061 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001062
Mike Frysinger055e0902011-06-03 17:01:49 -04001063 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1064 if (ret) {
1065 return ret;
pbrook53a59602006-03-25 19:31:22 +00001066 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001067 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1068 if (ret) {
1069 return ret;
pbrook53a59602006-03-25 19:31:22 +00001070 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001071 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1072 if (ret) {
1073 return ret;
pbrook53a59602006-03-25 19:31:22 +00001074 }
ths3b46e622007-09-17 08:09:54 +00001075
ths26edcf42007-12-09 02:25:24 +00001076 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001077 if (copy_from_user_timeval(&tv, target_tv_addr))
1078 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001079 tv_ptr = &tv;
1080 } else {
1081 tv_ptr = NULL;
1082 }
ths26edcf42007-12-09 02:25:24 +00001083
bellard31e31b82003-02-18 22:55:36 +00001084 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001085
ths26edcf42007-12-09 02:25:24 +00001086 if (!is_error(ret)) {
1087 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1088 return -TARGET_EFAULT;
1089 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1090 return -TARGET_EFAULT;
1091 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1092 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001093
ths788f5ec2007-12-09 02:37:05 +00001094 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1095 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001096 }
bellard579a97f2007-11-11 14:26:47 +00001097
bellard31e31b82003-02-18 22:55:36 +00001098 return ret;
1099}
Mike Frysinger055e0902011-06-03 17:01:49 -04001100#endif
bellard31e31b82003-02-18 22:55:36 +00001101
Riku Voipio099d6b02009-05-05 12:10:04 +03001102static abi_long do_pipe2(int host_pipe[], int flags)
1103{
1104#ifdef CONFIG_PIPE2
1105 return pipe2(host_pipe, flags);
1106#else
1107 return -ENOSYS;
1108#endif
1109}
1110
Richard Hendersonfb41a662010-05-03 10:07:52 -07001111static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1112 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001113{
1114 int host_pipe[2];
1115 abi_long ret;
1116 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1117
1118 if (is_error(ret))
1119 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001120
1121 /* Several targets have special calling conventions for the original
1122 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1123 if (!is_pipe2) {
1124#if defined(TARGET_ALPHA)
1125 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1126 return host_pipe[0];
1127#elif defined(TARGET_MIPS)
1128 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1129 return host_pipe[0];
1130#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001131 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001132 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001133#elif defined(TARGET_SPARC)
1134 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1135 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001136#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001137 }
1138
Riku Voipio099d6b02009-05-05 12:10:04 +03001139 if (put_user_s32(host_pipe[0], pipedes)
1140 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1141 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001142 return get_errno(ret);
1143}
1144
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001145static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1146 abi_ulong target_addr,
1147 socklen_t len)
1148{
1149 struct target_ip_mreqn *target_smreqn;
1150
1151 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1152 if (!target_smreqn)
1153 return -TARGET_EFAULT;
1154 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1155 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1156 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001157 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001158 unlock_user(target_smreqn, target_addr, 0);
1159
1160 return 0;
1161}
1162
Laurent Vivier7b36f782015-10-28 21:40:44 +01001163static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001164 abi_ulong target_addr,
1165 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001166{
aurel32607175e2009-04-15 16:11:59 +00001167 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1168 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001169 struct target_sockaddr *target_saddr;
1170
Laurent Vivier7b36f782015-10-28 21:40:44 +01001171 if (fd_trans_target_to_host_addr(fd)) {
1172 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1173 }
1174
bellard579a97f2007-11-11 14:26:47 +00001175 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1176 if (!target_saddr)
1177 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001178
1179 sa_family = tswap16(target_saddr->sa_family);
1180
1181 /* Oops. The caller might send a incomplete sun_path; sun_path
1182 * must be terminated by \0 (see the manual page), but
1183 * unfortunately it is quite common to specify sockaddr_un
1184 * length as "strlen(x->sun_path)" while it should be
1185 * "strlen(...) + 1". We'll fix that here if needed.
1186 * Linux kernel has a similar feature.
1187 */
1188
1189 if (sa_family == AF_UNIX) {
1190 if (len < unix_maxlen && len > 0) {
1191 char *cp = (char*)target_saddr;
1192
1193 if ( cp[len-1] && !cp[len] )
1194 len++;
1195 }
1196 if (len > unix_maxlen)
1197 len = unix_maxlen;
1198 }
1199
pbrook53a59602006-03-25 19:31:22 +00001200 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001201 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001202 if (sa_family == AF_PACKET) {
1203 struct target_sockaddr_ll *lladdr;
1204
1205 lladdr = (struct target_sockaddr_ll *)addr;
1206 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1207 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1208 }
pbrook53a59602006-03-25 19:31:22 +00001209 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001210
1211 return 0;
bellard7854b052003-03-29 17:22:23 +00001212}
1213
bellard579a97f2007-11-11 14:26:47 +00001214static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1215 struct sockaddr *addr,
1216 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001217{
pbrook53a59602006-03-25 19:31:22 +00001218 struct target_sockaddr *target_saddr;
1219
bellard579a97f2007-11-11 14:26:47 +00001220 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1221 if (!target_saddr)
1222 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001223 memcpy(target_saddr, addr, len);
1224 target_saddr->sa_family = tswap16(addr->sa_family);
1225 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001226
1227 return 0;
bellard7854b052003-03-29 17:22:23 +00001228}
1229
bellard5a4a8982007-11-11 17:39:18 +00001230static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1231 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001232{
1233 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001234 abi_long msg_controllen;
1235 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001236 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001237 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001238
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001239 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001240 if (msg_controllen < sizeof (struct target_cmsghdr))
1241 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001242 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001243 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001244 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001245 if (!target_cmsg)
1246 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001247
1248 while (cmsg && target_cmsg) {
1249 void *data = CMSG_DATA(cmsg);
1250 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1251
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001252 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001253 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1254
1255 space += CMSG_SPACE(len);
1256 if (space > msgh->msg_controllen) {
1257 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001258 /* This is a QEMU bug, since we allocated the payload
1259 * area ourselves (unlike overflow in host-to-target
1260 * conversion, which is just the guest giving us a buffer
1261 * that's too small). It can't happen for the payload types
1262 * we currently support; if it becomes an issue in future
1263 * we would need to improve our allocation strategy to
1264 * something more intelligent than "twice the size of the
1265 * target buffer we're reading from".
1266 */
bellard31febb72005-12-18 20:03:27 +00001267 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001268 break;
1269 }
1270
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001271 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1272 cmsg->cmsg_level = SOL_SOCKET;
1273 } else {
1274 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1275 }
bellard7854b052003-03-29 17:22:23 +00001276 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1277 cmsg->cmsg_len = CMSG_LEN(len);
1278
Alex Suykov30b8b682014-12-23 07:52:58 +02001279 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001280 int *fd = (int *)data;
1281 int *target_fd = (int *)target_data;
1282 int i, numfds = len / sizeof(int);
1283
Peter Maydell876e23c2015-05-26 19:46:32 +01001284 for (i = 0; i < numfds; i++) {
1285 __get_user(fd[i], target_fd + i);
1286 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001287 } else if (cmsg->cmsg_level == SOL_SOCKET
1288 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1289 struct ucred *cred = (struct ucred *)data;
1290 struct target_ucred *target_cred =
1291 (struct target_ucred *)target_data;
1292
Peter Maydell876e23c2015-05-26 19:46:32 +01001293 __get_user(cred->pid, &target_cred->pid);
1294 __get_user(cred->uid, &target_cred->uid);
1295 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001296 } else {
1297 gemu_log("Unsupported ancillary data: %d/%d\n",
1298 cmsg->cmsg_level, cmsg->cmsg_type);
1299 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001300 }
1301
1302 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001303 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1304 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001305 }
bellard5a4a8982007-11-11 17:39:18 +00001306 unlock_user(target_cmsg, target_cmsg_addr, 0);
1307 the_end:
bellard7854b052003-03-29 17:22:23 +00001308 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001309 return 0;
bellard7854b052003-03-29 17:22:23 +00001310}
1311
bellard5a4a8982007-11-11 17:39:18 +00001312static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1313 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001314{
1315 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001316 abi_long msg_controllen;
1317 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001318 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001319 socklen_t space = 0;
1320
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001321 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001322 if (msg_controllen < sizeof (struct target_cmsghdr))
1323 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001324 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001325 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001326 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001327 if (!target_cmsg)
1328 return -TARGET_EFAULT;
1329
bellard7854b052003-03-29 17:22:23 +00001330 while (cmsg && target_cmsg) {
1331 void *data = CMSG_DATA(cmsg);
1332 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1333
1334 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001335 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001336
Peter Maydellc2aeb252015-05-26 19:46:31 +01001337 /* We never copy a half-header but may copy half-data;
1338 * this is Linux's behaviour in put_cmsg(). Note that
1339 * truncation here is a guest problem (which we report
1340 * to the guest via the CTRUNC bit), unlike truncation
1341 * in target_to_host_cmsg, which is a QEMU bug.
1342 */
1343 if (msg_controllen < sizeof(struct cmsghdr)) {
1344 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001345 break;
1346 }
1347
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001348 if (cmsg->cmsg_level == SOL_SOCKET) {
1349 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1350 } else {
1351 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1352 }
bellard7854b052003-03-29 17:22:23 +00001353 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001354
Peter Maydellc2aeb252015-05-26 19:46:31 +01001355 tgt_len = TARGET_CMSG_LEN(len);
1356
1357 /* Payload types which need a different size of payload on
1358 * the target must adjust tgt_len here.
1359 */
1360 switch (cmsg->cmsg_level) {
1361 case SOL_SOCKET:
1362 switch (cmsg->cmsg_type) {
1363 case SO_TIMESTAMP:
1364 tgt_len = sizeof(struct target_timeval);
1365 break;
1366 default:
1367 break;
1368 }
1369 default:
1370 break;
1371 }
1372
1373 if (msg_controllen < tgt_len) {
1374 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1375 tgt_len = msg_controllen;
1376 }
1377
1378 /* We must now copy-and-convert len bytes of payload
1379 * into tgt_len bytes of destination space. Bear in mind
1380 * that in both source and destination we may be dealing
1381 * with a truncated value!
1382 */
Huw Davies52b65492014-04-17 14:02:47 +01001383 switch (cmsg->cmsg_level) {
1384 case SOL_SOCKET:
1385 switch (cmsg->cmsg_type) {
1386 case SCM_RIGHTS:
1387 {
1388 int *fd = (int *)data;
1389 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001390 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001391
Peter Maydell876e23c2015-05-26 19:46:32 +01001392 for (i = 0; i < numfds; i++) {
1393 __put_user(fd[i], target_fd + i);
1394 }
Huw Davies52b65492014-04-17 14:02:47 +01001395 break;
1396 }
1397 case SO_TIMESTAMP:
1398 {
1399 struct timeval *tv = (struct timeval *)data;
1400 struct target_timeval *target_tv =
1401 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001402
Peter Maydellc2aeb252015-05-26 19:46:31 +01001403 if (len != sizeof(struct timeval) ||
1404 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001405 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001406 }
Huw Davies52b65492014-04-17 14:02:47 +01001407
1408 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001409 __put_user(tv->tv_sec, &target_tv->tv_sec);
1410 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001411 break;
1412 }
Huw Davies4bc29752014-04-17 14:02:48 +01001413 case SCM_CREDENTIALS:
1414 {
1415 struct ucred *cred = (struct ucred *)data;
1416 struct target_ucred *target_cred =
1417 (struct target_ucred *)target_data;
1418
1419 __put_user(cred->pid, &target_cred->pid);
1420 __put_user(cred->uid, &target_cred->uid);
1421 __put_user(cred->gid, &target_cred->gid);
1422 break;
1423 }
Huw Davies52b65492014-04-17 14:02:47 +01001424 default:
1425 goto unimplemented;
1426 }
1427 break;
1428
1429 default:
1430 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001431 gemu_log("Unsupported ancillary data: %d/%d\n",
1432 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001433 memcpy(target_data, data, MIN(len, tgt_len));
1434 if (tgt_len > len) {
1435 memset(target_data + len, 0, tgt_len - len);
1436 }
bellard7854b052003-03-29 17:22:23 +00001437 }
1438
Peter Maydellc2aeb252015-05-26 19:46:31 +01001439 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001440 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001441 if (msg_controllen < tgt_space) {
1442 tgt_space = msg_controllen;
1443 }
1444 msg_controllen -= tgt_space;
1445 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001446 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001447 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1448 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001449 }
bellard5a4a8982007-11-11 17:39:18 +00001450 unlock_user(target_cmsg, target_cmsg_addr, space);
1451 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001452 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001453 return 0;
bellard7854b052003-03-29 17:22:23 +00001454}
1455
ths0da46a62007-10-20 20:23:07 +00001456/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001457static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001458 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001459{
blueswir1992f48a2007-10-14 16:27:31 +00001460 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001461 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001462 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001463 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001464
bellard8853f862004-02-22 14:57:26 +00001465 switch(level) {
1466 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001467 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001468 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001469 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001470
bellard2f619692007-11-16 10:46:05 +00001471 if (get_user_u32(val, optval_addr))
1472 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001473 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1474 break;
1475 case SOL_IP:
1476 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001477 case IP_TOS:
1478 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001479 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001480 case IP_ROUTER_ALERT:
1481 case IP_RECVOPTS:
1482 case IP_RETOPTS:
1483 case IP_PKTINFO:
1484 case IP_MTU_DISCOVER:
1485 case IP_RECVERR:
1486 case IP_RECVTOS:
1487#ifdef IP_FREEBIND
1488 case IP_FREEBIND:
1489#endif
1490 case IP_MULTICAST_TTL:
1491 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001492 val = 0;
1493 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001494 if (get_user_u32(val, optval_addr))
1495 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001496 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001497 if (get_user_u8(val, optval_addr))
1498 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001499 }
1500 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1501 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001502 case IP_ADD_MEMBERSHIP:
1503 case IP_DROP_MEMBERSHIP:
1504 if (optlen < sizeof (struct target_ip_mreq) ||
1505 optlen > sizeof (struct target_ip_mreqn))
1506 return -TARGET_EINVAL;
1507
1508 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1509 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1510 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1511 break;
1512
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001513 case IP_BLOCK_SOURCE:
1514 case IP_UNBLOCK_SOURCE:
1515 case IP_ADD_SOURCE_MEMBERSHIP:
1516 case IP_DROP_SOURCE_MEMBERSHIP:
1517 if (optlen != sizeof (struct target_ip_mreq_source))
1518 return -TARGET_EINVAL;
1519
1520 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1521 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1522 unlock_user (ip_mreq_source, optval_addr, 0);
1523 break;
1524
bellard8853f862004-02-22 14:57:26 +00001525 default:
1526 goto unimplemented;
1527 }
1528 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001529 case SOL_IPV6:
1530 switch (optname) {
1531 case IPV6_MTU_DISCOVER:
1532 case IPV6_MTU:
1533 case IPV6_V6ONLY:
1534 case IPV6_RECVPKTINFO:
1535 val = 0;
1536 if (optlen < sizeof(uint32_t)) {
1537 return -TARGET_EINVAL;
1538 }
1539 if (get_user_u32(val, optval_addr)) {
1540 return -TARGET_EFAULT;
1541 }
1542 ret = get_errno(setsockopt(sockfd, level, optname,
1543 &val, sizeof(val)));
1544 break;
1545 default:
1546 goto unimplemented;
1547 }
1548 break;
Jing Huang920394d2012-07-24 13:59:23 +00001549 case SOL_RAW:
1550 switch (optname) {
1551 case ICMP_FILTER:
1552 /* struct icmp_filter takes an u32 value */
1553 if (optlen < sizeof(uint32_t)) {
1554 return -TARGET_EINVAL;
1555 }
1556
1557 if (get_user_u32(val, optval_addr)) {
1558 return -TARGET_EFAULT;
1559 }
1560 ret = get_errno(setsockopt(sockfd, level, optname,
1561 &val, sizeof(val)));
1562 break;
1563
1564 default:
1565 goto unimplemented;
1566 }
1567 break;
bellard3532fa72006-06-24 15:06:03 +00001568 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001569 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001570 case TARGET_SO_RCVTIMEO:
1571 {
1572 struct timeval tv;
1573
1574 optname = SO_RCVTIMEO;
1575
1576set_timeout:
1577 if (optlen != sizeof(struct target_timeval)) {
1578 return -TARGET_EINVAL;
1579 }
1580
1581 if (copy_from_user_timeval(&tv, optval_addr)) {
1582 return -TARGET_EFAULT;
1583 }
1584
1585 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1586 &tv, sizeof(tv)));
1587 return ret;
1588 }
1589 case TARGET_SO_SNDTIMEO:
1590 optname = SO_SNDTIMEO;
1591 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001592 case TARGET_SO_ATTACH_FILTER:
1593 {
1594 struct target_sock_fprog *tfprog;
1595 struct target_sock_filter *tfilter;
1596 struct sock_fprog fprog;
1597 struct sock_filter *filter;
1598 int i;
1599
1600 if (optlen != sizeof(*tfprog)) {
1601 return -TARGET_EINVAL;
1602 }
1603 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1604 return -TARGET_EFAULT;
1605 }
1606 if (!lock_user_struct(VERIFY_READ, tfilter,
1607 tswapal(tfprog->filter), 0)) {
1608 unlock_user_struct(tfprog, optval_addr, 1);
1609 return -TARGET_EFAULT;
1610 }
1611
1612 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301613 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001614 if (filter == NULL) {
1615 unlock_user_struct(tfilter, tfprog->filter, 1);
1616 unlock_user_struct(tfprog, optval_addr, 1);
1617 return -TARGET_ENOMEM;
1618 }
1619 for (i = 0; i < fprog.len; i++) {
1620 filter[i].code = tswap16(tfilter[i].code);
1621 filter[i].jt = tfilter[i].jt;
1622 filter[i].jf = tfilter[i].jf;
1623 filter[i].k = tswap32(tfilter[i].k);
1624 }
1625 fprog.filter = filter;
1626
1627 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1628 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301629 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001630
1631 unlock_user_struct(tfilter, tfprog->filter, 1);
1632 unlock_user_struct(tfprog, optval_addr, 1);
1633 return ret;
1634 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001635 case TARGET_SO_BINDTODEVICE:
1636 {
1637 char *dev_ifname, *addr_ifname;
1638
1639 if (optlen > IFNAMSIZ - 1) {
1640 optlen = IFNAMSIZ - 1;
1641 }
1642 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1643 if (!dev_ifname) {
1644 return -TARGET_EFAULT;
1645 }
1646 optname = SO_BINDTODEVICE;
1647 addr_ifname = alloca(IFNAMSIZ);
1648 memcpy(addr_ifname, dev_ifname, optlen);
1649 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08001650 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1651 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001652 unlock_user (dev_ifname, optval_addr, 0);
1653 return ret;
1654 }
bellard8853f862004-02-22 14:57:26 +00001655 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001656 case TARGET_SO_DEBUG:
1657 optname = SO_DEBUG;
1658 break;
1659 case TARGET_SO_REUSEADDR:
1660 optname = SO_REUSEADDR;
1661 break;
1662 case TARGET_SO_TYPE:
1663 optname = SO_TYPE;
1664 break;
1665 case TARGET_SO_ERROR:
1666 optname = SO_ERROR;
1667 break;
1668 case TARGET_SO_DONTROUTE:
1669 optname = SO_DONTROUTE;
1670 break;
1671 case TARGET_SO_BROADCAST:
1672 optname = SO_BROADCAST;
1673 break;
1674 case TARGET_SO_SNDBUF:
1675 optname = SO_SNDBUF;
1676 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001677 case TARGET_SO_SNDBUFFORCE:
1678 optname = SO_SNDBUFFORCE;
1679 break;
bellard3532fa72006-06-24 15:06:03 +00001680 case TARGET_SO_RCVBUF:
1681 optname = SO_RCVBUF;
1682 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001683 case TARGET_SO_RCVBUFFORCE:
1684 optname = SO_RCVBUFFORCE;
1685 break;
bellard3532fa72006-06-24 15:06:03 +00001686 case TARGET_SO_KEEPALIVE:
1687 optname = SO_KEEPALIVE;
1688 break;
1689 case TARGET_SO_OOBINLINE:
1690 optname = SO_OOBINLINE;
1691 break;
1692 case TARGET_SO_NO_CHECK:
1693 optname = SO_NO_CHECK;
1694 break;
1695 case TARGET_SO_PRIORITY:
1696 optname = SO_PRIORITY;
1697 break;
bellard5e83e8e2005-03-01 22:32:06 +00001698#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001699 case TARGET_SO_BSDCOMPAT:
1700 optname = SO_BSDCOMPAT;
1701 break;
bellard5e83e8e2005-03-01 22:32:06 +00001702#endif
bellard3532fa72006-06-24 15:06:03 +00001703 case TARGET_SO_PASSCRED:
1704 optname = SO_PASSCRED;
1705 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001706 case TARGET_SO_PASSSEC:
1707 optname = SO_PASSSEC;
1708 break;
bellard3532fa72006-06-24 15:06:03 +00001709 case TARGET_SO_TIMESTAMP:
1710 optname = SO_TIMESTAMP;
1711 break;
1712 case TARGET_SO_RCVLOWAT:
1713 optname = SO_RCVLOWAT;
1714 break;
bellard8853f862004-02-22 14:57:26 +00001715 break;
1716 default:
1717 goto unimplemented;
1718 }
bellard3532fa72006-06-24 15:06:03 +00001719 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001720 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001721
bellard2f619692007-11-16 10:46:05 +00001722 if (get_user_u32(val, optval_addr))
1723 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001724 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001725 break;
bellard7854b052003-03-29 17:22:23 +00001726 default:
bellard8853f862004-02-22 14:57:26 +00001727 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001728 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001729 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001730 }
bellard8853f862004-02-22 14:57:26 +00001731 return ret;
bellard7854b052003-03-29 17:22:23 +00001732}
1733
ths0da46a62007-10-20 20:23:07 +00001734/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001735static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001736 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001737{
blueswir1992f48a2007-10-14 16:27:31 +00001738 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001739 int len, val;
1740 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001741
1742 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001743 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001744 level = SOL_SOCKET;
1745 switch (optname) {
1746 /* These don't just return a single integer */
1747 case TARGET_SO_LINGER:
1748 case TARGET_SO_RCVTIMEO:
1749 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001750 case TARGET_SO_PEERNAME:
1751 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001752 case TARGET_SO_PEERCRED: {
1753 struct ucred cr;
1754 socklen_t crlen;
1755 struct target_ucred *tcr;
1756
1757 if (get_user_u32(len, optlen)) {
1758 return -TARGET_EFAULT;
1759 }
1760 if (len < 0) {
1761 return -TARGET_EINVAL;
1762 }
1763
1764 crlen = sizeof(cr);
1765 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1766 &cr, &crlen));
1767 if (ret < 0) {
1768 return ret;
1769 }
1770 if (len > crlen) {
1771 len = crlen;
1772 }
1773 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1774 return -TARGET_EFAULT;
1775 }
1776 __put_user(cr.pid, &tcr->pid);
1777 __put_user(cr.uid, &tcr->uid);
1778 __put_user(cr.gid, &tcr->gid);
1779 unlock_user_struct(tcr, optval_addr, 1);
1780 if (put_user_u32(len, optlen)) {
1781 return -TARGET_EFAULT;
1782 }
1783 break;
1784 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001785 /* Options with 'int' argument. */
1786 case TARGET_SO_DEBUG:
1787 optname = SO_DEBUG;
1788 goto int_case;
1789 case TARGET_SO_REUSEADDR:
1790 optname = SO_REUSEADDR;
1791 goto int_case;
1792 case TARGET_SO_TYPE:
1793 optname = SO_TYPE;
1794 goto int_case;
1795 case TARGET_SO_ERROR:
1796 optname = SO_ERROR;
1797 goto int_case;
1798 case TARGET_SO_DONTROUTE:
1799 optname = SO_DONTROUTE;
1800 goto int_case;
1801 case TARGET_SO_BROADCAST:
1802 optname = SO_BROADCAST;
1803 goto int_case;
1804 case TARGET_SO_SNDBUF:
1805 optname = SO_SNDBUF;
1806 goto int_case;
1807 case TARGET_SO_RCVBUF:
1808 optname = SO_RCVBUF;
1809 goto int_case;
1810 case TARGET_SO_KEEPALIVE:
1811 optname = SO_KEEPALIVE;
1812 goto int_case;
1813 case TARGET_SO_OOBINLINE:
1814 optname = SO_OOBINLINE;
1815 goto int_case;
1816 case TARGET_SO_NO_CHECK:
1817 optname = SO_NO_CHECK;
1818 goto int_case;
1819 case TARGET_SO_PRIORITY:
1820 optname = SO_PRIORITY;
1821 goto int_case;
1822#ifdef SO_BSDCOMPAT
1823 case TARGET_SO_BSDCOMPAT:
1824 optname = SO_BSDCOMPAT;
1825 goto int_case;
1826#endif
1827 case TARGET_SO_PASSCRED:
1828 optname = SO_PASSCRED;
1829 goto int_case;
1830 case TARGET_SO_TIMESTAMP:
1831 optname = SO_TIMESTAMP;
1832 goto int_case;
1833 case TARGET_SO_RCVLOWAT:
1834 optname = SO_RCVLOWAT;
1835 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001836 case TARGET_SO_ACCEPTCONN:
1837 optname = SO_ACCEPTCONN;
1838 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001839 default:
bellard2efbe912005-07-23 15:10:20 +00001840 goto int_case;
1841 }
1842 break;
1843 case SOL_TCP:
1844 /* TCP options all take an 'int' value. */
1845 int_case:
bellard2f619692007-11-16 10:46:05 +00001846 if (get_user_u32(len, optlen))
1847 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001848 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001849 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001850 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001851 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1852 if (ret < 0)
1853 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001854 if (optname == SO_TYPE) {
1855 val = host_to_target_sock_type(val);
1856 }
bellard2efbe912005-07-23 15:10:20 +00001857 if (len > lv)
1858 len = lv;
bellard2f619692007-11-16 10:46:05 +00001859 if (len == 4) {
1860 if (put_user_u32(val, optval_addr))
1861 return -TARGET_EFAULT;
1862 } else {
1863 if (put_user_u8(val, optval_addr))
1864 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001865 }
bellard2f619692007-11-16 10:46:05 +00001866 if (put_user_u32(len, optlen))
1867 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001868 break;
1869 case SOL_IP:
1870 switch(optname) {
1871 case IP_TOS:
1872 case IP_TTL:
1873 case IP_HDRINCL:
1874 case IP_ROUTER_ALERT:
1875 case IP_RECVOPTS:
1876 case IP_RETOPTS:
1877 case IP_PKTINFO:
1878 case IP_MTU_DISCOVER:
1879 case IP_RECVERR:
1880 case IP_RECVTOS:
1881#ifdef IP_FREEBIND
1882 case IP_FREEBIND:
1883#endif
1884 case IP_MULTICAST_TTL:
1885 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001886 if (get_user_u32(len, optlen))
1887 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001888 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001889 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001890 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001891 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1892 if (ret < 0)
1893 return ret;
bellard2efbe912005-07-23 15:10:20 +00001894 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001895 len = 1;
bellard2f619692007-11-16 10:46:05 +00001896 if (put_user_u32(len, optlen)
1897 || put_user_u8(val, optval_addr))
1898 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001899 } else {
bellard2efbe912005-07-23 15:10:20 +00001900 if (len > sizeof(int))
1901 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001902 if (put_user_u32(len, optlen)
1903 || put_user_u32(val, optval_addr))
1904 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001905 }
bellard8853f862004-02-22 14:57:26 +00001906 break;
bellard2efbe912005-07-23 15:10:20 +00001907 default:
thsc02f4992007-12-18 02:39:59 +00001908 ret = -TARGET_ENOPROTOOPT;
1909 break;
bellard8853f862004-02-22 14:57:26 +00001910 }
1911 break;
1912 default:
1913 unimplemented:
1914 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1915 level, optname);
thsc02f4992007-12-18 02:39:59 +00001916 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001917 break;
1918 }
1919 return ret;
bellard7854b052003-03-29 17:22:23 +00001920}
1921
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001922static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1923 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001924{
1925 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001926 struct iovec *vec;
1927 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001928 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001929 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001930 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001931
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001932 if (count == 0) {
1933 errno = 0;
1934 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001935 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001936 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001937 errno = EINVAL;
1938 return NULL;
1939 }
1940
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301941 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001942 if (vec == NULL) {
1943 errno = ENOMEM;
1944 return NULL;
1945 }
1946
1947 target_vec = lock_user(VERIFY_READ, target_addr,
1948 count * sizeof(struct target_iovec), 1);
1949 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001950 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001951 goto fail2;
1952 }
1953
1954 /* ??? If host page size > target page size, this will result in a
1955 value larger than what we can actually support. */
1956 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1957 total_len = 0;
1958
1959 for (i = 0; i < count; i++) {
1960 abi_ulong base = tswapal(target_vec[i].iov_base);
1961 abi_long len = tswapal(target_vec[i].iov_len);
1962
1963 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001964 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001965 goto fail;
1966 } else if (len == 0) {
1967 /* Zero length pointer is ignored. */
1968 vec[i].iov_base = 0;
1969 } else {
1970 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05001971 /* If the first buffer pointer is bad, this is a fault. But
1972 * subsequent bad buffers will result in a partial write; this
1973 * is realized by filling the vector with null pointers and
1974 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001975 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05001976 if (i == 0) {
1977 err = EFAULT;
1978 goto fail;
1979 } else {
1980 bad_address = true;
1981 }
1982 }
1983 if (bad_address) {
1984 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001985 }
1986 if (len > max_len - total_len) {
1987 len = max_len - total_len;
1988 }
1989 }
1990 vec[i].iov_len = len;
1991 total_len += len;
1992 }
1993
1994 unlock_user(target_vec, target_addr, 0);
1995 return vec;
1996
1997 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08001998 while (--i >= 0) {
1999 if (tswapal(target_vec[i].iov_len) > 0) {
2000 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2001 }
2002 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002003 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002004 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302005 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002006 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002007 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002008}
2009
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002010static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2011 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002012{
2013 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002014 int i;
2015
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002016 target_vec = lock_user(VERIFY_READ, target_addr,
2017 count * sizeof(struct target_iovec), 1);
2018 if (target_vec) {
2019 for (i = 0; i < count; i++) {
2020 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002021 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002022 if (len < 0) {
2023 break;
2024 }
balrogd732dcb2008-10-28 10:21:03 +00002025 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2026 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002027 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002028 }
bellard579a97f2007-11-11 14:26:47 +00002029
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302030 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002031}
2032
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002033static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002034{
2035 int host_type = 0;
2036 int target_type = *type;
2037
2038 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2039 case TARGET_SOCK_DGRAM:
2040 host_type = SOCK_DGRAM;
2041 break;
2042 case TARGET_SOCK_STREAM:
2043 host_type = SOCK_STREAM;
2044 break;
2045 default:
2046 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2047 break;
2048 }
2049 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002050#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002051 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002052#else
2053 return -TARGET_EINVAL;
2054#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002055 }
2056 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002057#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002058 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002059#elif !defined(O_NONBLOCK)
2060 return -TARGET_EINVAL;
2061#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002062 }
2063 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002064 return 0;
2065}
2066
2067/* Try to emulate socket type flags after socket creation. */
2068static int sock_flags_fixup(int fd, int target_type)
2069{
2070#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2071 if (target_type & TARGET_SOCK_NONBLOCK) {
2072 int flags = fcntl(fd, F_GETFL);
2073 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2074 close(fd);
2075 return -TARGET_EINVAL;
2076 }
2077 }
2078#endif
2079 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002080}
2081
Laurent Vivier0cf22722015-10-28 21:40:45 +01002082static abi_long packet_target_to_host_sockaddr(void *host_addr,
2083 abi_ulong target_addr,
2084 socklen_t len)
2085{
2086 struct sockaddr *addr = host_addr;
2087 struct target_sockaddr *target_saddr;
2088
2089 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2090 if (!target_saddr) {
2091 return -TARGET_EFAULT;
2092 }
2093
2094 memcpy(addr, target_saddr, len);
2095 addr->sa_family = tswap16(target_saddr->sa_family);
2096 /* spkt_protocol is big-endian */
2097
2098 unlock_user(target_saddr, target_addr, 0);
2099 return 0;
2100}
2101
2102static TargetFdTrans target_packet_trans = {
2103 .target_to_host_addr = packet_target_to_host_sockaddr,
2104};
2105
ths0da46a62007-10-20 20:23:07 +00002106/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002107static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002108{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002109 int target_type = type;
2110 int ret;
2111
2112 ret = target_to_host_sock_type(&type);
2113 if (ret) {
2114 return ret;
2115 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002116
balrog12bc92a2007-10-30 21:06:14 +00002117 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07002118 return -TARGET_EAFNOSUPPORT;
Laurent Vivierff626f22015-10-28 21:40:42 +01002119
2120 if (domain == AF_PACKET ||
2121 (domain == AF_INET && type == SOCK_PACKET)) {
2122 protocol = tswap16(protocol);
2123 }
2124
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002125 ret = get_errno(socket(domain, type, protocol));
2126 if (ret >= 0) {
2127 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002128 if (type == SOCK_PACKET) {
2129 /* Manage an obsolete case :
2130 * if socket type is SOCK_PACKET, bind by name
2131 */
2132 fd_trans_register(ret, &target_packet_trans);
2133 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002134 }
2135 return ret;
bellard3532fa72006-06-24 15:06:03 +00002136}
2137
ths0da46a62007-10-20 20:23:07 +00002138/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002139static abi_long do_bind(int sockfd, abi_ulong target_addr,
2140 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002141{
aurel328f7aeaf2009-01-30 19:47:57 +00002142 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002143 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002144
Blue Swirl38724252010-09-18 05:53:14 +00002145 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002146 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002147 }
aurel328f7aeaf2009-01-30 19:47:57 +00002148
aurel32607175e2009-04-15 16:11:59 +00002149 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002150
Laurent Vivier7b36f782015-10-28 21:40:44 +01002151 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002152 if (ret)
2153 return ret;
2154
bellard3532fa72006-06-24 15:06:03 +00002155 return get_errno(bind(sockfd, addr, addrlen));
2156}
2157
ths0da46a62007-10-20 20:23:07 +00002158/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002159static abi_long do_connect(int sockfd, abi_ulong target_addr,
2160 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002161{
aurel328f7aeaf2009-01-30 19:47:57 +00002162 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002163 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002164
Blue Swirl38724252010-09-18 05:53:14 +00002165 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002166 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002167 }
aurel328f7aeaf2009-01-30 19:47:57 +00002168
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002169 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002170
Laurent Vivier7b36f782015-10-28 21:40:44 +01002171 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002172 if (ret)
2173 return ret;
2174
bellard3532fa72006-06-24 15:06:03 +00002175 return get_errno(connect(sockfd, addr, addrlen));
2176}
2177
Alexander Graff19e00d2014-03-02 19:36:42 +00002178/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2179static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2180 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002181{
balrog6de645c2008-10-28 10:26:29 +00002182 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002183 struct msghdr msg;
2184 int count;
2185 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002186 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002187
bellard3532fa72006-06-24 15:06:03 +00002188 if (msgp->msg_name) {
2189 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002190 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002191 ret = target_to_host_sockaddr(fd, msg.msg_name,
2192 tswapal(msgp->msg_name),
2193 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002194 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002195 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002196 }
bellard3532fa72006-06-24 15:06:03 +00002197 } else {
2198 msg.msg_name = NULL;
2199 msg.msg_namelen = 0;
2200 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002201 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002202 msg.msg_control = alloca(msg.msg_controllen);
2203 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002204
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002205 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002206 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002207 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2208 target_vec, count, send);
2209 if (vec == NULL) {
2210 ret = -host_to_target_errno(errno);
2211 goto out2;
2212 }
bellard3532fa72006-06-24 15:06:03 +00002213 msg.msg_iovlen = count;
2214 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002215
bellard3532fa72006-06-24 15:06:03 +00002216 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002217 ret = target_to_host_cmsg(&msg, msgp);
2218 if (ret == 0)
2219 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002220 } else {
2221 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002222 if (!is_error(ret)) {
2223 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002224 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002225 if (!is_error(ret)) {
2226 msgp->msg_namelen = tswap32(msg.msg_namelen);
2227 if (msg.msg_name != NULL) {
2228 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2229 msg.msg_name, msg.msg_namelen);
2230 if (ret) {
2231 goto out;
2232 }
2233 }
2234
balrog6de645c2008-10-28 10:26:29 +00002235 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002236 }
balrog6de645c2008-10-28 10:26:29 +00002237 }
bellard3532fa72006-06-24 15:06:03 +00002238 }
Jing Huangca619062012-07-24 13:58:02 +00002239
2240out:
bellard3532fa72006-06-24 15:06:03 +00002241 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002242out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002243 return ret;
2244}
2245
2246static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2247 int flags, int send)
2248{
2249 abi_long ret;
2250 struct target_msghdr *msgp;
2251
2252 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2253 msgp,
2254 target_msg,
2255 send ? 1 : 0)) {
2256 return -TARGET_EFAULT;
2257 }
2258 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002259 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002260 return ret;
2261}
2262
Alexander Graff19e00d2014-03-02 19:36:42 +00002263/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2264 * so it might not have this *mmsg-specific flag either.
2265 */
2266#ifndef MSG_WAITFORONE
2267#define MSG_WAITFORONE 0x10000
2268#endif
2269
2270static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2271 unsigned int vlen, unsigned int flags,
2272 int send)
2273{
2274 struct target_mmsghdr *mmsgp;
2275 abi_long ret = 0;
2276 int i;
2277
2278 if (vlen > UIO_MAXIOV) {
2279 vlen = UIO_MAXIOV;
2280 }
2281
2282 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2283 if (!mmsgp) {
2284 return -TARGET_EFAULT;
2285 }
2286
2287 for (i = 0; i < vlen; i++) {
2288 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2289 if (is_error(ret)) {
2290 break;
2291 }
2292 mmsgp[i].msg_len = tswap32(ret);
2293 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2294 if (flags & MSG_WAITFORONE) {
2295 flags |= MSG_DONTWAIT;
2296 }
2297 }
2298
2299 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2300
2301 /* Return number of datagrams sent if we sent any at all;
2302 * otherwise return the error.
2303 */
2304 if (i) {
2305 return i;
2306 }
2307 return ret;
2308}
Alexander Graff19e00d2014-03-02 19:36:42 +00002309
Peter Maydella94b4982013-02-08 04:35:04 +00002310/* If we don't have a system accept4() then just call accept.
2311 * The callsites to do_accept4() will ensure that they don't
2312 * pass a non-zero flags argument in this config.
2313 */
2314#ifndef CONFIG_ACCEPT4
2315static inline int accept4(int sockfd, struct sockaddr *addr,
2316 socklen_t *addrlen, int flags)
2317{
2318 assert(flags == 0);
2319 return accept(sockfd, addr, addrlen);
2320}
2321#endif
2322
2323/* do_accept4() Must return target values and target errnos. */
2324static abi_long do_accept4(int fd, abi_ulong target_addr,
2325 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002326{
bellard2f619692007-11-16 10:46:05 +00002327 socklen_t addrlen;
2328 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002329 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002330 int host_flags;
2331
2332 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002333
Peter Maydella94b4982013-02-08 04:35:04 +00002334 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002335 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002336 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002337
2338 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002339 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002340 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002341
Blue Swirl38724252010-09-18 05:53:14 +00002342 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002343 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002344 }
aurel328f7aeaf2009-01-30 19:47:57 +00002345
Arnaud Patard917507b2009-06-19 10:44:45 +03002346 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2347 return -TARGET_EINVAL;
2348
bellard2f619692007-11-16 10:46:05 +00002349 addr = alloca(addrlen);
2350
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002351 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002352 if (!is_error(ret)) {
2353 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002354 if (put_user_u32(addrlen, target_addrlen_addr))
2355 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002356 }
2357 return ret;
2358}
2359
ths0da46a62007-10-20 20:23:07 +00002360/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002361static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002362 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002363{
bellard2f619692007-11-16 10:46:05 +00002364 socklen_t addrlen;
2365 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002366 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002367
bellard2f619692007-11-16 10:46:05 +00002368 if (get_user_u32(addrlen, target_addrlen_addr))
2369 return -TARGET_EFAULT;
2370
Blue Swirl38724252010-09-18 05:53:14 +00002371 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002372 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002373 }
aurel328f7aeaf2009-01-30 19:47:57 +00002374
Arnaud Patard917507b2009-06-19 10:44:45 +03002375 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2376 return -TARGET_EFAULT;
2377
bellard2f619692007-11-16 10:46:05 +00002378 addr = alloca(addrlen);
2379
pbrook1be9e1d2006-11-19 15:26:04 +00002380 ret = get_errno(getpeername(fd, addr, &addrlen));
2381 if (!is_error(ret)) {
2382 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002383 if (put_user_u32(addrlen, target_addrlen_addr))
2384 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002385 }
2386 return ret;
2387}
2388
ths0da46a62007-10-20 20:23:07 +00002389/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002390static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002391 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002392{
bellard2f619692007-11-16 10:46:05 +00002393 socklen_t addrlen;
2394 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002395 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002396
bellard2f619692007-11-16 10:46:05 +00002397 if (get_user_u32(addrlen, target_addrlen_addr))
2398 return -TARGET_EFAULT;
2399
Blue Swirl38724252010-09-18 05:53:14 +00002400 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002401 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002402 }
aurel328f7aeaf2009-01-30 19:47:57 +00002403
Arnaud Patard917507b2009-06-19 10:44:45 +03002404 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2405 return -TARGET_EFAULT;
2406
bellard2f619692007-11-16 10:46:05 +00002407 addr = alloca(addrlen);
2408
pbrook1be9e1d2006-11-19 15:26:04 +00002409 ret = get_errno(getsockname(fd, addr, &addrlen));
2410 if (!is_error(ret)) {
2411 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002412 if (put_user_u32(addrlen, target_addrlen_addr))
2413 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002414 }
2415 return ret;
2416}
2417
ths0da46a62007-10-20 20:23:07 +00002418/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002419static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002420 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002421{
2422 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002423 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002424
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002425 target_to_host_sock_type(&type);
2426
pbrook1be9e1d2006-11-19 15:26:04 +00002427 ret = get_errno(socketpair(domain, type, protocol, tab));
2428 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002429 if (put_user_s32(tab[0], target_tab_addr)
2430 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2431 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002432 }
2433 return ret;
2434}
2435
ths0da46a62007-10-20 20:23:07 +00002436/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002437static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2438 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002439{
2440 void *addr;
2441 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002442 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002443
Blue Swirl38724252010-09-18 05:53:14 +00002444 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002445 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002446 }
aurel328f7aeaf2009-01-30 19:47:57 +00002447
bellard579a97f2007-11-11 14:26:47 +00002448 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2449 if (!host_msg)
2450 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002451 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002452 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002453 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002454 if (ret) {
2455 unlock_user(host_msg, msg, 0);
2456 return ret;
2457 }
pbrook1be9e1d2006-11-19 15:26:04 +00002458 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2459 } else {
2460 ret = get_errno(send(fd, host_msg, len, flags));
2461 }
2462 unlock_user(host_msg, msg, 0);
2463 return ret;
2464}
2465
ths0da46a62007-10-20 20:23:07 +00002466/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002467static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2468 abi_ulong target_addr,
2469 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002470{
2471 socklen_t addrlen;
2472 void *addr;
2473 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002474 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002475
bellard579a97f2007-11-11 14:26:47 +00002476 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2477 if (!host_msg)
2478 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002479 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002480 if (get_user_u32(addrlen, target_addrlen)) {
2481 ret = -TARGET_EFAULT;
2482 goto fail;
2483 }
Blue Swirl38724252010-09-18 05:53:14 +00002484 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002485 ret = -TARGET_EINVAL;
2486 goto fail;
2487 }
pbrook1be9e1d2006-11-19 15:26:04 +00002488 addr = alloca(addrlen);
2489 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2490 } else {
2491 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002492 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002493 }
2494 if (!is_error(ret)) {
2495 if (target_addr) {
2496 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002497 if (put_user_u32(addrlen, target_addrlen)) {
2498 ret = -TARGET_EFAULT;
2499 goto fail;
2500 }
pbrook1be9e1d2006-11-19 15:26:04 +00002501 }
2502 unlock_user(host_msg, msg, len);
2503 } else {
bellard2f619692007-11-16 10:46:05 +00002504fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002505 unlock_user(host_msg, msg, 0);
2506 }
2507 return ret;
2508}
2509
j_mayer32407102007-09-26 23:01:49 +00002510#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002511/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002512static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002513{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002514 static const unsigned ac[] = { /* number of arguments per call */
2515 [SOCKOP_socket] = 3, /* domain, type, protocol */
2516 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2517 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2518 [SOCKOP_listen] = 2, /* sockfd, backlog */
2519 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2520 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2521 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2522 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2523 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2524 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2525 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2526 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2527 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2528 [SOCKOP_shutdown] = 2, /* sockfd, how */
2529 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2530 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002531 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
2532 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002533 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2534 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2535 };
2536 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002537
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002538 /* first, collect the arguments in a[] according to ac[] */
2539 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2540 unsigned i;
2541 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2542 for (i = 0; i < ac[num]; ++i) {
2543 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002544 return -TARGET_EFAULT;
2545 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002546 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002547 }
bellard2f619692007-11-16 10:46:05 +00002548
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002549 /* now when we have the args, actually handle the call */
2550 switch (num) {
2551 case SOCKOP_socket: /* domain, type, protocol */
2552 return do_socket(a[0], a[1], a[2]);
2553 case SOCKOP_bind: /* sockfd, addr, addrlen */
2554 return do_bind(a[0], a[1], a[2]);
2555 case SOCKOP_connect: /* sockfd, addr, addrlen */
2556 return do_connect(a[0], a[1], a[2]);
2557 case SOCKOP_listen: /* sockfd, backlog */
2558 return get_errno(listen(a[0], a[1]));
2559 case SOCKOP_accept: /* sockfd, addr, addrlen */
2560 return do_accept4(a[0], a[1], a[2], 0);
2561 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2562 return do_accept4(a[0], a[1], a[2], a[3]);
2563 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2564 return do_getsockname(a[0], a[1], a[2]);
2565 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2566 return do_getpeername(a[0], a[1], a[2]);
2567 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2568 return do_socketpair(a[0], a[1], a[2], a[3]);
2569 case SOCKOP_send: /* sockfd, msg, len, flags */
2570 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2571 case SOCKOP_recv: /* sockfd, msg, len, flags */
2572 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2573 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2574 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2575 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2576 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2577 case SOCKOP_shutdown: /* sockfd, how */
2578 return get_errno(shutdown(a[0], a[1]));
2579 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2580 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2581 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2582 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002583 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
2584 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
2585 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
2586 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002587 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2588 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2589 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2590 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002591 default:
2592 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002593 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002594 }
bellard31e31b82003-02-18 22:55:36 +00002595}
j_mayer32407102007-09-26 23:01:49 +00002596#endif
bellard31e31b82003-02-18 22:55:36 +00002597
bellard8853f862004-02-22 14:57:26 +00002598#define N_SHM_REGIONS 32
2599
2600static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002601 abi_ulong start;
2602 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002603} shm_regions[N_SHM_REGIONS];
2604
ths3eb6b042007-06-03 14:26:27 +00002605struct target_semid_ds
2606{
2607 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002608 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002609#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002610 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002611#endif
blueswir1992f48a2007-10-14 16:27:31 +00002612 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002613#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002614 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002615#endif
blueswir1992f48a2007-10-14 16:27:31 +00002616 abi_ulong sem_nsems;
2617 abi_ulong __unused3;
2618 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002619};
2620
bellard579a97f2007-11-11 14:26:47 +00002621static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2622 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002623{
2624 struct target_ipc_perm *target_ip;
2625 struct target_semid_ds *target_sd;
2626
bellard579a97f2007-11-11 14:26:47 +00002627 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2628 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002629 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002630 host_ip->__key = tswap32(target_ip->__key);
2631 host_ip->uid = tswap32(target_ip->uid);
2632 host_ip->gid = tswap32(target_ip->gid);
2633 host_ip->cuid = tswap32(target_ip->cuid);
2634 host_ip->cgid = tswap32(target_ip->cgid);
2635#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2636 host_ip->mode = tswap32(target_ip->mode);
2637#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002638 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002639#endif
2640#if defined(TARGET_PPC)
2641 host_ip->__seq = tswap32(target_ip->__seq);
2642#else
2643 host_ip->__seq = tswap16(target_ip->__seq);
2644#endif
ths3eb6b042007-06-03 14:26:27 +00002645 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002646 return 0;
ths3eb6b042007-06-03 14:26:27 +00002647}
2648
bellard579a97f2007-11-11 14:26:47 +00002649static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2650 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002651{
2652 struct target_ipc_perm *target_ip;
2653 struct target_semid_ds *target_sd;
2654
bellard579a97f2007-11-11 14:26:47 +00002655 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2656 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002657 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002658 target_ip->__key = tswap32(host_ip->__key);
2659 target_ip->uid = tswap32(host_ip->uid);
2660 target_ip->gid = tswap32(host_ip->gid);
2661 target_ip->cuid = tswap32(host_ip->cuid);
2662 target_ip->cgid = tswap32(host_ip->cgid);
2663#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2664 target_ip->mode = tswap32(host_ip->mode);
2665#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002666 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002667#endif
2668#if defined(TARGET_PPC)
2669 target_ip->__seq = tswap32(host_ip->__seq);
2670#else
2671 target_ip->__seq = tswap16(host_ip->__seq);
2672#endif
ths3eb6b042007-06-03 14:26:27 +00002673 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002674 return 0;
ths3eb6b042007-06-03 14:26:27 +00002675}
2676
bellard579a97f2007-11-11 14:26:47 +00002677static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2678 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002679{
2680 struct target_semid_ds *target_sd;
2681
bellard579a97f2007-11-11 14:26:47 +00002682 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2683 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002684 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2685 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002686 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2687 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2688 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002689 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002690 return 0;
ths3eb6b042007-06-03 14:26:27 +00002691}
2692
bellard579a97f2007-11-11 14:26:47 +00002693static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2694 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002695{
2696 struct target_semid_ds *target_sd;
2697
bellard579a97f2007-11-11 14:26:47 +00002698 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2699 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002700 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002701 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002702 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2703 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2704 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002705 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002706 return 0;
ths3eb6b042007-06-03 14:26:27 +00002707}
2708
aurel32e5289082009-04-18 16:16:12 +00002709struct target_seminfo {
2710 int semmap;
2711 int semmni;
2712 int semmns;
2713 int semmnu;
2714 int semmsl;
2715 int semopm;
2716 int semume;
2717 int semusz;
2718 int semvmx;
2719 int semaem;
2720};
2721
2722static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2723 struct seminfo *host_seminfo)
2724{
2725 struct target_seminfo *target_seminfo;
2726 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2727 return -TARGET_EFAULT;
2728 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2729 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2730 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2731 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2732 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2733 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2734 __put_user(host_seminfo->semume, &target_seminfo->semume);
2735 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2736 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2737 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2738 unlock_user_struct(target_seminfo, target_addr, 1);
2739 return 0;
2740}
2741
thsfa294812007-02-02 22:05:00 +00002742union semun {
2743 int val;
ths3eb6b042007-06-03 14:26:27 +00002744 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002745 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002746 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002747};
2748
ths3eb6b042007-06-03 14:26:27 +00002749union target_semun {
2750 int val;
aurel32e5289082009-04-18 16:16:12 +00002751 abi_ulong buf;
2752 abi_ulong array;
2753 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002754};
2755
aurel32e5289082009-04-18 16:16:12 +00002756static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2757 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002758{
aurel32e5289082009-04-18 16:16:12 +00002759 int nsems;
2760 unsigned short *array;
2761 union semun semun;
2762 struct semid_ds semid_ds;
2763 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002764
aurel32e5289082009-04-18 16:16:12 +00002765 semun.buf = &semid_ds;
2766
2767 ret = semctl(semid, 0, IPC_STAT, semun);
2768 if (ret == -1)
2769 return get_errno(ret);
2770
2771 nsems = semid_ds.sem_nsems;
2772
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302773 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00002774 if (!*host_array) {
2775 return -TARGET_ENOMEM;
2776 }
aurel32e5289082009-04-18 16:16:12 +00002777 array = lock_user(VERIFY_READ, target_addr,
2778 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002779 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302780 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002781 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002782 }
aurel32e5289082009-04-18 16:16:12 +00002783
2784 for(i=0; i<nsems; i++) {
2785 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002786 }
aurel32e5289082009-04-18 16:16:12 +00002787 unlock_user(array, target_addr, 0);
2788
bellard579a97f2007-11-11 14:26:47 +00002789 return 0;
ths3eb6b042007-06-03 14:26:27 +00002790}
2791
aurel32e5289082009-04-18 16:16:12 +00002792static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2793 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002794{
aurel32e5289082009-04-18 16:16:12 +00002795 int nsems;
2796 unsigned short *array;
2797 union semun semun;
2798 struct semid_ds semid_ds;
2799 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002800
aurel32e5289082009-04-18 16:16:12 +00002801 semun.buf = &semid_ds;
2802
2803 ret = semctl(semid, 0, IPC_STAT, semun);
2804 if (ret == -1)
2805 return get_errno(ret);
2806
2807 nsems = semid_ds.sem_nsems;
2808
2809 array = lock_user(VERIFY_WRITE, target_addr,
2810 nsems*sizeof(unsigned short), 0);
2811 if (!array)
2812 return -TARGET_EFAULT;
2813
2814 for(i=0; i<nsems; i++) {
2815 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002816 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302817 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002818 unlock_user(array, target_addr, 1);
2819
bellard579a97f2007-11-11 14:26:47 +00002820 return 0;
ths3eb6b042007-06-03 14:26:27 +00002821}
2822
aurel32e5289082009-04-18 16:16:12 +00002823static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01002824 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00002825{
Stefan Weild1c002b2015-02-08 15:40:58 +01002826 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00002827 union semun arg;
2828 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302829 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002830 struct seminfo seminfo;
2831 abi_long ret = -TARGET_EINVAL;
2832 abi_long err;
2833 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002834
2835 switch( cmd ) {
2836 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002837 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002838 /* In 64 bit cross-endian situations, we will erroneously pick up
2839 * the wrong half of the union for the "val" element. To rectify
2840 * this, the entire 8-byte structure is byteswapped, followed by
2841 * a swap of the 4 byte val field. In other cases, the data is
2842 * already in proper host byte order. */
2843 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2844 target_su.buf = tswapal(target_su.buf);
2845 arg.val = tswap32(target_su.val);
2846 } else {
2847 arg.val = target_su.val;
2848 }
aurel32e5289082009-04-18 16:16:12 +00002849 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002850 break;
2851 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002852 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002853 err = target_to_host_semarray(semid, &array, target_su.array);
2854 if (err)
2855 return err;
2856 arg.array = array;
2857 ret = get_errno(semctl(semid, semnum, cmd, arg));
2858 err = host_to_target_semarray(semid, target_su.array, &array);
2859 if (err)
2860 return err;
ths3eb6b042007-06-03 14:26:27 +00002861 break;
2862 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002863 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002864 case SEM_STAT:
2865 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2866 if (err)
2867 return err;
2868 arg.buf = &dsarg;
2869 ret = get_errno(semctl(semid, semnum, cmd, arg));
2870 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2871 if (err)
2872 return err;
ths3eb6b042007-06-03 14:26:27 +00002873 break;
aurel32e5289082009-04-18 16:16:12 +00002874 case IPC_INFO:
2875 case SEM_INFO:
2876 arg.__buf = &seminfo;
2877 ret = get_errno(semctl(semid, semnum, cmd, arg));
2878 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2879 if (err)
2880 return err;
2881 break;
2882 case IPC_RMID:
2883 case GETPID:
2884 case GETNCNT:
2885 case GETZCNT:
2886 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2887 break;
ths3eb6b042007-06-03 14:26:27 +00002888 }
2889
2890 return ret;
2891}
2892
aurel32e5289082009-04-18 16:16:12 +00002893struct target_sembuf {
2894 unsigned short sem_num;
2895 short sem_op;
2896 short sem_flg;
2897};
2898
2899static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2900 abi_ulong target_addr,
2901 unsigned nsops)
2902{
2903 struct target_sembuf *target_sembuf;
2904 int i;
2905
2906 target_sembuf = lock_user(VERIFY_READ, target_addr,
2907 nsops*sizeof(struct target_sembuf), 1);
2908 if (!target_sembuf)
2909 return -TARGET_EFAULT;
2910
2911 for(i=0; i<nsops; i++) {
2912 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2913 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2914 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2915 }
2916
2917 unlock_user(target_sembuf, target_addr, 0);
2918
2919 return 0;
2920}
2921
2922static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2923{
2924 struct sembuf sops[nsops];
2925
2926 if (target_to_host_sembuf(sops, ptr, nsops))
2927 return -TARGET_EFAULT;
2928
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002929 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002930}
2931
ths1bc012f2007-06-03 14:27:49 +00002932struct target_msqid_ds
2933{
aurel321c54ff92008-10-13 21:08:44 +00002934 struct target_ipc_perm msg_perm;
2935 abi_ulong msg_stime;
2936#if TARGET_ABI_BITS == 32
2937 abi_ulong __unused1;
2938#endif
2939 abi_ulong msg_rtime;
2940#if TARGET_ABI_BITS == 32
2941 abi_ulong __unused2;
2942#endif
2943 abi_ulong msg_ctime;
2944#if TARGET_ABI_BITS == 32
2945 abi_ulong __unused3;
2946#endif
2947 abi_ulong __msg_cbytes;
2948 abi_ulong msg_qnum;
2949 abi_ulong msg_qbytes;
2950 abi_ulong msg_lspid;
2951 abi_ulong msg_lrpid;
2952 abi_ulong __unused4;
2953 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002954};
2955
bellard579a97f2007-11-11 14:26:47 +00002956static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2957 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002958{
2959 struct target_msqid_ds *target_md;
2960
bellard579a97f2007-11-11 14:26:47 +00002961 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2962 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002963 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2964 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002965 host_md->msg_stime = tswapal(target_md->msg_stime);
2966 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2967 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2968 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2969 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2970 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2971 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2972 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002973 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002974 return 0;
ths1bc012f2007-06-03 14:27:49 +00002975}
2976
bellard579a97f2007-11-11 14:26:47 +00002977static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2978 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002979{
2980 struct target_msqid_ds *target_md;
2981
bellard579a97f2007-11-11 14:26:47 +00002982 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2983 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002984 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2985 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002986 target_md->msg_stime = tswapal(host_md->msg_stime);
2987 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2988 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2989 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2990 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2991 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2992 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2993 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002994 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002995 return 0;
ths1bc012f2007-06-03 14:27:49 +00002996}
2997
aurel321c54ff92008-10-13 21:08:44 +00002998struct target_msginfo {
2999 int msgpool;
3000 int msgmap;
3001 int msgmax;
3002 int msgmnb;
3003 int msgmni;
3004 int msgssz;
3005 int msgtql;
3006 unsigned short int msgseg;
3007};
3008
3009static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3010 struct msginfo *host_msginfo)
3011{
3012 struct target_msginfo *target_msginfo;
3013 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3014 return -TARGET_EFAULT;
3015 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3016 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3017 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3018 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3019 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3020 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3021 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3022 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3023 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003024 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003025}
3026
3027static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003028{
3029 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003030 struct msginfo msginfo;
3031 abi_long ret = -TARGET_EINVAL;
3032
3033 cmd &= 0xff;
3034
3035 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003036 case IPC_STAT:
3037 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003038 case MSG_STAT:
3039 if (target_to_host_msqid_ds(&dsarg,ptr))
3040 return -TARGET_EFAULT;
3041 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3042 if (host_to_target_msqid_ds(ptr,&dsarg))
3043 return -TARGET_EFAULT;
3044 break;
3045 case IPC_RMID:
3046 ret = get_errno(msgctl(msgid, cmd, NULL));
3047 break;
3048 case IPC_INFO:
3049 case MSG_INFO:
3050 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3051 if (host_to_target_msginfo(ptr, &msginfo))
3052 return -TARGET_EFAULT;
3053 break;
ths1bc012f2007-06-03 14:27:49 +00003054 }
aurel321c54ff92008-10-13 21:08:44 +00003055
ths1bc012f2007-06-03 14:27:49 +00003056 return ret;
3057}
3058
3059struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003060 abi_long mtype;
3061 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003062};
3063
blueswir1992f48a2007-10-14 16:27:31 +00003064static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003065 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003066{
3067 struct target_msgbuf *target_mb;
3068 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003069 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003070
Tom Mustaedcc5f92014-08-12 13:53:37 -05003071 if (msgsz < 0) {
3072 return -TARGET_EINVAL;
3073 }
3074
bellard579a97f2007-11-11 14:26:47 +00003075 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3076 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303077 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003078 if (!host_mb) {
3079 unlock_user_struct(target_mb, msgp, 0);
3080 return -TARGET_ENOMEM;
3081 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003082 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003083 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00003084 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303085 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003086 unlock_user_struct(target_mb, msgp, 0);
3087
3088 return ret;
3089}
3090
blueswir1992f48a2007-10-14 16:27:31 +00003091static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00003092 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003093 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003094{
3095 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003096 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003097 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003098 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003099
bellard579a97f2007-11-11 14:26:47 +00003100 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3101 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003102
Jim Meyering0d07fe42012-08-22 13:55:53 +02003103 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003104 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003105
bellard579a97f2007-11-11 14:26:47 +00003106 if (ret > 0) {
3107 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3108 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3109 if (!target_mtext) {
3110 ret = -TARGET_EFAULT;
3111 goto end;
3112 }
aurel321c54ff92008-10-13 21:08:44 +00003113 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003114 unlock_user(target_mtext, target_mtext_addr, ret);
3115 }
aurel321c54ff92008-10-13 21:08:44 +00003116
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003117 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003118
bellard579a97f2007-11-11 14:26:47 +00003119end:
3120 if (target_mb)
3121 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003122 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003123 return ret;
3124}
3125
Riku Voipio88a8c982009-04-03 10:42:00 +03003126static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3127 abi_ulong target_addr)
3128{
3129 struct target_shmid_ds *target_sd;
3130
3131 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3132 return -TARGET_EFAULT;
3133 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3134 return -TARGET_EFAULT;
3135 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3136 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3137 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3138 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3139 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3140 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3141 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3142 unlock_user_struct(target_sd, target_addr, 0);
3143 return 0;
3144}
3145
3146static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3147 struct shmid_ds *host_sd)
3148{
3149 struct target_shmid_ds *target_sd;
3150
3151 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3152 return -TARGET_EFAULT;
3153 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3154 return -TARGET_EFAULT;
3155 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3156 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3157 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3158 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3159 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3160 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3161 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3162 unlock_user_struct(target_sd, target_addr, 1);
3163 return 0;
3164}
3165
3166struct target_shminfo {
3167 abi_ulong shmmax;
3168 abi_ulong shmmin;
3169 abi_ulong shmmni;
3170 abi_ulong shmseg;
3171 abi_ulong shmall;
3172};
3173
3174static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3175 struct shminfo *host_shminfo)
3176{
3177 struct target_shminfo *target_shminfo;
3178 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3179 return -TARGET_EFAULT;
3180 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3181 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3182 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3183 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3184 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3185 unlock_user_struct(target_shminfo, target_addr, 1);
3186 return 0;
3187}
3188
3189struct target_shm_info {
3190 int used_ids;
3191 abi_ulong shm_tot;
3192 abi_ulong shm_rss;
3193 abi_ulong shm_swp;
3194 abi_ulong swap_attempts;
3195 abi_ulong swap_successes;
3196};
3197
3198static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3199 struct shm_info *host_shm_info)
3200{
3201 struct target_shm_info *target_shm_info;
3202 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3203 return -TARGET_EFAULT;
3204 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3205 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3206 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3207 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3208 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3209 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3210 unlock_user_struct(target_shm_info, target_addr, 1);
3211 return 0;
3212}
3213
3214static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3215{
3216 struct shmid_ds dsarg;
3217 struct shminfo shminfo;
3218 struct shm_info shm_info;
3219 abi_long ret = -TARGET_EINVAL;
3220
3221 cmd &= 0xff;
3222
3223 switch(cmd) {
3224 case IPC_STAT:
3225 case IPC_SET:
3226 case SHM_STAT:
3227 if (target_to_host_shmid_ds(&dsarg, buf))
3228 return -TARGET_EFAULT;
3229 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3230 if (host_to_target_shmid_ds(buf, &dsarg))
3231 return -TARGET_EFAULT;
3232 break;
3233 case IPC_INFO:
3234 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3235 if (host_to_target_shminfo(buf, &shminfo))
3236 return -TARGET_EFAULT;
3237 break;
3238 case SHM_INFO:
3239 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3240 if (host_to_target_shm_info(buf, &shm_info))
3241 return -TARGET_EFAULT;
3242 break;
3243 case IPC_RMID:
3244 case SHM_LOCK:
3245 case SHM_UNLOCK:
3246 ret = get_errno(shmctl(shmid, cmd, NULL));
3247 break;
3248 }
3249
3250 return ret;
3251}
3252
3253static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3254{
3255 abi_long raddr;
3256 void *host_raddr;
3257 struct shmid_ds shm_info;
3258 int i,ret;
3259
3260 /* find out the length of the shared memory segment */
3261 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3262 if (is_error(ret)) {
3263 /* can't get length, bail out */
3264 return ret;
3265 }
3266
3267 mmap_lock();
3268
3269 if (shmaddr)
3270 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3271 else {
3272 abi_ulong mmap_start;
3273
3274 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3275
3276 if (mmap_start == -1) {
3277 errno = ENOMEM;
3278 host_raddr = (void *)-1;
3279 } else
3280 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3281 }
3282
3283 if (host_raddr == (void *)-1) {
3284 mmap_unlock();
3285 return get_errno((long)host_raddr);
3286 }
3287 raddr=h2g((unsigned long)host_raddr);
3288
3289 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3290 PAGE_VALID | PAGE_READ |
3291 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3292
3293 for (i = 0; i < N_SHM_REGIONS; i++) {
3294 if (shm_regions[i].start == 0) {
3295 shm_regions[i].start = raddr;
3296 shm_regions[i].size = shm_info.shm_segsz;
3297 break;
3298 }
3299 }
3300
3301 mmap_unlock();
3302 return raddr;
3303
3304}
3305
3306static inline abi_long do_shmdt(abi_ulong shmaddr)
3307{
3308 int i;
3309
3310 for (i = 0; i < N_SHM_REGIONS; ++i) {
3311 if (shm_regions[i].start == shmaddr) {
3312 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003313 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003314 break;
3315 }
3316 }
3317
3318 return get_errno(shmdt(g2h(shmaddr)));
3319}
3320
aurel321c54ff92008-10-13 21:08:44 +00003321#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003322/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003323/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003324static abi_long do_ipc(unsigned int call, abi_long first,
3325 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003326 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003327{
3328 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003329 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003330
3331 version = call >> 16;
3332 call &= 0xffff;
3333
3334 switch (call) {
thsfa294812007-02-02 22:05:00 +00003335 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003336 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003337 break;
3338
3339 case IPCOP_semget:
3340 ret = get_errno(semget(first, second, third));
3341 break;
3342
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003343 case IPCOP_semctl: {
3344 /* The semun argument to semctl is passed by value, so dereference the
3345 * ptr argument. */
3346 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003347 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01003348 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00003349 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003350 }
thsd96372e2007-02-02 22:05:44 +00003351
aurel321c54ff92008-10-13 21:08:44 +00003352 case IPCOP_msgget:
3353 ret = get_errno(msgget(first, second));
3354 break;
thsd96372e2007-02-02 22:05:44 +00003355
aurel321c54ff92008-10-13 21:08:44 +00003356 case IPCOP_msgsnd:
3357 ret = do_msgsnd(first, ptr, second, third);
3358 break;
thsd96372e2007-02-02 22:05:44 +00003359
aurel321c54ff92008-10-13 21:08:44 +00003360 case IPCOP_msgctl:
3361 ret = do_msgctl(first, second, ptr);
3362 break;
thsd96372e2007-02-02 22:05:44 +00003363
aurel321c54ff92008-10-13 21:08:44 +00003364 case IPCOP_msgrcv:
3365 switch (version) {
3366 case 0:
3367 {
3368 struct target_ipc_kludge {
3369 abi_long msgp;
3370 abi_long msgtyp;
3371 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003372
aurel321c54ff92008-10-13 21:08:44 +00003373 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3374 ret = -TARGET_EFAULT;
3375 break;
ths1bc012f2007-06-03 14:27:49 +00003376 }
aurel321c54ff92008-10-13 21:08:44 +00003377
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003378 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003379
3380 unlock_user_struct(tmp, ptr, 0);
3381 break;
3382 }
3383 default:
3384 ret = do_msgrcv(first, ptr, second, fifth, third);
3385 }
3386 break;
thsd96372e2007-02-02 22:05:44 +00003387
bellard8853f862004-02-22 14:57:26 +00003388 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003389 switch (version) {
3390 default:
bellard5a4a8982007-11-11 17:39:18 +00003391 {
3392 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003393 raddr = do_shmat(first, ptr, second);
3394 if (is_error(raddr))
3395 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003396 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003397 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003398 break;
3399 }
3400 case 1:
3401 ret = -TARGET_EINVAL;
3402 break;
bellard5a4a8982007-11-11 17:39:18 +00003403 }
bellard8853f862004-02-22 14:57:26 +00003404 break;
3405 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003406 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003407 break;
3408
3409 case IPCOP_shmget:
3410 /* IPC_* flag values are the same on all linux platforms */
3411 ret = get_errno(shmget(first, second, third));
3412 break;
3413
3414 /* IPC_* and SHM_* command values are the same on all linux platforms */
3415 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003416 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003417 break;
3418 default:
j_mayer32407102007-09-26 23:01:49 +00003419 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003420 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003421 break;
3422 }
3423 return ret;
3424}
j_mayer32407102007-09-26 23:01:49 +00003425#endif
bellard8853f862004-02-22 14:57:26 +00003426
bellard31e31b82003-02-18 22:55:36 +00003427/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003428
Blue Swirl001faf32009-05-13 17:53:17 +00003429#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003430#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3431enum {
3432#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02003433STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00003434};
3435#undef STRUCT
3436#undef STRUCT_SPECIAL
3437
Blue Swirl001faf32009-05-13 17:53:17 +00003438#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003439#define STRUCT_SPECIAL(name)
3440#include "syscall_types.h"
3441#undef STRUCT
3442#undef STRUCT_SPECIAL
3443
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003444typedef struct IOCTLEntry IOCTLEntry;
3445
3446typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003447 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003448
3449struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08003450 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00003451 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003452 const char *name;
3453 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003454 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003455 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003456};
bellard31e31b82003-02-18 22:55:36 +00003457
3458#define IOC_R 0x0001
3459#define IOC_W 0x0002
3460#define IOC_RW (IOC_R | IOC_W)
3461
3462#define MAX_STRUCT_SIZE 4096
3463
Peter Maydelldace20d2011-01-10 13:11:24 +00003464#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003465/* So fiemap access checks don't overflow on 32 bit systems.
3466 * This is very slightly smaller than the limit imposed by
3467 * the underlying kernel.
3468 */
3469#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3470 / sizeof(struct fiemap_extent))
3471
3472static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003473 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00003474{
3475 /* The parameter for this ioctl is a struct fiemap followed
3476 * by an array of struct fiemap_extent whose size is set
3477 * in fiemap->fm_extent_count. The array is filled in by the
3478 * ioctl.
3479 */
3480 int target_size_in, target_size_out;
3481 struct fiemap *fm;
3482 const argtype *arg_type = ie->arg_type;
3483 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3484 void *argptr, *p;
3485 abi_long ret;
3486 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3487 uint32_t outbufsz;
3488 int free_fm = 0;
3489
3490 assert(arg_type[0] == TYPE_PTR);
3491 assert(ie->access == IOC_RW);
3492 arg_type++;
3493 target_size_in = thunk_type_size(arg_type, 0);
3494 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3495 if (!argptr) {
3496 return -TARGET_EFAULT;
3497 }
3498 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3499 unlock_user(argptr, arg, 0);
3500 fm = (struct fiemap *)buf_temp;
3501 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3502 return -TARGET_EINVAL;
3503 }
3504
3505 outbufsz = sizeof (*fm) +
3506 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3507
3508 if (outbufsz > MAX_STRUCT_SIZE) {
3509 /* We can't fit all the extents into the fixed size buffer.
3510 * Allocate one that is large enough and use it instead.
3511 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303512 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00003513 if (!fm) {
3514 return -TARGET_ENOMEM;
3515 }
3516 memcpy(fm, buf_temp, sizeof(struct fiemap));
3517 free_fm = 1;
3518 }
3519 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3520 if (!is_error(ret)) {
3521 target_size_out = target_size_in;
3522 /* An extent_count of 0 means we were only counting the extents
3523 * so there are no structs to copy
3524 */
3525 if (fm->fm_extent_count != 0) {
3526 target_size_out += fm->fm_mapped_extents * extent_size;
3527 }
3528 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3529 if (!argptr) {
3530 ret = -TARGET_EFAULT;
3531 } else {
3532 /* Convert the struct fiemap */
3533 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3534 if (fm->fm_extent_count != 0) {
3535 p = argptr + target_size_in;
3536 /* ...and then all the struct fiemap_extents */
3537 for (i = 0; i < fm->fm_mapped_extents; i++) {
3538 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3539 THUNK_TARGET);
3540 p += extent_size;
3541 }
3542 }
3543 unlock_user(argptr, arg, target_size_out);
3544 }
3545 }
3546 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303547 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00003548 }
3549 return ret;
3550}
Peter Maydelldace20d2011-01-10 13:11:24 +00003551#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003552
Laurent Vivier059c2f22011-03-30 00:12:12 +02003553static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003554 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02003555{
3556 const argtype *arg_type = ie->arg_type;
3557 int target_size;
3558 void *argptr;
3559 int ret;
3560 struct ifconf *host_ifconf;
3561 uint32_t outbufsz;
3562 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3563 int target_ifreq_size;
3564 int nb_ifreq;
3565 int free_buf = 0;
3566 int i;
3567 int target_ifc_len;
3568 abi_long target_ifc_buf;
3569 int host_ifc_len;
3570 char *host_ifc_buf;
3571
3572 assert(arg_type[0] == TYPE_PTR);
3573 assert(ie->access == IOC_RW);
3574
3575 arg_type++;
3576 target_size = thunk_type_size(arg_type, 0);
3577
3578 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3579 if (!argptr)
3580 return -TARGET_EFAULT;
3581 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3582 unlock_user(argptr, arg, 0);
3583
3584 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3585 target_ifc_len = host_ifconf->ifc_len;
3586 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3587
3588 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3589 nb_ifreq = target_ifc_len / target_ifreq_size;
3590 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3591
3592 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3593 if (outbufsz > MAX_STRUCT_SIZE) {
3594 /* We can't fit all the extents into the fixed size buffer.
3595 * Allocate one that is large enough and use it instead.
3596 */
3597 host_ifconf = malloc(outbufsz);
3598 if (!host_ifconf) {
3599 return -TARGET_ENOMEM;
3600 }
3601 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3602 free_buf = 1;
3603 }
3604 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3605
3606 host_ifconf->ifc_len = host_ifc_len;
3607 host_ifconf->ifc_buf = host_ifc_buf;
3608
3609 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3610 if (!is_error(ret)) {
3611 /* convert host ifc_len to target ifc_len */
3612
3613 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3614 target_ifc_len = nb_ifreq * target_ifreq_size;
3615 host_ifconf->ifc_len = target_ifc_len;
3616
3617 /* restore target ifc_buf */
3618
3619 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3620
3621 /* copy struct ifconf to target user */
3622
3623 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3624 if (!argptr)
3625 return -TARGET_EFAULT;
3626 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3627 unlock_user(argptr, arg, target_size);
3628
3629 /* copy ifreq[] to target user */
3630
3631 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3632 for (i = 0; i < nb_ifreq ; i++) {
3633 thunk_convert(argptr + i * target_ifreq_size,
3634 host_ifc_buf + i * sizeof(struct ifreq),
3635 ifreq_arg_type, THUNK_TARGET);
3636 }
3637 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3638 }
3639
3640 if (free_buf) {
3641 free(host_ifconf);
3642 }
3643
3644 return ret;
3645}
3646
Alexander Graf56e904e2012-01-31 18:42:06 +01003647static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003648 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01003649{
3650 void *argptr;
3651 struct dm_ioctl *host_dm;
3652 abi_long guest_data;
3653 uint32_t guest_data_size;
3654 int target_size;
3655 const argtype *arg_type = ie->arg_type;
3656 abi_long ret;
3657 void *big_buf = NULL;
3658 char *host_data;
3659
3660 arg_type++;
3661 target_size = thunk_type_size(arg_type, 0);
3662 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3663 if (!argptr) {
3664 ret = -TARGET_EFAULT;
3665 goto out;
3666 }
3667 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3668 unlock_user(argptr, arg, 0);
3669
3670 /* buf_temp is too small, so fetch things into a bigger buffer */
3671 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3672 memcpy(big_buf, buf_temp, target_size);
3673 buf_temp = big_buf;
3674 host_dm = big_buf;
3675
3676 guest_data = arg + host_dm->data_start;
3677 if ((guest_data - arg) < 0) {
3678 ret = -EINVAL;
3679 goto out;
3680 }
3681 guest_data_size = host_dm->data_size - host_dm->data_start;
3682 host_data = (char*)host_dm + host_dm->data_start;
3683
3684 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3685 switch (ie->host_cmd) {
3686 case DM_REMOVE_ALL:
3687 case DM_LIST_DEVICES:
3688 case DM_DEV_CREATE:
3689 case DM_DEV_REMOVE:
3690 case DM_DEV_SUSPEND:
3691 case DM_DEV_STATUS:
3692 case DM_DEV_WAIT:
3693 case DM_TABLE_STATUS:
3694 case DM_TABLE_CLEAR:
3695 case DM_TABLE_DEPS:
3696 case DM_LIST_VERSIONS:
3697 /* no input data */
3698 break;
3699 case DM_DEV_RENAME:
3700 case DM_DEV_SET_GEOMETRY:
3701 /* data contains only strings */
3702 memcpy(host_data, argptr, guest_data_size);
3703 break;
3704 case DM_TARGET_MSG:
3705 memcpy(host_data, argptr, guest_data_size);
3706 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3707 break;
3708 case DM_TABLE_LOAD:
3709 {
3710 void *gspec = argptr;
3711 void *cur_data = host_data;
3712 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3713 int spec_size = thunk_type_size(arg_type, 0);
3714 int i;
3715
3716 for (i = 0; i < host_dm->target_count; i++) {
3717 struct dm_target_spec *spec = cur_data;
3718 uint32_t next;
3719 int slen;
3720
3721 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3722 slen = strlen((char*)gspec + spec_size) + 1;
3723 next = spec->next;
3724 spec->next = sizeof(*spec) + slen;
3725 strcpy((char*)&spec[1], gspec + spec_size);
3726 gspec += next;
3727 cur_data += spec->next;
3728 }
3729 break;
3730 }
3731 default:
3732 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08003733 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003734 goto out;
3735 }
3736 unlock_user(argptr, guest_data, 0);
3737
3738 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3739 if (!is_error(ret)) {
3740 guest_data = arg + host_dm->data_start;
3741 guest_data_size = host_dm->data_size - host_dm->data_start;
3742 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3743 switch (ie->host_cmd) {
3744 case DM_REMOVE_ALL:
3745 case DM_DEV_CREATE:
3746 case DM_DEV_REMOVE:
3747 case DM_DEV_RENAME:
3748 case DM_DEV_SUSPEND:
3749 case DM_DEV_STATUS:
3750 case DM_TABLE_LOAD:
3751 case DM_TABLE_CLEAR:
3752 case DM_TARGET_MSG:
3753 case DM_DEV_SET_GEOMETRY:
3754 /* no return data */
3755 break;
3756 case DM_LIST_DEVICES:
3757 {
3758 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3759 uint32_t remaining_data = guest_data_size;
3760 void *cur_data = argptr;
3761 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3762 int nl_size = 12; /* can't use thunk_size due to alignment */
3763
3764 while (1) {
3765 uint32_t next = nl->next;
3766 if (next) {
3767 nl->next = nl_size + (strlen(nl->name) + 1);
3768 }
3769 if (remaining_data < nl->next) {
3770 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3771 break;
3772 }
3773 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3774 strcpy(cur_data + nl_size, nl->name);
3775 cur_data += nl->next;
3776 remaining_data -= nl->next;
3777 if (!next) {
3778 break;
3779 }
3780 nl = (void*)nl + next;
3781 }
3782 break;
3783 }
3784 case DM_DEV_WAIT:
3785 case DM_TABLE_STATUS:
3786 {
3787 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3788 void *cur_data = argptr;
3789 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3790 int spec_size = thunk_type_size(arg_type, 0);
3791 int i;
3792
3793 for (i = 0; i < host_dm->target_count; i++) {
3794 uint32_t next = spec->next;
3795 int slen = strlen((char*)&spec[1]) + 1;
3796 spec->next = (cur_data - argptr) + spec_size + slen;
3797 if (guest_data_size < spec->next) {
3798 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3799 break;
3800 }
3801 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3802 strcpy(cur_data + spec_size, (char*)&spec[1]);
3803 cur_data = argptr + spec->next;
3804 spec = (void*)host_dm + host_dm->data_start + next;
3805 }
3806 break;
3807 }
3808 case DM_TABLE_DEPS:
3809 {
3810 void *hdata = (void*)host_dm + host_dm->data_start;
3811 int count = *(uint32_t*)hdata;
3812 uint64_t *hdev = hdata + 8;
3813 uint64_t *gdev = argptr + 8;
3814 int i;
3815
3816 *(uint32_t*)argptr = tswap32(count);
3817 for (i = 0; i < count; i++) {
3818 *gdev = tswap64(*hdev);
3819 gdev++;
3820 hdev++;
3821 }
3822 break;
3823 }
3824 case DM_LIST_VERSIONS:
3825 {
3826 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3827 uint32_t remaining_data = guest_data_size;
3828 void *cur_data = argptr;
3829 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3830 int vers_size = thunk_type_size(arg_type, 0);
3831
3832 while (1) {
3833 uint32_t next = vers->next;
3834 if (next) {
3835 vers->next = vers_size + (strlen(vers->name) + 1);
3836 }
3837 if (remaining_data < vers->next) {
3838 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3839 break;
3840 }
3841 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3842 strcpy(cur_data + vers_size, vers->name);
3843 cur_data += vers->next;
3844 remaining_data -= vers->next;
3845 if (!next) {
3846 break;
3847 }
3848 vers = (void*)vers + next;
3849 }
3850 break;
3851 }
3852 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08003853 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003854 ret = -TARGET_EINVAL;
3855 goto out;
3856 }
3857 unlock_user(argptr, guest_data, guest_data_size);
3858
3859 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3860 if (!argptr) {
3861 ret = -TARGET_EFAULT;
3862 goto out;
3863 }
3864 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3865 unlock_user(argptr, arg, target_size);
3866 }
3867out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003868 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003869 return ret;
3870}
3871
Alexander Grafa59b5e32014-08-22 13:15:50 +02003872static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003873 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02003874{
3875 void *argptr;
3876 int target_size;
3877 const argtype *arg_type = ie->arg_type;
3878 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3879 abi_long ret;
3880
3881 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3882 struct blkpg_partition host_part;
3883
3884 /* Read and convert blkpg */
3885 arg_type++;
3886 target_size = thunk_type_size(arg_type, 0);
3887 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3888 if (!argptr) {
3889 ret = -TARGET_EFAULT;
3890 goto out;
3891 }
3892 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3893 unlock_user(argptr, arg, 0);
3894
3895 switch (host_blkpg->op) {
3896 case BLKPG_ADD_PARTITION:
3897 case BLKPG_DEL_PARTITION:
3898 /* payload is struct blkpg_partition */
3899 break;
3900 default:
3901 /* Unknown opcode */
3902 ret = -TARGET_EINVAL;
3903 goto out;
3904 }
3905
3906 /* Read and convert blkpg->data */
3907 arg = (abi_long)(uintptr_t)host_blkpg->data;
3908 target_size = thunk_type_size(part_arg_type, 0);
3909 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3910 if (!argptr) {
3911 ret = -TARGET_EFAULT;
3912 goto out;
3913 }
3914 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3915 unlock_user(argptr, arg, 0);
3916
3917 /* Swizzle the data pointer to our local copy and call! */
3918 host_blkpg->data = &host_part;
3919 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3920
3921out:
3922 return ret;
3923}
3924
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003925static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003926 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003927{
3928 const argtype *arg_type = ie->arg_type;
3929 const StructEntry *se;
3930 const argtype *field_types;
3931 const int *dst_offsets, *src_offsets;
3932 int target_size;
3933 void *argptr;
3934 abi_ulong *target_rt_dev_ptr;
3935 unsigned long *host_rt_dev_ptr;
3936 abi_long ret;
3937 int i;
3938
3939 assert(ie->access == IOC_W);
3940 assert(*arg_type == TYPE_PTR);
3941 arg_type++;
3942 assert(*arg_type == TYPE_STRUCT);
3943 target_size = thunk_type_size(arg_type, 0);
3944 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3945 if (!argptr) {
3946 return -TARGET_EFAULT;
3947 }
3948 arg_type++;
3949 assert(*arg_type == (int)STRUCT_rtentry);
3950 se = struct_entries + *arg_type++;
3951 assert(se->convert[0] == NULL);
3952 /* convert struct here to be able to catch rt_dev string */
3953 field_types = se->field_types;
3954 dst_offsets = se->field_offsets[THUNK_HOST];
3955 src_offsets = se->field_offsets[THUNK_TARGET];
3956 for (i = 0; i < se->nb_fields; i++) {
3957 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3958 assert(*field_types == TYPE_PTRVOID);
3959 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3960 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3961 if (*target_rt_dev_ptr != 0) {
3962 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3963 tswapal(*target_rt_dev_ptr));
3964 if (!*host_rt_dev_ptr) {
3965 unlock_user(argptr, arg, 0);
3966 return -TARGET_EFAULT;
3967 }
3968 } else {
3969 *host_rt_dev_ptr = 0;
3970 }
3971 field_types++;
3972 continue;
3973 }
3974 field_types = thunk_convert(buf_temp + dst_offsets[i],
3975 argptr + src_offsets[i],
3976 field_types, THUNK_HOST);
3977 }
3978 unlock_user(argptr, arg, 0);
3979
3980 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3981 if (*host_rt_dev_ptr != 0) {
3982 unlock_user((void *)*host_rt_dev_ptr,
3983 *target_rt_dev_ptr, 0);
3984 }
3985 return ret;
3986}
3987
Paul Burtonca56f5b2014-06-22 11:25:47 +01003988static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003989 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01003990{
3991 int sig = target_to_host_signal(arg);
3992 return get_errno(ioctl(fd, ie->host_cmd, sig));
3993}
3994
blueswir19f106a72008-10-05 10:52:52 +00003995static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003996#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003997 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3998#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3999 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004000#include "ioctls.h"
4001 { 0, 0, },
4002};
4003
pbrook53a59602006-03-25 19:31:22 +00004004/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004005/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004006static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004007{
4008 const IOCTLEntry *ie;
4009 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004010 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004011 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004012 int target_size;
4013 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004014
4015 ie = ioctl_entries;
4016 for(;;) {
4017 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004018 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004019 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004020 }
4021 if (ie->target_cmd == cmd)
4022 break;
4023 ie++;
4024 }
4025 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004026#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004027 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004028#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004029 if (ie->do_ioctl) {
4030 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4031 }
4032
bellard31e31b82003-02-18 22:55:36 +00004033 switch(arg_type[0]) {
4034 case TYPE_NULL:
4035 /* no argument */
4036 ret = get_errno(ioctl(fd, ie->host_cmd));
4037 break;
4038 case TYPE_PTRVOID:
4039 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004040 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4041 break;
4042 case TYPE_PTR:
4043 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004044 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004045 switch(ie->access) {
4046 case IOC_R:
4047 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4048 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004049 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4050 if (!argptr)
4051 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004052 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4053 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004054 }
4055 break;
4056 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004057 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4058 if (!argptr)
4059 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004060 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4061 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004062 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4063 break;
4064 default:
4065 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004066 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4067 if (!argptr)
4068 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004069 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4070 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004071 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4072 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004073 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4074 if (!argptr)
4075 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004076 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4077 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004078 }
4079 break;
4080 }
4081 break;
4082 default:
j_mayer32407102007-09-26 23:01:49 +00004083 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4084 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004085 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004086 break;
4087 }
4088 return ret;
4089}
4090
blueswir1b39bc502008-10-05 10:51:10 +00004091static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004092 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4093 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4094 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4095 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4096 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4097 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4098 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4099 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4100 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4101 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4102 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4103 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4104 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4105 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4106 { 0, 0, 0, 0 }
4107};
4108
blueswir1b39bc502008-10-05 10:51:10 +00004109static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004110 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4111 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4112 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4113 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4114 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4115 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4116 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4117 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4118 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4119 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4120 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4121 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4122 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4123 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4124 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4125 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4126 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4127 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4128 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4129 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4130 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4131 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4132 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4133 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4134 { 0, 0, 0, 0 }
4135};
4136
blueswir1b39bc502008-10-05 10:51:10 +00004137static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004138 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4139 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4140 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4141 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4142 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4143 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4144 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4145 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4146 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4147 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4148 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4149 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4150 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4151 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4152 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4153 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4154 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4155 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4156 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4157 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4158 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4159 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4160 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4161 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4162 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4163 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4164 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4165 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4166 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4167 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4168 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4169 { 0, 0, 0, 0 }
4170};
4171
blueswir1b39bc502008-10-05 10:51:10 +00004172static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004173 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4174 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4175 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4176 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4177 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4178 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4179 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4180 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4181 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4182 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4183 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4184 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4185 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4186 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4187 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4188 { 0, 0, 0, 0 }
4189};
4190
4191static void target_to_host_termios (void *dst, const void *src)
4192{
4193 struct host_termios *host = dst;
4194 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004195
ths5fafdf22007-09-16 21:08:06 +00004196 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004197 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004198 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004199 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004200 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004201 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004202 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004203 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4204 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004205
Arnaud Patard44607122009-04-21 17:39:08 +03004206 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004207 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4208 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004209 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004210 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004211 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004212 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004213 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004214 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004215 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004216 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4217 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004218 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4219 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4220 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4221 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4222 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004223 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004224}
ths3b46e622007-09-17 08:09:54 +00004225
bellard31e31b82003-02-18 22:55:36 +00004226static void host_to_target_termios (void *dst, const void *src)
4227{
4228 struct target_termios *target = dst;
4229 const struct host_termios *host = src;
4230
ths5fafdf22007-09-16 21:08:06 +00004231 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004232 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004233 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004234 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004235 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004236 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004237 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004238 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4239 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004240
Arnaud Patard44607122009-04-21 17:39:08 +03004241 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004242 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4243 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4244 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4245 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4246 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4247 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4248 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4249 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4250 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4251 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4252 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4253 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4254 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4255 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4256 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4257 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4258 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4259}
4260
blueswir18e853dc2008-10-05 10:49:32 +00004261static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004262 .convert = { host_to_target_termios, target_to_host_termios },
4263 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4264 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4265};
4266
bellard5286db72003-06-05 00:57:30 +00004267static bitmask_transtbl mmap_flags_tbl[] = {
4268 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4269 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4270 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4271 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4272 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4273 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4274 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4275 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004276 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4277 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004278 { 0, 0, 0, 0 }
4279};
4280
bellard2ab83ea2003-06-15 19:56:46 +00004281#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004282
4283/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004284static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004285
bellard03acab62007-11-11 14:57:14 +00004286static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004287{
4288 int size;
pbrook53a59602006-03-25 19:31:22 +00004289 void *p;
bellard6dbad632003-03-16 18:05:05 +00004290
4291 if (!ldt_table)
4292 return 0;
4293 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4294 if (size > bytecount)
4295 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004296 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4297 if (!p)
bellard03acab62007-11-11 14:57:14 +00004298 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004299 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004300 memcpy(p, ldt_table, size);
4301 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004302 return size;
4303}
4304
4305/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004306static abi_long write_ldt(CPUX86State *env,
4307 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004308{
4309 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004310 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004311 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004312 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004313 uint32_t *lp, entry_1, entry_2;
4314
4315 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004316 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004317 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004318 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004319 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004320 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004321 ldt_info.limit = tswap32(target_ldt_info->limit);
4322 ldt_info.flags = tswap32(target_ldt_info->flags);
4323 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004324
bellard6dbad632003-03-16 18:05:05 +00004325 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004326 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004327 seg_32bit = ldt_info.flags & 1;
4328 contents = (ldt_info.flags >> 1) & 3;
4329 read_exec_only = (ldt_info.flags >> 3) & 1;
4330 limit_in_pages = (ldt_info.flags >> 4) & 1;
4331 seg_not_present = (ldt_info.flags >> 5) & 1;
4332 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004333#ifdef TARGET_ABI32
4334 lm = 0;
4335#else
4336 lm = (ldt_info.flags >> 7) & 1;
4337#endif
bellard6dbad632003-03-16 18:05:05 +00004338 if (contents == 3) {
4339 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004340 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004341 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004342 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004343 }
4344 /* allocate the LDT */
4345 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004346 env->ldt.base = target_mmap(0,
4347 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4348 PROT_READ|PROT_WRITE,
4349 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4350 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004351 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004352 memset(g2h(env->ldt.base), 0,
4353 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004354 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004355 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004356 }
4357
4358 /* NOTE: same code as Linux kernel */
4359 /* Allow LDTs to be cleared by the user. */
4360 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4361 if (oldmode ||
4362 (contents == 0 &&
4363 read_exec_only == 1 &&
4364 seg_32bit == 0 &&
4365 limit_in_pages == 0 &&
4366 seg_not_present == 1 &&
4367 useable == 0 )) {
4368 entry_1 = 0;
4369 entry_2 = 0;
4370 goto install;
4371 }
4372 }
ths3b46e622007-09-17 08:09:54 +00004373
bellard6dbad632003-03-16 18:05:05 +00004374 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4375 (ldt_info.limit & 0x0ffff);
4376 entry_2 = (ldt_info.base_addr & 0xff000000) |
4377 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4378 (ldt_info.limit & 0xf0000) |
4379 ((read_exec_only ^ 1) << 9) |
4380 (contents << 10) |
4381 ((seg_not_present ^ 1) << 15) |
4382 (seg_32bit << 22) |
4383 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004384 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004385 0x7000;
4386 if (!oldmode)
4387 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004388
bellard6dbad632003-03-16 18:05:05 +00004389 /* Install the new entry ... */
4390install:
4391 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4392 lp[0] = tswap32(entry_1);
4393 lp[1] = tswap32(entry_2);
4394 return 0;
4395}
4396
4397/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004398static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4399 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004400{
bellard03acab62007-11-11 14:57:14 +00004401 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004402
bellard6dbad632003-03-16 18:05:05 +00004403 switch (func) {
4404 case 0:
4405 ret = read_ldt(ptr, bytecount);
4406 break;
4407 case 1:
4408 ret = write_ldt(env, ptr, bytecount, 1);
4409 break;
4410 case 0x11:
4411 ret = write_ldt(env, ptr, bytecount, 0);
4412 break;
bellard03acab62007-11-11 14:57:14 +00004413 default:
4414 ret = -TARGET_ENOSYS;
4415 break;
bellard6dbad632003-03-16 18:05:05 +00004416 }
4417 return ret;
4418}
bellard1b6b0292003-03-22 17:31:38 +00004419
blueswir14583f582008-08-24 10:35:55 +00004420#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004421abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004422{
4423 uint64_t *gdt_table = g2h(env->gdt.base);
4424 struct target_modify_ldt_ldt_s ldt_info;
4425 struct target_modify_ldt_ldt_s *target_ldt_info;
4426 int seg_32bit, contents, read_exec_only, limit_in_pages;
4427 int seg_not_present, useable, lm;
4428 uint32_t *lp, entry_1, entry_2;
4429 int i;
4430
4431 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4432 if (!target_ldt_info)
4433 return -TARGET_EFAULT;
4434 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004435 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004436 ldt_info.limit = tswap32(target_ldt_info->limit);
4437 ldt_info.flags = tswap32(target_ldt_info->flags);
4438 if (ldt_info.entry_number == -1) {
4439 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4440 if (gdt_table[i] == 0) {
4441 ldt_info.entry_number = i;
4442 target_ldt_info->entry_number = tswap32(i);
4443 break;
4444 }
4445 }
4446 }
4447 unlock_user_struct(target_ldt_info, ptr, 1);
4448
4449 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4450 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4451 return -TARGET_EINVAL;
4452 seg_32bit = ldt_info.flags & 1;
4453 contents = (ldt_info.flags >> 1) & 3;
4454 read_exec_only = (ldt_info.flags >> 3) & 1;
4455 limit_in_pages = (ldt_info.flags >> 4) & 1;
4456 seg_not_present = (ldt_info.flags >> 5) & 1;
4457 useable = (ldt_info.flags >> 6) & 1;
4458#ifdef TARGET_ABI32
4459 lm = 0;
4460#else
4461 lm = (ldt_info.flags >> 7) & 1;
4462#endif
4463
4464 if (contents == 3) {
4465 if (seg_not_present == 0)
4466 return -TARGET_EINVAL;
4467 }
4468
4469 /* NOTE: same code as Linux kernel */
4470 /* Allow LDTs to be cleared by the user. */
4471 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4472 if ((contents == 0 &&
4473 read_exec_only == 1 &&
4474 seg_32bit == 0 &&
4475 limit_in_pages == 0 &&
4476 seg_not_present == 1 &&
4477 useable == 0 )) {
4478 entry_1 = 0;
4479 entry_2 = 0;
4480 goto install;
4481 }
4482 }
4483
4484 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4485 (ldt_info.limit & 0x0ffff);
4486 entry_2 = (ldt_info.base_addr & 0xff000000) |
4487 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4488 (ldt_info.limit & 0xf0000) |
4489 ((read_exec_only ^ 1) << 9) |
4490 (contents << 10) |
4491 ((seg_not_present ^ 1) << 15) |
4492 (seg_32bit << 22) |
4493 (limit_in_pages << 23) |
4494 (useable << 20) |
4495 (lm << 21) |
4496 0x7000;
4497
4498 /* Install the new entry ... */
4499install:
4500 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4501 lp[0] = tswap32(entry_1);
4502 lp[1] = tswap32(entry_2);
4503 return 0;
4504}
4505
blueswir18fcd3692008-08-17 20:26:25 +00004506static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004507{
4508 struct target_modify_ldt_ldt_s *target_ldt_info;
4509 uint64_t *gdt_table = g2h(env->gdt.base);
4510 uint32_t base_addr, limit, flags;
4511 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4512 int seg_not_present, useable, lm;
4513 uint32_t *lp, entry_1, entry_2;
4514
4515 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4516 if (!target_ldt_info)
4517 return -TARGET_EFAULT;
4518 idx = tswap32(target_ldt_info->entry_number);
4519 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4520 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4521 unlock_user_struct(target_ldt_info, ptr, 1);
4522 return -TARGET_EINVAL;
4523 }
4524 lp = (uint32_t *)(gdt_table + idx);
4525 entry_1 = tswap32(lp[0]);
4526 entry_2 = tswap32(lp[1]);
4527
4528 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4529 contents = (entry_2 >> 10) & 3;
4530 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4531 seg_32bit = (entry_2 >> 22) & 1;
4532 limit_in_pages = (entry_2 >> 23) & 1;
4533 useable = (entry_2 >> 20) & 1;
4534#ifdef TARGET_ABI32
4535 lm = 0;
4536#else
4537 lm = (entry_2 >> 21) & 1;
4538#endif
4539 flags = (seg_32bit << 0) | (contents << 1) |
4540 (read_exec_only << 3) | (limit_in_pages << 4) |
4541 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4542 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4543 base_addr = (entry_1 >> 16) |
4544 (entry_2 & 0xff000000) |
4545 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004546 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004547 target_ldt_info->limit = tswap32(limit);
4548 target_ldt_info->flags = tswap32(flags);
4549 unlock_user_struct(target_ldt_info, ptr, 1);
4550 return 0;
4551}
blueswir14583f582008-08-24 10:35:55 +00004552#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004553
bellardd2fd1af2007-11-14 18:08:56 +00004554#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004555abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004556{
Juan Quintela1add8692011-06-16 17:37:09 +01004557 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004558 abi_ulong val;
4559 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004560
bellardd2fd1af2007-11-14 18:08:56 +00004561 switch(code) {
4562 case TARGET_ARCH_SET_GS:
4563 case TARGET_ARCH_SET_FS:
4564 if (code == TARGET_ARCH_SET_GS)
4565 idx = R_GS;
4566 else
4567 idx = R_FS;
4568 cpu_x86_load_seg(env, idx, 0);
4569 env->segs[idx].base = addr;
4570 break;
4571 case TARGET_ARCH_GET_GS:
4572 case TARGET_ARCH_GET_FS:
4573 if (code == TARGET_ARCH_GET_GS)
4574 idx = R_GS;
4575 else
4576 idx = R_FS;
4577 val = env->segs[idx].base;
4578 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004579 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004580 break;
4581 default:
4582 ret = -TARGET_EINVAL;
4583 break;
4584 }
Juan Quintela1add8692011-06-16 17:37:09 +01004585 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004586}
4587#endif
4588
bellard2ab83ea2003-06-15 19:56:46 +00004589#endif /* defined(TARGET_I386) */
4590
Riku Voipio05098a92011-03-04 15:27:29 +02004591#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004592
pbrookd865bab2008-06-07 22:12:17 +00004593
4594static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4595typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004596 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004597 pthread_mutex_t mutex;
4598 pthread_cond_t cond;
4599 pthread_t thread;
4600 uint32_t tid;
4601 abi_ulong child_tidptr;
4602 abi_ulong parent_tidptr;
4603 sigset_t sigmask;
4604} new_thread_info;
4605
4606static void *clone_func(void *arg)
4607{
4608 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004609 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004610 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004611 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004612
Emilio G. Cota70903762015-08-23 20:23:41 -04004613 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00004614 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004615 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004616 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004617 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004618 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004619 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004620 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004621 if (info->child_tidptr)
4622 put_user_u32(info->tid, info->child_tidptr);
4623 if (info->parent_tidptr)
4624 put_user_u32(info->tid, info->parent_tidptr);
4625 /* Enable signals. */
4626 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4627 /* Signal to the parent that we're ready. */
4628 pthread_mutex_lock(&info->mutex);
4629 pthread_cond_broadcast(&info->cond);
4630 pthread_mutex_unlock(&info->mutex);
4631 /* Wait until the parent has finshed initializing the tls state. */
4632 pthread_mutex_lock(&clone_lock);
4633 pthread_mutex_unlock(&clone_lock);
4634 cpu_loop(env);
4635 /* never exits */
4636 return NULL;
4637}
bellard1b6b0292003-03-22 17:31:38 +00004638
ths0da46a62007-10-20 20:23:07 +00004639/* do_fork() Must return host values and target errnos (unlike most
4640 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004641static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004642 abi_ulong parent_tidptr, target_ulong newtls,
4643 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004644{
Andreas Färber0429a972013-08-26 18:14:44 +02004645 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004646 int ret;
bellard5cd43932003-03-29 16:54:36 +00004647 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004648 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004649 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004650 unsigned int nptl_flags;
4651 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004652
balrog436d1242008-09-21 02:39:45 +00004653 /* Emulate vfork() with fork() */
4654 if (flags & CLONE_VFORK)
4655 flags &= ~(CLONE_VFORK | CLONE_VM);
4656
bellard1b6b0292003-03-22 17:31:38 +00004657 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004658 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004659 new_thread_info info;
4660 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004661
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02004662 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00004663 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004664 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004665 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004666 /* Init regs that differ from the parent. */
4667 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004668 new_cpu = ENV_GET_CPU(new_env);
4669 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004670 ts->bprm = parent_ts->bprm;
4671 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004672 nptl_flags = flags;
4673 flags &= ~CLONE_NPTL_FLAGS2;
4674
pbrookc2764712009-03-07 15:24:59 +00004675 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4676 ts->child_tidptr = child_tidptr;
4677 }
4678
pbrookd865bab2008-06-07 22:12:17 +00004679 if (nptl_flags & CLONE_SETTLS)
4680 cpu_set_tls (new_env, newtls);
4681
4682 /* Grab a mutex so that thread setup appears atomic. */
4683 pthread_mutex_lock(&clone_lock);
4684
4685 memset(&info, 0, sizeof(info));
4686 pthread_mutex_init(&info.mutex, NULL);
4687 pthread_mutex_lock(&info.mutex);
4688 pthread_cond_init(&info.cond, NULL);
4689 info.env = new_env;
4690 if (nptl_flags & CLONE_CHILD_SETTID)
4691 info.child_tidptr = child_tidptr;
4692 if (nptl_flags & CLONE_PARENT_SETTID)
4693 info.parent_tidptr = parent_tidptr;
4694
4695 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004696 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4697 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004698 /* It is not safe to deliver signals until the child has finished
4699 initializing, so temporarily block all signals. */
4700 sigfillset(&sigmask);
4701 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4702
4703 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004704 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004705
4706 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4707 pthread_attr_destroy(&attr);
4708 if (ret == 0) {
4709 /* Wait for the child to initialize. */
4710 pthread_cond_wait(&info.cond, &info.mutex);
4711 ret = info.tid;
4712 if (flags & CLONE_PARENT_SETTID)
4713 put_user_u32(ret, parent_tidptr);
4714 } else {
4715 ret = -1;
4716 }
4717 pthread_mutex_unlock(&info.mutex);
4718 pthread_cond_destroy(&info.cond);
4719 pthread_mutex_destroy(&info.mutex);
4720 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004721 } else {
4722 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01004723 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
4724 return -TARGET_EINVAL;
4725 }
pbrookd865bab2008-06-07 22:12:17 +00004726 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004727 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004728 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004729 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02004730 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00004731 cpu_clone_regs(env, newsp);
4732 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004733 /* There is a race condition here. The parent process could
4734 theoretically read the TID in the child process before the child
4735 tid is set. This would require using either ptrace
4736 (not implemented) or having *_tidptr to point at a shared memory
4737 mapping. We can't repeat the spinlock hack used above because
4738 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004739 if (flags & CLONE_CHILD_SETTID)
4740 put_user_u32(gettid(), child_tidptr);
4741 if (flags & CLONE_PARENT_SETTID)
4742 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004743 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004744 if (flags & CLONE_SETTLS)
4745 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004746 if (flags & CLONE_CHILD_CLEARTID)
4747 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004748 } else {
4749 fork_end(0);
4750 }
bellard1b6b0292003-03-22 17:31:38 +00004751 }
4752 return ret;
4753}
4754
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004755/* warning : doesn't handle linux specific flags... */
4756static int target_to_host_fcntl_cmd(int cmd)
4757{
4758 switch(cmd) {
4759 case TARGET_F_DUPFD:
4760 case TARGET_F_GETFD:
4761 case TARGET_F_SETFD:
4762 case TARGET_F_GETFL:
4763 case TARGET_F_SETFL:
4764 return cmd;
4765 case TARGET_F_GETLK:
4766 return F_GETLK;
4767 case TARGET_F_SETLK:
4768 return F_SETLK;
4769 case TARGET_F_SETLKW:
4770 return F_SETLKW;
4771 case TARGET_F_GETOWN:
4772 return F_GETOWN;
4773 case TARGET_F_SETOWN:
4774 return F_SETOWN;
4775 case TARGET_F_GETSIG:
4776 return F_GETSIG;
4777 case TARGET_F_SETSIG:
4778 return F_SETSIG;
4779#if TARGET_ABI_BITS == 32
4780 case TARGET_F_GETLK64:
4781 return F_GETLK64;
4782 case TARGET_F_SETLK64:
4783 return F_SETLK64;
4784 case TARGET_F_SETLKW64:
4785 return F_SETLKW64;
4786#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004787 case TARGET_F_SETLEASE:
4788 return F_SETLEASE;
4789 case TARGET_F_GETLEASE:
4790 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004791#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004792 case TARGET_F_DUPFD_CLOEXEC:
4793 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004794#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004795 case TARGET_F_NOTIFY:
4796 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004797#ifdef F_GETOWN_EX
4798 case TARGET_F_GETOWN_EX:
4799 return F_GETOWN_EX;
4800#endif
4801#ifdef F_SETOWN_EX
4802 case TARGET_F_SETOWN_EX:
4803 return F_SETOWN_EX;
4804#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004805 default:
4806 return -TARGET_EINVAL;
4807 }
4808 return -TARGET_EINVAL;
4809}
4810
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004811#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4812static const bitmask_transtbl flock_tbl[] = {
4813 TRANSTBL_CONVERT(F_RDLCK),
4814 TRANSTBL_CONVERT(F_WRLCK),
4815 TRANSTBL_CONVERT(F_UNLCK),
4816 TRANSTBL_CONVERT(F_EXLCK),
4817 TRANSTBL_CONVERT(F_SHLCK),
4818 { 0, 0, 0, 0 }
4819};
4820
blueswir1992f48a2007-10-14 16:27:31 +00004821static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004822{
4823 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004824 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004825 struct flock64 fl64;
4826 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004827#ifdef F_GETOWN_EX
4828 struct f_owner_ex fox;
4829 struct target_f_owner_ex *target_fox;
4830#endif
blueswir1992f48a2007-10-14 16:27:31 +00004831 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004832 int host_cmd = target_to_host_fcntl_cmd(cmd);
4833
4834 if (host_cmd == -TARGET_EINVAL)
4835 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004836
bellard7775e9e2003-05-14 22:46:48 +00004837 switch(cmd) {
4838 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004839 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4840 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004841 fl.l_type =
4842 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004843 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004844 fl.l_start = tswapal(target_fl->l_start);
4845 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004846 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004847 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004848 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004849 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004850 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4851 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004852 target_fl->l_type =
4853 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004854 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004855 target_fl->l_start = tswapal(fl.l_start);
4856 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004857 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004858 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004859 }
4860 break;
ths3b46e622007-09-17 08:09:54 +00004861
bellard7775e9e2003-05-14 22:46:48 +00004862 case TARGET_F_SETLK:
4863 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004864 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4865 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004866 fl.l_type =
4867 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004868 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004869 fl.l_start = tswapal(target_fl->l_start);
4870 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004871 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004872 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004873 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004874 break;
ths3b46e622007-09-17 08:09:54 +00004875
bellard7775e9e2003-05-14 22:46:48 +00004876 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004877 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4878 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004879 fl64.l_type =
4880 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004881 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004882 fl64.l_start = tswap64(target_fl64->l_start);
4883 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004884 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004885 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004886 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004887 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004888 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4889 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004890 target_fl64->l_type =
4891 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004892 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004893 target_fl64->l_start = tswap64(fl64.l_start);
4894 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004895 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004896 unlock_user_struct(target_fl64, arg, 1);
4897 }
bellard9ee1fa22007-11-11 15:11:19 +00004898 break;
bellard7775e9e2003-05-14 22:46:48 +00004899 case TARGET_F_SETLK64:
4900 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004901 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4902 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004903 fl64.l_type =
4904 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004905 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004906 fl64.l_start = tswap64(target_fl64->l_start);
4907 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004908 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004909 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004910 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004911 break;
4912
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004913 case TARGET_F_GETFL:
4914 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004915 if (ret >= 0) {
4916 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4917 }
bellardffa65c32004-01-04 23:57:22 +00004918 break;
4919
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004920 case TARGET_F_SETFL:
4921 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4922 break;
4923
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004924#ifdef F_GETOWN_EX
4925 case TARGET_F_GETOWN_EX:
4926 ret = get_errno(fcntl(fd, host_cmd, &fox));
4927 if (ret >= 0) {
4928 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4929 return -TARGET_EFAULT;
4930 target_fox->type = tswap32(fox.type);
4931 target_fox->pid = tswap32(fox.pid);
4932 unlock_user_struct(target_fox, arg, 1);
4933 }
4934 break;
4935#endif
4936
4937#ifdef F_SETOWN_EX
4938 case TARGET_F_SETOWN_EX:
4939 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4940 return -TARGET_EFAULT;
4941 fox.type = tswap32(target_fox->type);
4942 fox.pid = tswap32(target_fox->pid);
4943 unlock_user_struct(target_fox, arg, 0);
4944 ret = get_errno(fcntl(fd, host_cmd, &fox));
4945 break;
4946#endif
4947
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004948 case TARGET_F_SETOWN:
4949 case TARGET_F_GETOWN:
4950 case TARGET_F_SETSIG:
4951 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004952 case TARGET_F_SETLEASE:
4953 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004954 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004955 break;
4956
bellard7775e9e2003-05-14 22:46:48 +00004957 default:
bellard9ee1fa22007-11-11 15:11:19 +00004958 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004959 break;
4960 }
4961 return ret;
4962}
4963
bellard67867302003-11-23 17:05:30 +00004964#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004965
bellard67867302003-11-23 17:05:30 +00004966static inline int high2lowuid(int uid)
4967{
4968 if (uid > 65535)
4969 return 65534;
4970 else
4971 return uid;
4972}
4973
4974static inline int high2lowgid(int gid)
4975{
4976 if (gid > 65535)
4977 return 65534;
4978 else
4979 return gid;
4980}
4981
4982static inline int low2highuid(int uid)
4983{
4984 if ((int16_t)uid == -1)
4985 return -1;
4986 else
4987 return uid;
4988}
4989
4990static inline int low2highgid(int gid)
4991{
4992 if ((int16_t)gid == -1)
4993 return -1;
4994 else
4995 return gid;
4996}
Riku Voipio0c866a72011-04-18 15:23:06 +03004997static inline int tswapid(int id)
4998{
4999 return tswap16(id);
5000}
Peter Maydell76ca3102014-03-02 19:36:41 +00005001
5002#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5003
Riku Voipio0c866a72011-04-18 15:23:06 +03005004#else /* !USE_UID16 */
5005static inline int high2lowuid(int uid)
5006{
5007 return uid;
5008}
5009static inline int high2lowgid(int gid)
5010{
5011 return gid;
5012}
5013static inline int low2highuid(int uid)
5014{
5015 return uid;
5016}
5017static inline int low2highgid(int gid)
5018{
5019 return gid;
5020}
5021static inline int tswapid(int id)
5022{
5023 return tswap32(id);
5024}
Peter Maydell76ca3102014-03-02 19:36:41 +00005025
5026#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5027
bellard67867302003-11-23 17:05:30 +00005028#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005029
bellard31e31b82003-02-18 22:55:36 +00005030void syscall_init(void)
5031{
bellard2ab83ea2003-06-15 19:56:46 +00005032 IOCTLEntry *ie;
5033 const argtype *arg_type;
5034 int size;
thsb92c47c2007-11-01 00:07:38 +00005035 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005036
Alexander Graf8be656b2015-05-06 23:47:32 +02005037 thunk_init(STRUCT_MAX);
5038
Blue Swirl001faf32009-05-13 17:53:17 +00005039#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005040#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005041#include "syscall_types.h"
5042#undef STRUCT
5043#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005044
Peter Maydelldd6e9572012-07-23 08:07:22 +00005045 /* Build target_to_host_errno_table[] table from
5046 * host_to_target_errno_table[]. */
5047 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5048 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5049 }
5050
bellard2ab83ea2003-06-15 19:56:46 +00005051 /* we patch the ioctl size if necessary. We rely on the fact that
5052 no ioctl has all the bits at '1' in the size field */
5053 ie = ioctl_entries;
5054 while (ie->target_cmd != 0) {
5055 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5056 TARGET_IOC_SIZEMASK) {
5057 arg_type = ie->arg_type;
5058 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005059 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005060 ie->target_cmd);
5061 exit(1);
5062 }
5063 arg_type++;
5064 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005065 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005066 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5067 (size << TARGET_IOC_SIZESHIFT);
5068 }
thsb92c47c2007-11-01 00:07:38 +00005069
bellard2ab83ea2003-06-15 19:56:46 +00005070 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005071#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5072 (defined(__x86_64__) && defined(TARGET_X86_64))
5073 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5074 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5075 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005076 }
5077#endif
5078 ie++;
5079 }
bellard31e31b82003-02-18 22:55:36 +00005080}
bellardc573ff62004-01-04 15:51:36 +00005081
blueswir1992f48a2007-10-14 16:27:31 +00005082#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005083static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5084{
thsaf325d32008-06-10 15:29:15 +00005085#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005086 return ((uint64_t)word0 << 32) | word1;
5087#else
5088 return ((uint64_t)word1 << 32) | word0;
5089#endif
5090}
blueswir1992f48a2007-10-14 16:27:31 +00005091#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005092static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5093{
5094 return word0;
5095}
blueswir1992f48a2007-10-14 16:27:31 +00005096#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005097
5098#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005099static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5100 abi_long arg2,
5101 abi_long arg3,
5102 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005103{
Riku Voipio48e515d2011-07-12 15:40:51 +03005104 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005105 arg2 = arg3;
5106 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005107 }
pbrookce4defa2006-02-09 16:49:55 +00005108 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5109}
5110#endif
5111
5112#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005113static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5114 abi_long arg2,
5115 abi_long arg3,
5116 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005117{
Riku Voipio48e515d2011-07-12 15:40:51 +03005118 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005119 arg2 = arg3;
5120 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005121 }
pbrookce4defa2006-02-09 16:49:55 +00005122 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5123}
5124#endif
5125
bellard579a97f2007-11-11 14:26:47 +00005126static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5127 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005128{
5129 struct target_timespec *target_ts;
5130
bellard579a97f2007-11-11 14:26:47 +00005131 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5132 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005133 host_ts->tv_sec = tswapal(target_ts->tv_sec);
5134 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005135 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005136 return 0;
pbrook53a59602006-03-25 19:31:22 +00005137}
5138
bellard579a97f2007-11-11 14:26:47 +00005139static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5140 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005141{
5142 struct target_timespec *target_ts;
5143
bellard579a97f2007-11-11 14:26:47 +00005144 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5145 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005146 target_ts->tv_sec = tswapal(host_ts->tv_sec);
5147 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005148 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005149 return 0;
pbrook53a59602006-03-25 19:31:22 +00005150}
5151
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005152static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5153 abi_ulong target_addr)
5154{
5155 struct target_itimerspec *target_itspec;
5156
5157 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5158 return -TARGET_EFAULT;
5159 }
5160
5161 host_itspec->it_interval.tv_sec =
5162 tswapal(target_itspec->it_interval.tv_sec);
5163 host_itspec->it_interval.tv_nsec =
5164 tswapal(target_itspec->it_interval.tv_nsec);
5165 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5166 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5167
5168 unlock_user_struct(target_itspec, target_addr, 1);
5169 return 0;
5170}
5171
5172static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5173 struct itimerspec *host_its)
5174{
5175 struct target_itimerspec *target_itspec;
5176
5177 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5178 return -TARGET_EFAULT;
5179 }
5180
5181 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5182 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5183
5184 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5185 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5186
5187 unlock_user_struct(target_itspec, target_addr, 0);
5188 return 0;
5189}
5190
Peter Maydellc0659762014-08-09 15:42:32 +01005191static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5192 abi_ulong target_addr)
5193{
5194 struct target_sigevent *target_sevp;
5195
5196 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5197 return -TARGET_EFAULT;
5198 }
5199
5200 /* This union is awkward on 64 bit systems because it has a 32 bit
5201 * integer and a pointer in it; we follow the conversion approach
5202 * used for handling sigval types in signal.c so the guest should get
5203 * the correct value back even if we did a 64 bit byteswap and it's
5204 * using the 32 bit integer.
5205 */
5206 host_sevp->sigev_value.sival_ptr =
5207 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5208 host_sevp->sigev_signo =
5209 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5210 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5211 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5212
5213 unlock_user_struct(target_sevp, target_addr, 1);
5214 return 0;
5215}
5216
Tom Musta6f6a4032014-08-12 13:53:42 -05005217#if defined(TARGET_NR_mlockall)
5218static inline int target_to_host_mlockall_arg(int arg)
5219{
5220 int result = 0;
5221
5222 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5223 result |= MCL_CURRENT;
5224 }
5225 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5226 result |= MCL_FUTURE;
5227 }
5228 return result;
5229}
5230#endif
5231
aurel329d33b762009-04-08 23:07:05 +00005232#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00005233static inline abi_long host_to_target_stat64(void *cpu_env,
5234 abi_ulong target_addr,
5235 struct stat *host_st)
5236{
Alexander Graf09701192013-09-03 20:12:15 +01005237#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005238 if (((CPUARMState *)cpu_env)->eabi) {
5239 struct target_eabi_stat64 *target_st;
5240
5241 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5242 return -TARGET_EFAULT;
5243 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5244 __put_user(host_st->st_dev, &target_st->st_dev);
5245 __put_user(host_st->st_ino, &target_st->st_ino);
5246#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5247 __put_user(host_st->st_ino, &target_st->__st_ino);
5248#endif
5249 __put_user(host_st->st_mode, &target_st->st_mode);
5250 __put_user(host_st->st_nlink, &target_st->st_nlink);
5251 __put_user(host_st->st_uid, &target_st->st_uid);
5252 __put_user(host_st->st_gid, &target_st->st_gid);
5253 __put_user(host_st->st_rdev, &target_st->st_rdev);
5254 __put_user(host_st->st_size, &target_st->st_size);
5255 __put_user(host_st->st_blksize, &target_st->st_blksize);
5256 __put_user(host_st->st_blocks, &target_st->st_blocks);
5257 __put_user(host_st->st_atime, &target_st->target_st_atime);
5258 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5259 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5260 unlock_user_struct(target_st, target_addr, 1);
5261 } else
5262#endif
5263 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005264#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005265 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005266#else
5267 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005268#endif
balrog6a24a772008-09-20 02:23:36 +00005269
5270 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5271 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005272 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005273 __put_user(host_st->st_dev, &target_st->st_dev);
5274 __put_user(host_st->st_ino, &target_st->st_ino);
5275#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5276 __put_user(host_st->st_ino, &target_st->__st_ino);
5277#endif
5278 __put_user(host_st->st_mode, &target_st->st_mode);
5279 __put_user(host_st->st_nlink, &target_st->st_nlink);
5280 __put_user(host_st->st_uid, &target_st->st_uid);
5281 __put_user(host_st->st_gid, &target_st->st_gid);
5282 __put_user(host_st->st_rdev, &target_st->st_rdev);
5283 /* XXX: better use of kernel struct */
5284 __put_user(host_st->st_size, &target_st->st_size);
5285 __put_user(host_st->st_blksize, &target_st->st_blksize);
5286 __put_user(host_st->st_blocks, &target_st->st_blocks);
5287 __put_user(host_st->st_atime, &target_st->target_st_atime);
5288 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5289 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5290 unlock_user_struct(target_st, target_addr, 1);
5291 }
5292
5293 return 0;
5294}
5295#endif
5296
pbrookbd0c5662008-05-29 14:34:11 +00005297/* ??? Using host futex calls even when target atomic operations
5298 are not really atomic probably breaks things. However implementing
5299 futexes locally would make futexes shared between multiple processes
5300 tricky. However they're probably useless because guest atomic
5301 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005302static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5303 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005304{
5305 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005306 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005307
5308 /* ??? We assume FUTEX_* constants are the same on both host
5309 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005310#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005311 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005312#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005313 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005314#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005315 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005316 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005317 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005318 if (timeout) {
5319 pts = &ts;
5320 target_to_host_timespec(pts, timeout);
5321 } else {
5322 pts = NULL;
5323 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005324 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005325 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005326 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005327 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005328 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005329 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005330 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005331 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005332 case FUTEX_WAKE_OP:
5333 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5334 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5335 But the prototype takes a `struct timespec *'; insert casts
5336 to satisfy the compiler. We do not need to tswap TIMEOUT
5337 since it's not compared to guest memory. */
5338 pts = (struct timespec *)(uintptr_t) timeout;
5339 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5340 g2h(uaddr2),
5341 (base_op == FUTEX_CMP_REQUEUE
5342 ? tswap32(val3)
5343 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005344 default:
5345 return -TARGET_ENOSYS;
5346 }
5347}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005348#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5349static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
5350 abi_long handle, abi_long mount_id,
5351 abi_long flags)
5352{
5353 struct file_handle *target_fh;
5354 struct file_handle *fh;
5355 int mid = 0;
5356 abi_long ret;
5357 char *name;
5358 unsigned int size, total_size;
5359
5360 if (get_user_s32(size, handle)) {
5361 return -TARGET_EFAULT;
5362 }
5363
5364 name = lock_user_string(pathname);
5365 if (!name) {
5366 return -TARGET_EFAULT;
5367 }
5368
5369 total_size = sizeof(struct file_handle) + size;
5370 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
5371 if (!target_fh) {
5372 unlock_user(name, pathname, 0);
5373 return -TARGET_EFAULT;
5374 }
5375
5376 fh = g_malloc0(total_size);
5377 fh->handle_bytes = size;
5378
5379 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
5380 unlock_user(name, pathname, 0);
5381
5382 /* man name_to_handle_at(2):
5383 * Other than the use of the handle_bytes field, the caller should treat
5384 * the file_handle structure as an opaque data type
5385 */
5386
5387 memcpy(target_fh, fh, total_size);
5388 target_fh->handle_bytes = tswap32(fh->handle_bytes);
5389 target_fh->handle_type = tswap32(fh->handle_type);
5390 g_free(fh);
5391 unlock_user(target_fh, handle, total_size);
5392
5393 if (put_user_s32(mid, mount_id)) {
5394 return -TARGET_EFAULT;
5395 }
5396
5397 return ret;
5398
5399}
5400#endif
5401
5402#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5403static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
5404 abi_long flags)
5405{
5406 struct file_handle *target_fh;
5407 struct file_handle *fh;
5408 unsigned int size, total_size;
5409 abi_long ret;
5410
5411 if (get_user_s32(size, handle)) {
5412 return -TARGET_EFAULT;
5413 }
5414
5415 total_size = sizeof(struct file_handle) + size;
5416 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
5417 if (!target_fh) {
5418 return -TARGET_EFAULT;
5419 }
5420
Thomas Huthe9d49d52015-10-09 17:56:38 +02005421 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005422 fh->handle_bytes = size;
5423 fh->handle_type = tswap32(target_fh->handle_type);
5424
5425 ret = get_errno(open_by_handle_at(mount_fd, fh,
5426 target_to_host_bitmask(flags, fcntl_flags_tbl)));
5427
5428 g_free(fh);
5429
5430 unlock_user(target_fh, handle, total_size);
5431
5432 return ret;
5433}
5434#endif
pbrookbd0c5662008-05-29 14:34:11 +00005435
Laurent Viviere36800c2015-10-02 14:48:09 +02005436#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
5437
5438/* signalfd siginfo conversion */
5439
5440static void
5441host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
5442 const struct signalfd_siginfo *info)
5443{
5444 int sig = host_to_target_signal(info->ssi_signo);
5445
5446 /* linux/signalfd.h defines a ssi_addr_lsb
5447 * not defined in sys/signalfd.h but used by some kernels
5448 */
5449
5450#ifdef BUS_MCEERR_AO
5451 if (tinfo->ssi_signo == SIGBUS &&
5452 (tinfo->ssi_code == BUS_MCEERR_AR ||
5453 tinfo->ssi_code == BUS_MCEERR_AO)) {
5454 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
5455 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
5456 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
5457 }
5458#endif
5459
5460 tinfo->ssi_signo = tswap32(sig);
5461 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
5462 tinfo->ssi_code = tswap32(info->ssi_code);
5463 tinfo->ssi_pid = tswap32(info->ssi_pid);
5464 tinfo->ssi_uid = tswap32(info->ssi_uid);
5465 tinfo->ssi_fd = tswap32(info->ssi_fd);
5466 tinfo->ssi_tid = tswap32(info->ssi_tid);
5467 tinfo->ssi_band = tswap32(info->ssi_band);
5468 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
5469 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
5470 tinfo->ssi_status = tswap32(info->ssi_status);
5471 tinfo->ssi_int = tswap32(info->ssi_int);
5472 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
5473 tinfo->ssi_utime = tswap64(info->ssi_utime);
5474 tinfo->ssi_stime = tswap64(info->ssi_stime);
5475 tinfo->ssi_addr = tswap64(info->ssi_addr);
5476}
5477
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005478static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02005479{
5480 int i;
5481
5482 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
5483 host_to_target_signalfd_siginfo(buf + i, buf + i);
5484 }
5485
5486 return len;
5487}
5488
5489static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005490 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02005491};
5492
5493static abi_long do_signalfd4(int fd, abi_long mask, int flags)
5494{
5495 int host_flags;
5496 target_sigset_t *target_mask;
5497 sigset_t host_mask;
5498 abi_long ret;
5499
5500 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
5501 return -TARGET_EINVAL;
5502 }
5503 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
5504 return -TARGET_EFAULT;
5505 }
5506
5507 target_to_host_sigset(&host_mask, target_mask);
5508
5509 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
5510
5511 ret = get_errno(signalfd(fd, &host_mask, host_flags));
5512 if (ret >= 0) {
5513 fd_trans_register(ret, &target_signalfd_trans);
5514 }
5515
5516 unlock_user_struct(target_mask, mask, 0);
5517
5518 return ret;
5519}
5520#endif
5521
pbrook1d9d8b52009-04-16 15:17:02 +00005522/* Map host to target signal numbers for the wait family of syscalls.
5523 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005524int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005525{
5526 if (WIFSIGNALED(status)) {
5527 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5528 }
5529 if (WIFSTOPPED(status)) {
5530 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5531 | (status & 0xff);
5532 }
5533 return status;
5534}
5535
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005536static int open_self_cmdline(void *cpu_env, int fd)
5537{
5538 int fd_orig = -1;
5539 bool word_skipped = false;
5540
5541 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5542 if (fd_orig < 0) {
5543 return fd_orig;
5544 }
5545
5546 while (true) {
5547 ssize_t nb_read;
5548 char buf[128];
5549 char *cp_buf = buf;
5550
5551 nb_read = read(fd_orig, buf, sizeof(buf));
5552 if (nb_read < 0) {
5553 fd_orig = close(fd_orig);
5554 return -1;
5555 } else if (nb_read == 0) {
5556 break;
5557 }
5558
5559 if (!word_skipped) {
5560 /* Skip the first string, which is the path to qemu-*-static
5561 instead of the actual command. */
5562 cp_buf = memchr(buf, 0, sizeof(buf));
5563 if (cp_buf) {
5564 /* Null byte found, skip one string */
5565 cp_buf++;
5566 nb_read -= cp_buf - buf;
5567 word_skipped = true;
5568 }
5569 }
5570
5571 if (word_skipped) {
5572 if (write(fd, cp_buf, nb_read) != nb_read) {
zhanghailiang680dfde2014-08-22 16:23:51 +08005573 close(fd_orig);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005574 return -1;
5575 }
5576 }
5577 }
5578
5579 return close(fd_orig);
5580}
5581
Alexander Graf36c08d42011-11-02 20:23:24 +01005582static int open_self_maps(void *cpu_env, int fd)
5583{
Andreas Färber0429a972013-08-26 18:14:44 +02005584 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5585 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005586 FILE *fp;
5587 char *line = NULL;
5588 size_t len = 0;
5589 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005590
Alexander Graf1a49ef22012-05-01 16:30:28 +01005591 fp = fopen("/proc/self/maps", "r");
5592 if (fp == NULL) {
5593 return -EACCES;
5594 }
5595
5596 while ((read = getline(&line, &len, fp)) != -1) {
5597 int fields, dev_maj, dev_min, inode;
5598 uint64_t min, max, offset;
5599 char flag_r, flag_w, flag_x, flag_p;
5600 char path[512] = "";
5601 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5602 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5603 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5604
5605 if ((fields < 10) || (fields > 11)) {
5606 continue;
5607 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005608 if (h2g_valid(min)) {
5609 int flags = page_get_flags(h2g(min));
5610 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5611 if (page_check_range(h2g(min), max - min, flags) == -1) {
5612 continue;
5613 }
5614 if (h2g(min) == ts->info->stack_limit) {
5615 pstrcpy(path, sizeof(path), " [stack]");
5616 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005617 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005618 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005619 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005620 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005621 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005622 }
5623 }
5624
5625 free(line);
5626 fclose(fp);
5627
Alexander Graf36c08d42011-11-02 20:23:24 +01005628 return 0;
5629}
5630
Alexander Graf480b8e72011-11-02 20:23:25 +01005631static int open_self_stat(void *cpu_env, int fd)
5632{
Andreas Färber0429a972013-08-26 18:14:44 +02005633 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5634 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005635 abi_ulong start_stack = ts->info->start_stack;
5636 int i;
5637
5638 for (i = 0; i < 44; i++) {
5639 char buf[128];
5640 int len;
5641 uint64_t val = 0;
5642
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005643 if (i == 0) {
5644 /* pid */
5645 val = getpid();
5646 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5647 } else if (i == 1) {
5648 /* app name */
5649 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5650 } else if (i == 27) {
5651 /* stack bottom */
5652 val = start_stack;
5653 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5654 } else {
5655 /* for the rest, there is MasterCard */
5656 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005657 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005658
Alexander Graf480b8e72011-11-02 20:23:25 +01005659 len = strlen(buf);
5660 if (write(fd, buf, len) != len) {
5661 return -1;
5662 }
5663 }
5664
5665 return 0;
5666}
5667
Alexander Graf257450e2011-11-02 20:23:26 +01005668static int open_self_auxv(void *cpu_env, int fd)
5669{
Andreas Färber0429a972013-08-26 18:14:44 +02005670 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5671 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005672 abi_ulong auxv = ts->info->saved_auxv;
5673 abi_ulong len = ts->info->auxv_len;
5674 char *ptr;
5675
5676 /*
5677 * Auxiliary vector is stored in target process stack.
5678 * read in whole auxv vector and copy it to file
5679 */
5680 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5681 if (ptr != NULL) {
5682 while (len > 0) {
5683 ssize_t r;
5684 r = write(fd, ptr, len);
5685 if (r <= 0) {
5686 break;
5687 }
5688 len -= r;
5689 ptr += r;
5690 }
5691 lseek(fd, 0, SEEK_SET);
5692 unlock_user(ptr, auxv, len);
5693 }
5694
5695 return 0;
5696}
5697
Andreas Schwab463d8e72013-07-02 14:04:12 +01005698static int is_proc_myself(const char *filename, const char *entry)
5699{
5700 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5701 filename += strlen("/proc/");
5702 if (!strncmp(filename, "self/", strlen("self/"))) {
5703 filename += strlen("self/");
5704 } else if (*filename >= '1' && *filename <= '9') {
5705 char myself[80];
5706 snprintf(myself, sizeof(myself), "%d/", getpid());
5707 if (!strncmp(filename, myself, strlen(myself))) {
5708 filename += strlen(myself);
5709 } else {
5710 return 0;
5711 }
5712 } else {
5713 return 0;
5714 }
5715 if (!strcmp(filename, entry)) {
5716 return 1;
5717 }
5718 }
5719 return 0;
5720}
5721
Laurent Vivierde6b9932013-08-30 01:46:40 +02005722#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5723static int is_proc(const char *filename, const char *entry)
5724{
5725 return strcmp(filename, entry) == 0;
5726}
5727
5728static int open_net_route(void *cpu_env, int fd)
5729{
5730 FILE *fp;
5731 char *line = NULL;
5732 size_t len = 0;
5733 ssize_t read;
5734
5735 fp = fopen("/proc/net/route", "r");
5736 if (fp == NULL) {
5737 return -EACCES;
5738 }
5739
5740 /* read header */
5741
5742 read = getline(&line, &len, fp);
5743 dprintf(fd, "%s", line);
5744
5745 /* read routes */
5746
5747 while ((read = getline(&line, &len, fp)) != -1) {
5748 char iface[16];
5749 uint32_t dest, gw, mask;
5750 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5751 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5752 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5753 &mask, &mtu, &window, &irtt);
5754 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5755 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5756 metric, tswap32(mask), mtu, window, irtt);
5757 }
5758
5759 free(line);
5760 fclose(fp);
5761
5762 return 0;
5763}
5764#endif
5765
Riku Voipio0b2effd2014-08-06 10:36:37 +03005766static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005767{
5768 struct fake_open {
5769 const char *filename;
5770 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005771 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005772 };
5773 const struct fake_open *fake_open;
5774 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005775 { "maps", open_self_maps, is_proc_myself },
5776 { "stat", open_self_stat, is_proc_myself },
5777 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005778 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005779#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5780 { "/proc/net/route", open_net_route, is_proc },
5781#endif
5782 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005783 };
5784
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005785 if (is_proc_myself(pathname, "exe")) {
5786 int execfd = qemu_getauxval(AT_EXECFD);
Riku Voipio0b2effd2014-08-06 10:36:37 +03005787 return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005788 }
5789
Alexander Graf3be14d02011-11-02 20:23:23 +01005790 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005791 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005792 break;
5793 }
5794 }
5795
5796 if (fake_open->filename) {
5797 const char *tmpdir;
5798 char filename[PATH_MAX];
5799 int fd, r;
5800
5801 /* create temporary file to map stat to */
5802 tmpdir = getenv("TMPDIR");
5803 if (!tmpdir)
5804 tmpdir = "/tmp";
5805 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5806 fd = mkstemp(filename);
5807 if (fd < 0) {
5808 return fd;
5809 }
5810 unlink(filename);
5811
5812 if ((r = fake_open->fill(cpu_env, fd))) {
5813 close(fd);
5814 return r;
5815 }
5816 lseek(fd, 0, SEEK_SET);
5817
5818 return fd;
5819 }
5820
Riku Voipio0b2effd2014-08-06 10:36:37 +03005821 return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
Alexander Graf3be14d02011-11-02 20:23:23 +01005822}
5823
Alexander Grafaecc8862014-11-10 21:33:03 +01005824#define TIMER_MAGIC 0x0caf0000
5825#define TIMER_MAGIC_MASK 0xffff0000
5826
5827/* Convert QEMU provided timer ID back to internal 16bit index format */
5828static target_timer_t get_timer_id(abi_long arg)
5829{
5830 target_timer_t timerid = arg;
5831
5832 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
5833 return -TARGET_EINVAL;
5834 }
5835
5836 timerid &= 0xffff;
5837
5838 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
5839 return -TARGET_EINVAL;
5840 }
5841
5842 return timerid;
5843}
5844
ths0da46a62007-10-20 20:23:07 +00005845/* do_syscall() should always have a single exit point at the end so
5846 that actions, such as logging of syscall results, can be performed.
5847 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005848abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5849 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005850 abi_long arg5, abi_long arg6, abi_long arg7,
5851 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005852{
Andreas Färber182735e2013-05-29 22:29:20 +02005853 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005854 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005855 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005856 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005857 void *p;
ths3b46e622007-09-17 08:09:54 +00005858
bellard72f03902003-02-18 23:33:18 +00005859#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005860 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005861#endif
thsb92c47c2007-11-01 00:07:38 +00005862 if(do_strace)
5863 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5864
bellard31e31b82003-02-18 22:55:36 +00005865 switch(num) {
5866 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005867 /* In old applications this may be used to implement _exit(2).
5868 However in threaded applictions it is used for thread termination,
5869 and _exit_group is used for application termination.
5870 Do thread termination if we have more then one thread. */
5871 /* FIXME: This probably breaks if a signal arrives. We should probably
5872 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005873 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005874 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005875
Andreas Färber9b056fc2013-06-24 23:53:10 +02005876 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005877 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005878 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005879 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005880 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005881 if (ts->child_tidptr) {
5882 put_user_u32(0, ts->child_tidptr);
5883 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5884 NULL, NULL, 0);
5885 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005886 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005887 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005888 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04005889 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005890 pthread_exit(NULL);
5891 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005892#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005893 _mcleanup();
5894#endif
bellarde9009672005-04-26 20:42:36 +00005895 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005896 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005897 ret = 0; /* avoid warning */
5898 break;
5899 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005900 if (arg3 == 0)
5901 ret = 0;
5902 else {
5903 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5904 goto efault;
5905 ret = get_errno(read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005906 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005907 fd_trans_host_to_target_data(arg1)) {
5908 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02005909 }
aurel3238d840e2009-01-30 19:48:17 +00005910 unlock_user(p, arg2, ret);
5911 }
bellard31e31b82003-02-18 22:55:36 +00005912 break;
5913 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005914 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5915 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005916 ret = get_errno(write(arg1, p, arg3));
5917 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005918 break;
Chen Gang704eff62015-08-21 05:37:33 +08005919#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00005920 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005921 if (!(p = lock_user_string(arg1)))
5922 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005923 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
5924 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5925 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005926 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00005927 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005928 break;
Chen Gang704eff62015-08-21 05:37:33 +08005929#endif
ths82424832007-09-24 09:21:55 +00005930 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005931 if (!(p = lock_user_string(arg2)))
5932 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005933 ret = get_errno(do_openat(cpu_env, arg1, p,
5934 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5935 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02005936 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00005937 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005938 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005939#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5940 case TARGET_NR_name_to_handle_at:
5941 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
5942 break;
5943#endif
5944#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5945 case TARGET_NR_open_by_handle_at:
5946 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02005947 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005948 break;
5949#endif
bellard31e31b82003-02-18 22:55:36 +00005950 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02005951 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00005952 ret = get_errno(close(arg1));
5953 break;
5954 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005955 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005956 break;
Chen Gang704eff62015-08-21 05:37:33 +08005957#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00005958 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005959 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005960 break;
Chen Gang704eff62015-08-21 05:37:33 +08005961#endif
thse5febef2007-04-01 18:31:35 +00005962#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005963 case TARGET_NR_waitpid:
5964 {
pbrook53a59602006-03-25 19:31:22 +00005965 int status;
5966 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005967 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005968 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005969 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005970 }
5971 break;
thse5febef2007-04-01 18:31:35 +00005972#endif
pbrookf0cbb612008-05-30 18:20:05 +00005973#ifdef TARGET_NR_waitid
5974 case TARGET_NR_waitid:
5975 {
5976 siginfo_t info;
5977 info.si_pid = 0;
5978 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5979 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005980 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005981 goto efault;
5982 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005983 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005984 }
5985 }
5986 break;
5987#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005988#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005989 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005990 if (!(p = lock_user_string(arg1)))
5991 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005992 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02005993 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00005994 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005995 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005996#endif
Chen Gang704eff62015-08-21 05:37:33 +08005997#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00005998 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005999 {
6000 void * p2;
6001 p = lock_user_string(arg1);
6002 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006003 if (!p || !p2)
6004 ret = -TARGET_EFAULT;
6005 else
6006 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006007 unlock_user(p2, arg2, 0);
6008 unlock_user(p, arg1, 0);
6009 }
bellard31e31b82003-02-18 22:55:36 +00006010 break;
Chen Gang704eff62015-08-21 05:37:33 +08006011#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006012#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006013 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006014 {
6015 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006016 if (!arg2 || !arg4)
6017 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006018 p = lock_user_string(arg2);
6019 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006020 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006021 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006022 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006023 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006024 unlock_user(p, arg2, 0);
6025 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006026 }
6027 break;
6028#endif
Chen Gang704eff62015-08-21 05:37:33 +08006029#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006030 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006031 if (!(p = lock_user_string(arg1)))
6032 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006033 ret = get_errno(unlink(p));
6034 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006035 break;
Chen Gang704eff62015-08-21 05:37:33 +08006036#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006037#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006038 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006039 if (!(p = lock_user_string(arg2)))
6040 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006041 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006042 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006043 break;
balrogb7d35e62007-12-12 00:40:24 +00006044#endif
bellard31e31b82003-02-18 22:55:36 +00006045 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006046 {
6047 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006048 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006049 abi_ulong gp;
6050 abi_ulong guest_argp;
6051 abi_ulong guest_envp;
6052 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006053 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006054 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006055
bellardf7341ff2003-03-30 21:00:25 +00006056 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006057 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006058 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006059 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006060 goto efault;
ths03aa1972007-12-02 06:28:08 +00006061 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006062 break;
bellard7854b052003-03-29 17:22:23 +00006063 argc++;
bellard2f619692007-11-16 10:46:05 +00006064 }
bellardf7341ff2003-03-30 21:00:25 +00006065 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006066 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006067 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006068 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006069 goto efault;
ths03aa1972007-12-02 06:28:08 +00006070 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006071 break;
bellard7854b052003-03-29 17:22:23 +00006072 envc++;
bellard2f619692007-11-16 10:46:05 +00006073 }
bellard7854b052003-03-29 17:22:23 +00006074
bellardf7341ff2003-03-30 21:00:25 +00006075 argp = alloca((argc + 1) * sizeof(void *));
6076 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006077
pbrookda94d262008-05-30 18:24:00 +00006078 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006079 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006080 if (get_user_ual(addr, gp))
6081 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006082 if (!addr)
6083 break;
bellard2f619692007-11-16 10:46:05 +00006084 if (!(*q = lock_user_string(addr)))
6085 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006086 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006087 }
bellardf7341ff2003-03-30 21:00:25 +00006088 *q = NULL;
6089
pbrookda94d262008-05-30 18:24:00 +00006090 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006091 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006092 if (get_user_ual(addr, gp))
6093 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006094 if (!addr)
6095 break;
bellard2f619692007-11-16 10:46:05 +00006096 if (!(*q = lock_user_string(addr)))
6097 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006098 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006099 }
bellardf7341ff2003-03-30 21:00:25 +00006100 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006101
bellard2f619692007-11-16 10:46:05 +00006102 if (!(p = lock_user_string(arg1)))
6103 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006104 ret = get_errno(execve(p, argp, envp));
6105 unlock_user(p, arg1, 0);
6106
bellard2f619692007-11-16 10:46:05 +00006107 goto execve_end;
6108
6109 execve_efault:
6110 ret = -TARGET_EFAULT;
6111
6112 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006113 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006114 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006115 if (get_user_ual(addr, gp)
6116 || !addr)
6117 break;
pbrook53a59602006-03-25 19:31:22 +00006118 unlock_user(*q, addr, 0);
6119 }
6120 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006121 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006122 if (get_user_ual(addr, gp)
6123 || !addr)
6124 break;
pbrook53a59602006-03-25 19:31:22 +00006125 unlock_user(*q, addr, 0);
6126 }
bellard7854b052003-03-29 17:22:23 +00006127 }
bellard31e31b82003-02-18 22:55:36 +00006128 break;
6129 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006130 if (!(p = lock_user_string(arg1)))
6131 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006132 ret = get_errno(chdir(p));
6133 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006134 break;
bellarda315a142005-01-30 22:59:18 +00006135#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006136 case TARGET_NR_time:
6137 {
pbrook53a59602006-03-25 19:31:22 +00006138 time_t host_time;
6139 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006140 if (!is_error(ret)
6141 && arg1
6142 && put_user_sal(host_time, arg1))
6143 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006144 }
6145 break;
bellarda315a142005-01-30 22:59:18 +00006146#endif
Chen Gang704eff62015-08-21 05:37:33 +08006147#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006148 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006149 if (!(p = lock_user_string(arg1)))
6150 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006151 ret = get_errno(mknod(p, arg2, arg3));
6152 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006153 break;
Chen Gang704eff62015-08-21 05:37:33 +08006154#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006155#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006156 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006157 if (!(p = lock_user_string(arg2)))
6158 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006159 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00006160 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00006161 break;
6162#endif
Chen Gang704eff62015-08-21 05:37:33 +08006163#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00006164 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00006165 if (!(p = lock_user_string(arg1)))
6166 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006167 ret = get_errno(chmod(p, arg2));
6168 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006169 break;
Chen Gang704eff62015-08-21 05:37:33 +08006170#endif
bellardebc05482003-09-30 21:08:41 +00006171#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00006172 case TARGET_NR_break:
6173 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006174#endif
6175#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00006176 case TARGET_NR_oldstat:
6177 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006178#endif
bellard31e31b82003-02-18 22:55:36 +00006179 case TARGET_NR_lseek:
6180 ret = get_errno(lseek(arg1, arg2, arg3));
6181 break;
Richard Henderson92317332010-05-03 10:07:53 -07006182#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
6183 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00006184 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07006185 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00006186 ret = get_errno(getpid());
6187 break;
Richard Henderson92317332010-05-03 10:07:53 -07006188#endif
6189#ifdef TARGET_NR_getpid
6190 case TARGET_NR_getpid:
6191 ret = get_errno(getpid());
6192 break;
6193#endif
bellard31e31b82003-02-18 22:55:36 +00006194 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01006195 {
6196 /* need to look at the data field */
6197 void *p2, *p3;
6198
6199 if (arg1) {
6200 p = lock_user_string(arg1);
6201 if (!p) {
6202 goto efault;
6203 }
6204 } else {
6205 p = NULL;
6206 }
6207
6208 p2 = lock_user_string(arg2);
6209 if (!p2) {
6210 if (arg1) {
6211 unlock_user(p, arg1, 0);
6212 }
6213 goto efault;
6214 }
6215
6216 if (arg3) {
6217 p3 = lock_user_string(arg3);
6218 if (!p3) {
6219 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006220 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01006221 }
6222 unlock_user(p2, arg2, 0);
6223 goto efault;
6224 }
6225 } else {
6226 p3 = NULL;
6227 }
6228
6229 /* FIXME - arg5 should be locked, but it isn't clear how to
6230 * do that since it's not guaranteed to be a NULL-terminated
6231 * string.
6232 */
6233 if (!arg5) {
6234 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
6235 } else {
6236 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
6237 }
6238 ret = get_errno(ret);
6239
6240 if (arg1) {
6241 unlock_user(p, arg1, 0);
6242 }
6243 unlock_user(p2, arg2, 0);
6244 if (arg3) {
6245 unlock_user(p3, arg3, 0);
6246 }
6247 }
6248 break;
thse5febef2007-04-01 18:31:35 +00006249#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00006250 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00006251 if (!(p = lock_user_string(arg1)))
6252 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006253 ret = get_errno(umount(p));
6254 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006255 break;
thse5febef2007-04-01 18:31:35 +00006256#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006257#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006258 case TARGET_NR_stime:
6259 {
pbrook53a59602006-03-25 19:31:22 +00006260 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00006261 if (get_user_sal(host_time, arg1))
6262 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006263 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00006264 }
6265 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006266#endif
bellard31e31b82003-02-18 22:55:36 +00006267 case TARGET_NR_ptrace:
6268 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00006269#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006270 case TARGET_NR_alarm:
6271 ret = alarm(arg1);
6272 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006273#endif
bellardebc05482003-09-30 21:08:41 +00006274#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00006275 case TARGET_NR_oldfstat:
6276 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006277#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006278#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006279 case TARGET_NR_pause:
6280 ret = get_errno(pause());
6281 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006282#endif
thse5febef2007-04-01 18:31:35 +00006283#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00006284 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00006285 {
pbrook53a59602006-03-25 19:31:22 +00006286 struct utimbuf tbuf, *host_tbuf;
6287 struct target_utimbuf *target_tbuf;
6288 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006289 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
6290 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006291 tbuf.actime = tswapal(target_tbuf->actime);
6292 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00006293 unlock_user_struct(target_tbuf, arg2, 0);
6294 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00006295 } else {
pbrook53a59602006-03-25 19:31:22 +00006296 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00006297 }
bellard579a97f2007-11-11 14:26:47 +00006298 if (!(p = lock_user_string(arg1)))
6299 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006300 ret = get_errno(utime(p, host_tbuf));
6301 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00006302 }
6303 break;
thse5febef2007-04-01 18:31:35 +00006304#endif
Chen Gang704eff62015-08-21 05:37:33 +08006305#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00006306 case TARGET_NR_utimes:
6307 {
bellard978a66f2004-12-06 22:58:05 +00006308 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00006309 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00006310 if (copy_from_user_timeval(&tv[0], arg2)
6311 || copy_from_user_timeval(&tv[1],
6312 arg2 + sizeof(struct target_timeval)))
6313 goto efault;
bellard978a66f2004-12-06 22:58:05 +00006314 tvp = tv;
6315 } else {
6316 tvp = NULL;
6317 }
bellard579a97f2007-11-11 14:26:47 +00006318 if (!(p = lock_user_string(arg1)))
6319 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006320 ret = get_errno(utimes(p, tvp));
6321 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00006322 }
6323 break;
Chen Gang704eff62015-08-21 05:37:33 +08006324#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006325#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00006326 case TARGET_NR_futimesat:
6327 {
6328 struct timeval *tvp, tv[2];
6329 if (arg3) {
6330 if (copy_from_user_timeval(&tv[0], arg3)
6331 || copy_from_user_timeval(&tv[1],
6332 arg3 + sizeof(struct target_timeval)))
6333 goto efault;
6334 tvp = tv;
6335 } else {
6336 tvp = NULL;
6337 }
6338 if (!(p = lock_user_string(arg2)))
6339 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006340 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00006341 unlock_user(p, arg2, 0);
6342 }
6343 break;
6344#endif
bellardebc05482003-09-30 21:08:41 +00006345#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00006346 case TARGET_NR_stty:
6347 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006348#endif
6349#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00006350 case TARGET_NR_gtty:
6351 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006352#endif
Chen Gang704eff62015-08-21 05:37:33 +08006353#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00006354 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00006355 if (!(p = lock_user_string(arg1)))
6356 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02006357 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00006358 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006359 break;
Chen Gang704eff62015-08-21 05:37:33 +08006360#endif
ths92a34c12007-09-24 09:27:49 +00006361#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
6362 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00006363 if (!(p = lock_user_string(arg2)))
6364 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006365 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006366 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00006367 break;
6368#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006369#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006370 case TARGET_NR_nice:
6371 ret = get_errno(nice(arg1));
6372 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006373#endif
bellardebc05482003-09-30 21:08:41 +00006374#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00006375 case TARGET_NR_ftime:
6376 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006377#endif
bellard31e31b82003-02-18 22:55:36 +00006378 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00006379 sync();
6380 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00006381 break;
6382 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00006383 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00006384 break;
Chen Gang704eff62015-08-21 05:37:33 +08006385#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00006386 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00006387 {
6388 void *p2;
6389 p = lock_user_string(arg1);
6390 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006391 if (!p || !p2)
6392 ret = -TARGET_EFAULT;
6393 else
6394 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006395 unlock_user(p2, arg2, 0);
6396 unlock_user(p, arg1, 0);
6397 }
bellard31e31b82003-02-18 22:55:36 +00006398 break;
Chen Gang704eff62015-08-21 05:37:33 +08006399#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006400#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006401 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006402 {
bellard579a97f2007-11-11 14:26:47 +00006403 void *p2;
ths722183f2007-09-24 09:24:37 +00006404 p = lock_user_string(arg2);
6405 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006406 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006407 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006408 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006409 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006410 unlock_user(p2, arg4, 0);
6411 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006412 }
6413 break;
6414#endif
Chen Gang704eff62015-08-21 05:37:33 +08006415#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00006416 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006417 if (!(p = lock_user_string(arg1)))
6418 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006419 ret = get_errno(mkdir(p, arg2));
6420 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006421 break;
Chen Gang704eff62015-08-21 05:37:33 +08006422#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006423#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006424 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006425 if (!(p = lock_user_string(arg2)))
6426 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006427 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006428 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006429 break;
6430#endif
Chen Gang704eff62015-08-21 05:37:33 +08006431#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00006432 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006433 if (!(p = lock_user_string(arg1)))
6434 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006435 ret = get_errno(rmdir(p));
6436 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006437 break;
Chen Gang704eff62015-08-21 05:37:33 +08006438#endif
bellard31e31b82003-02-18 22:55:36 +00006439 case TARGET_NR_dup:
6440 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02006441 if (ret >= 0) {
6442 fd_trans_dup(arg1, ret);
6443 }
bellard31e31b82003-02-18 22:55:36 +00006444 break;
Chen Gang704eff62015-08-21 05:37:33 +08006445#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00006446 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006447 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006448 break;
Chen Gang704eff62015-08-21 05:37:33 +08006449#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03006450#ifdef TARGET_NR_pipe2
6451 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006452 ret = do_pipe(cpu_env, arg1,
6453 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006454 break;
6455#endif
bellard31e31b82003-02-18 22:55:36 +00006456 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006457 {
pbrook53a59602006-03-25 19:31:22 +00006458 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006459 struct tms tms;
6460 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006461 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006462 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6463 if (!tmsp)
6464 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006465 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6466 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6467 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6468 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006469 }
bellardc596ed12003-07-13 17:32:31 +00006470 if (!is_error(ret))
6471 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006472 }
6473 break;
bellardebc05482003-09-30 21:08:41 +00006474#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006475 case TARGET_NR_prof:
6476 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006477#endif
thse5febef2007-04-01 18:31:35 +00006478#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006479 case TARGET_NR_signal:
6480 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006481#endif
bellard31e31b82003-02-18 22:55:36 +00006482 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006483 if (arg1 == 0) {
6484 ret = get_errno(acct(NULL));
6485 } else {
6486 if (!(p = lock_user_string(arg1)))
6487 goto efault;
6488 ret = get_errno(acct(path(p)));
6489 unlock_user(p, arg1, 0);
6490 }
pbrook24836682006-04-16 14:14:53 +00006491 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006492#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006493 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006494 if (!(p = lock_user_string(arg1)))
6495 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006496 ret = get_errno(umount2(p, arg2));
6497 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006498 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006499#endif
bellardebc05482003-09-30 21:08:41 +00006500#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006501 case TARGET_NR_lock:
6502 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006503#endif
bellard31e31b82003-02-18 22:55:36 +00006504 case TARGET_NR_ioctl:
6505 ret = do_ioctl(arg1, arg2, arg3);
6506 break;
6507 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006508 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006509 break;
bellardebc05482003-09-30 21:08:41 +00006510#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006511 case TARGET_NR_mpx:
6512 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006513#endif
bellard31e31b82003-02-18 22:55:36 +00006514 case TARGET_NR_setpgid:
6515 ret = get_errno(setpgid(arg1, arg2));
6516 break;
bellardebc05482003-09-30 21:08:41 +00006517#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006518 case TARGET_NR_ulimit:
6519 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006520#endif
6521#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006522 case TARGET_NR_oldolduname:
6523 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006524#endif
bellard31e31b82003-02-18 22:55:36 +00006525 case TARGET_NR_umask:
6526 ret = get_errno(umask(arg1));
6527 break;
6528 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006529 if (!(p = lock_user_string(arg1)))
6530 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006531 ret = get_errno(chroot(p));
6532 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006533 break;
Chen Gang704eff62015-08-21 05:37:33 +08006534#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00006535 case TARGET_NR_ustat:
6536 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08006537#endif
6538#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00006539 case TARGET_NR_dup2:
6540 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006541 if (ret >= 0) {
6542 fd_trans_dup(arg1, arg2);
6543 }
bellard31e31b82003-02-18 22:55:36 +00006544 break;
Chen Gang704eff62015-08-21 05:37:33 +08006545#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03006546#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6547 case TARGET_NR_dup3:
6548 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006549 if (ret >= 0) {
6550 fd_trans_dup(arg1, arg2);
6551 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03006552 break;
6553#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006554#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006555 case TARGET_NR_getppid:
6556 ret = get_errno(getppid());
6557 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006558#endif
Chen Gang704eff62015-08-21 05:37:33 +08006559#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00006560 case TARGET_NR_getpgrp:
6561 ret = get_errno(getpgrp());
6562 break;
Chen Gang704eff62015-08-21 05:37:33 +08006563#endif
bellard31e31b82003-02-18 22:55:36 +00006564 case TARGET_NR_setsid:
6565 ret = get_errno(setsid());
6566 break;
thse5febef2007-04-01 18:31:35 +00006567#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006568 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006569 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006570#if defined(TARGET_ALPHA)
6571 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006572 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006573 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006574 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6575 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006576 act._sa_handler = old_act->_sa_handler;
6577 target_siginitset(&act.sa_mask, old_act->sa_mask);
6578 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006579 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006580 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006581 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006582 }
6583 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006584 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006585 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6586 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006587 old_act->_sa_handler = oact._sa_handler;
6588 old_act->sa_mask = oact.sa_mask.sig[0];
6589 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006590 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006591 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006592#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006593 struct target_sigaction act, oact, *pact, *old_act;
6594
6595 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006596 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6597 goto efault;
bellard106ec872006-06-27 21:08:10 +00006598 act._sa_handler = old_act->_sa_handler;
6599 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6600 act.sa_flags = old_act->sa_flags;
6601 unlock_user_struct(old_act, arg2, 0);
6602 pact = &act;
6603 } else {
6604 pact = NULL;
6605 }
6606
6607 ret = get_errno(do_sigaction(arg1, pact, &oact));
6608
6609 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006610 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6611 goto efault;
bellard106ec872006-06-27 21:08:10 +00006612 old_act->_sa_handler = oact._sa_handler;
6613 old_act->sa_flags = oact.sa_flags;
6614 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6615 old_act->sa_mask.sig[1] = 0;
6616 old_act->sa_mask.sig[2] = 0;
6617 old_act->sa_mask.sig[3] = 0;
6618 unlock_user_struct(old_act, arg3, 1);
6619 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006620#else
6621 struct target_old_sigaction *old_act;
6622 struct target_sigaction act, oact, *pact;
6623 if (arg2) {
6624 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6625 goto efault;
6626 act._sa_handler = old_act->_sa_handler;
6627 target_siginitset(&act.sa_mask, old_act->sa_mask);
6628 act.sa_flags = old_act->sa_flags;
6629 act.sa_restorer = old_act->sa_restorer;
6630 unlock_user_struct(old_act, arg2, 0);
6631 pact = &act;
6632 } else {
6633 pact = NULL;
6634 }
6635 ret = get_errno(do_sigaction(arg1, pact, &oact));
6636 if (!is_error(ret) && arg3) {
6637 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6638 goto efault;
6639 old_act->_sa_handler = oact._sa_handler;
6640 old_act->sa_mask = oact.sa_mask.sig[0];
6641 old_act->sa_flags = oact.sa_flags;
6642 old_act->sa_restorer = oact.sa_restorer;
6643 unlock_user_struct(old_act, arg3, 1);
6644 }
ths388bb212007-05-13 13:58:00 +00006645#endif
bellard31e31b82003-02-18 22:55:36 +00006646 }
6647 break;
thse5febef2007-04-01 18:31:35 +00006648#endif
bellard66fb9762003-03-23 01:06:05 +00006649 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006650 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006651#if defined(TARGET_ALPHA)
6652 struct target_sigaction act, oact, *pact = 0;
6653 struct target_rt_sigaction *rt_act;
6654 /* ??? arg4 == sizeof(sigset_t). */
6655 if (arg2) {
6656 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6657 goto efault;
6658 act._sa_handler = rt_act->_sa_handler;
6659 act.sa_mask = rt_act->sa_mask;
6660 act.sa_flags = rt_act->sa_flags;
6661 act.sa_restorer = arg5;
6662 unlock_user_struct(rt_act, arg2, 0);
6663 pact = &act;
6664 }
6665 ret = get_errno(do_sigaction(arg1, pact, &oact));
6666 if (!is_error(ret) && arg3) {
6667 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6668 goto efault;
6669 rt_act->_sa_handler = oact._sa_handler;
6670 rt_act->sa_mask = oact.sa_mask;
6671 rt_act->sa_flags = oact.sa_flags;
6672 unlock_user_struct(rt_act, arg3, 1);
6673 }
6674#else
pbrook53a59602006-03-25 19:31:22 +00006675 struct target_sigaction *act;
6676 struct target_sigaction *oact;
6677
bellard579a97f2007-11-11 14:26:47 +00006678 if (arg2) {
6679 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6680 goto efault;
6681 } else
pbrook53a59602006-03-25 19:31:22 +00006682 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006683 if (arg3) {
6684 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6685 ret = -TARGET_EFAULT;
6686 goto rt_sigaction_fail;
6687 }
6688 } else
pbrook53a59602006-03-25 19:31:22 +00006689 oact = NULL;
6690 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006691 rt_sigaction_fail:
6692 if (act)
pbrook53a59602006-03-25 19:31:22 +00006693 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006694 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006695 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006696#endif
pbrook53a59602006-03-25 19:31:22 +00006697 }
bellard66fb9762003-03-23 01:06:05 +00006698 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006699#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006700 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006701 {
6702 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006703 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006704 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006705 host_to_target_old_sigset(&target_set, &cur_set);
6706 ret = target_set;
6707 }
6708 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006709#endif
6710#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006711 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006712 {
6713 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006714 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006715 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006716 target_to_host_old_sigset(&set, &target_set);
6717 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006718 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006719 host_to_target_old_sigset(&target_set, &oset);
6720 ret = target_set;
6721 }
6722 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006723#endif
thse5febef2007-04-01 18:31:35 +00006724#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006725 case TARGET_NR_sigprocmask:
6726 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006727#if defined(TARGET_ALPHA)
6728 sigset_t set, oldset;
6729 abi_ulong mask;
6730 int how;
6731
6732 switch (arg1) {
6733 case TARGET_SIG_BLOCK:
6734 how = SIG_BLOCK;
6735 break;
6736 case TARGET_SIG_UNBLOCK:
6737 how = SIG_UNBLOCK;
6738 break;
6739 case TARGET_SIG_SETMASK:
6740 how = SIG_SETMASK;
6741 break;
6742 default:
6743 ret = -TARGET_EINVAL;
6744 goto fail;
6745 }
6746 mask = arg2;
6747 target_to_host_old_sigset(&set, &mask);
6748
Alex Barcelo1c275922014-03-14 14:36:55 +00006749 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006750 if (!is_error(ret)) {
6751 host_to_target_old_sigset(&mask, &oldset);
6752 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006753 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006754 }
6755#else
bellard66fb9762003-03-23 01:06:05 +00006756 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006757 int how;
ths3b46e622007-09-17 08:09:54 +00006758
pbrook53a59602006-03-25 19:31:22 +00006759 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006760 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006761 case TARGET_SIG_BLOCK:
6762 how = SIG_BLOCK;
6763 break;
6764 case TARGET_SIG_UNBLOCK:
6765 how = SIG_UNBLOCK;
6766 break;
6767 case TARGET_SIG_SETMASK:
6768 how = SIG_SETMASK;
6769 break;
6770 default:
ths0da46a62007-10-20 20:23:07 +00006771 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006772 goto fail;
6773 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006774 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006775 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006776 target_to_host_old_sigset(&set, p);
6777 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006778 set_ptr = &set;
6779 } else {
6780 how = 0;
6781 set_ptr = NULL;
6782 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006783 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006784 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006785 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006786 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006787 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006788 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006789 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006790#endif
bellard66fb9762003-03-23 01:06:05 +00006791 }
6792 break;
thse5febef2007-04-01 18:31:35 +00006793#endif
bellard66fb9762003-03-23 01:06:05 +00006794 case TARGET_NR_rt_sigprocmask:
6795 {
6796 int how = arg1;
6797 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006798
pbrook53a59602006-03-25 19:31:22 +00006799 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006800 switch(how) {
6801 case TARGET_SIG_BLOCK:
6802 how = SIG_BLOCK;
6803 break;
6804 case TARGET_SIG_UNBLOCK:
6805 how = SIG_UNBLOCK;
6806 break;
6807 case TARGET_SIG_SETMASK:
6808 how = SIG_SETMASK;
6809 break;
6810 default:
ths0da46a62007-10-20 20:23:07 +00006811 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006812 goto fail;
6813 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006814 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006815 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006816 target_to_host_sigset(&set, p);
6817 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006818 set_ptr = &set;
6819 } else {
6820 how = 0;
6821 set_ptr = NULL;
6822 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006823 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006824 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006825 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006826 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006827 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006828 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006829 }
6830 }
6831 break;
thse5febef2007-04-01 18:31:35 +00006832#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006833 case TARGET_NR_sigpending:
6834 {
6835 sigset_t set;
6836 ret = get_errno(sigpending(&set));
6837 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006838 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006839 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006840 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006841 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006842 }
6843 }
6844 break;
thse5febef2007-04-01 18:31:35 +00006845#endif
bellard66fb9762003-03-23 01:06:05 +00006846 case TARGET_NR_rt_sigpending:
6847 {
6848 sigset_t set;
6849 ret = get_errno(sigpending(&set));
6850 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006851 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006852 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006853 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006854 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006855 }
6856 }
6857 break;
thse5febef2007-04-01 18:31:35 +00006858#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006859 case TARGET_NR_sigsuspend:
6860 {
6861 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006862#if defined(TARGET_ALPHA)
6863 abi_ulong mask = arg1;
6864 target_to_host_old_sigset(&set, &mask);
6865#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006866 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006867 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006868 target_to_host_old_sigset(&set, p);
6869 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006870#endif
bellard66fb9762003-03-23 01:06:05 +00006871 ret = get_errno(sigsuspend(&set));
6872 }
6873 break;
thse5febef2007-04-01 18:31:35 +00006874#endif
bellard66fb9762003-03-23 01:06:05 +00006875 case TARGET_NR_rt_sigsuspend:
6876 {
6877 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006878 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006879 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006880 target_to_host_sigset(&set, p);
6881 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006882 ret = get_errno(sigsuspend(&set));
6883 }
6884 break;
6885 case TARGET_NR_rt_sigtimedwait:
6886 {
bellard66fb9762003-03-23 01:06:05 +00006887 sigset_t set;
6888 struct timespec uts, *puts;
6889 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006890
Anthony Liguoric227f092009-10-01 16:12:16 -05006891 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006892 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006893 target_to_host_sigset(&set, p);
6894 unlock_user(p, arg1, 0);
6895 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006896 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006897 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006898 } else {
6899 puts = NULL;
6900 }
6901 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006902 if (!is_error(ret)) {
6903 if (arg2) {
6904 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6905 0);
6906 if (!p) {
6907 goto efault;
6908 }
6909 host_to_target_siginfo(p, &uinfo);
6910 unlock_user(p, arg2, sizeof(target_siginfo_t));
6911 }
6912 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006913 }
6914 }
6915 break;
6916 case TARGET_NR_rt_sigqueueinfo:
6917 {
6918 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006919 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006920 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006921 target_to_host_siginfo(&uinfo, p);
6922 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006923 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6924 }
6925 break;
thse5febef2007-04-01 18:31:35 +00006926#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006927 case TARGET_NR_sigreturn:
6928 /* NOTE: ret is eax, so not transcoding must be done */
6929 ret = do_sigreturn(cpu_env);
6930 break;
thse5febef2007-04-01 18:31:35 +00006931#endif
bellard66fb9762003-03-23 01:06:05 +00006932 case TARGET_NR_rt_sigreturn:
6933 /* NOTE: ret is eax, so not transcoding must be done */
6934 ret = do_rt_sigreturn(cpu_env);
6935 break;
bellard31e31b82003-02-18 22:55:36 +00006936 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006937 if (!(p = lock_user_string(arg1)))
6938 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006939 ret = get_errno(sethostname(p, arg2));
6940 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006941 break;
6942 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006943 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006944 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006945 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006946 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006947 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6948 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006949 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6950 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006951 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006952 ret = get_errno(setrlimit(resource, &rlim));
6953 }
6954 break;
bellard31e31b82003-02-18 22:55:36 +00006955 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006956 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006957 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006958 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006959 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006960
bellard9de5e442003-03-23 16:49:39 +00006961 ret = get_errno(getrlimit(resource, &rlim));
6962 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006963 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6964 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006965 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6966 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006967 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006968 }
6969 }
6970 break;
bellard31e31b82003-02-18 22:55:36 +00006971 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006972 {
6973 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006974 ret = get_errno(getrusage(arg1, &rusage));
6975 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006976 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006977 }
6978 }
6979 break;
bellard31e31b82003-02-18 22:55:36 +00006980 case TARGET_NR_gettimeofday:
6981 {
bellard31e31b82003-02-18 22:55:36 +00006982 struct timeval tv;
6983 ret = get_errno(gettimeofday(&tv, NULL));
6984 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006985 if (copy_to_user_timeval(arg1, &tv))
6986 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006987 }
6988 }
6989 break;
6990 case TARGET_NR_settimeofday:
6991 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006992 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006993 struct timezone tz, *ptz = NULL;
6994
Paul Burtonb67d8032014-06-22 11:25:41 +01006995 if (arg1) {
6996 if (copy_from_user_timeval(&tv, arg1)) {
6997 goto efault;
6998 }
6999 ptv = &tv;
7000 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007001
7002 if (arg2) {
7003 if (copy_from_user_timezone(&tz, arg2)) {
7004 goto efault;
7005 }
7006 ptz = &tz;
7007 }
7008
Paul Burtonb67d8032014-06-22 11:25:41 +01007009 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007010 }
7011 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007012#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007013 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007014#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7015 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7016#else
bellardf2674e32003-07-09 12:26:09 +00007017 {
pbrook53a59602006-03-25 19:31:22 +00007018 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007019 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007020 long nsel;
7021
bellard579a97f2007-11-11 14:26:47 +00007022 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7023 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007024 nsel = tswapal(sel->n);
7025 inp = tswapal(sel->inp);
7026 outp = tswapal(sel->outp);
7027 exp = tswapal(sel->exp);
7028 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007029 unlock_user_struct(sel, arg1, 0);
7030 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007031 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007032#endif
bellardf2674e32003-07-09 12:26:09 +00007033 break;
bellard048f6b42005-11-26 18:47:20 +00007034#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007035#ifdef TARGET_NR_pselect6
7036 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007037 {
7038 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7039 fd_set rfds, wfds, efds;
7040 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7041 struct timespec ts, *ts_ptr;
7042
7043 /*
7044 * The 6th arg is actually two args smashed together,
7045 * so we cannot use the C library.
7046 */
7047 sigset_t set;
7048 struct {
7049 sigset_t *set;
7050 size_t size;
7051 } sig, *sig_ptr;
7052
7053 abi_ulong arg_sigset, arg_sigsize, *arg7;
7054 target_sigset_t *target_sigset;
7055
7056 n = arg1;
7057 rfd_addr = arg2;
7058 wfd_addr = arg3;
7059 efd_addr = arg4;
7060 ts_addr = arg5;
7061
7062 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7063 if (ret) {
7064 goto fail;
7065 }
7066 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7067 if (ret) {
7068 goto fail;
7069 }
7070 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7071 if (ret) {
7072 goto fail;
7073 }
7074
7075 /*
7076 * This takes a timespec, and not a timeval, so we cannot
7077 * use the do_select() helper ...
7078 */
7079 if (ts_addr) {
7080 if (target_to_host_timespec(&ts, ts_addr)) {
7081 goto efault;
7082 }
7083 ts_ptr = &ts;
7084 } else {
7085 ts_ptr = NULL;
7086 }
7087
7088 /* Extract the two packed args for the sigset */
7089 if (arg6) {
7090 sig_ptr = &sig;
7091 sig.size = _NSIG / 8;
7092
7093 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7094 if (!arg7) {
7095 goto efault;
7096 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007097 arg_sigset = tswapal(arg7[0]);
7098 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007099 unlock_user(arg7, arg6, 0);
7100
7101 if (arg_sigset) {
7102 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007103 if (arg_sigsize != sizeof(*target_sigset)) {
7104 /* Like the kernel, we enforce correct size sigsets */
7105 ret = -TARGET_EINVAL;
7106 goto fail;
7107 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007108 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7109 sizeof(*target_sigset), 1);
7110 if (!target_sigset) {
7111 goto efault;
7112 }
7113 target_to_host_sigset(&set, target_sigset);
7114 unlock_user(target_sigset, arg_sigset, 0);
7115 } else {
7116 sig.set = NULL;
7117 }
7118 } else {
7119 sig_ptr = NULL;
7120 }
7121
7122 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7123 ts_ptr, sig_ptr));
7124
7125 if (!is_error(ret)) {
7126 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7127 goto efault;
7128 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7129 goto efault;
7130 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7131 goto efault;
7132
7133 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
7134 goto efault;
7135 }
7136 }
7137 break;
Riku Voipio9e423822010-05-07 12:28:05 +00007138#endif
Chen Gang704eff62015-08-21 05:37:33 +08007139#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00007140 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00007141 {
7142 void *p2;
7143 p = lock_user_string(arg1);
7144 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007145 if (!p || !p2)
7146 ret = -TARGET_EFAULT;
7147 else
7148 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007149 unlock_user(p2, arg2, 0);
7150 unlock_user(p, arg1, 0);
7151 }
bellard31e31b82003-02-18 22:55:36 +00007152 break;
Chen Gang704eff62015-08-21 05:37:33 +08007153#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007154#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00007155 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00007156 {
bellard579a97f2007-11-11 14:26:47 +00007157 void *p2;
thsf0b62432007-09-24 09:25:40 +00007158 p = lock_user_string(arg1);
7159 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00007160 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007161 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00007162 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007163 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00007164 unlock_user(p2, arg3, 0);
7165 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00007166 }
7167 break;
7168#endif
bellardebc05482003-09-30 21:08:41 +00007169#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00007170 case TARGET_NR_oldlstat:
7171 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007172#endif
Chen Gang704eff62015-08-21 05:37:33 +08007173#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00007174 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00007175 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01007176 void *p2;
pbrook53a59602006-03-25 19:31:22 +00007177 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00007178 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007179 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00007180 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09007181 } else if (!arg3) {
7182 /* Short circuit this for the magic exe check. */
7183 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01007184 } else if (is_proc_myself((const char *)p, "exe")) {
7185 char real[PATH_MAX], *temp;
7186 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09007187 /* Return value is # of bytes that we wrote to the buffer. */
7188 if (temp == NULL) {
7189 ret = get_errno(-1);
7190 } else {
7191 /* Don't worry about sign mismatch as earlier mapping
7192 * logic would have thrown a bad address error. */
7193 ret = MIN(strlen(real), arg3);
7194 /* We cannot NUL terminate the string. */
7195 memcpy(p2, real, ret);
7196 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01007197 } else {
7198 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00007199 }
pbrook53a59602006-03-25 19:31:22 +00007200 unlock_user(p2, arg2, ret);
7201 unlock_user(p, arg1, 0);
7202 }
bellard31e31b82003-02-18 22:55:36 +00007203 break;
Chen Gang704eff62015-08-21 05:37:33 +08007204#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007205#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00007206 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00007207 {
bellard579a97f2007-11-11 14:26:47 +00007208 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00007209 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007210 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007211 if (!p || !p2) {
7212 ret = -TARGET_EFAULT;
7213 } else if (is_proc_myself((const char *)p, "exe")) {
7214 char real[PATH_MAX], *temp;
7215 temp = realpath(exec_path, real);
7216 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
7217 snprintf((char *)p2, arg4, "%s", real);
7218 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01007219 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01007220 }
bellard579a97f2007-11-11 14:26:47 +00007221 unlock_user(p2, arg3, ret);
7222 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00007223 }
7224 break;
7225#endif
thse5febef2007-04-01 18:31:35 +00007226#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00007227 case TARGET_NR_uselib:
7228 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007229#endif
7230#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00007231 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00007232 if (!(p = lock_user_string(arg1)))
7233 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007234 ret = get_errno(swapon(p, arg2));
7235 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007236 break;
thse5febef2007-04-01 18:31:35 +00007237#endif
bellard31e31b82003-02-18 22:55:36 +00007238 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00007239 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
7240 /* arg4 must be ignored in all other cases */
7241 p = lock_user_string(arg4);
7242 if (!p) {
7243 goto efault;
7244 }
7245 ret = get_errno(reboot(arg1, arg2, arg3, p));
7246 unlock_user(p, arg4, 0);
7247 } else {
7248 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
7249 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02007250 break;
thse5febef2007-04-01 18:31:35 +00007251#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00007252 case TARGET_NR_readdir:
7253 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007254#endif
7255#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00007256 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01007257#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7258 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007259 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
7260 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00007261 {
blueswir1992f48a2007-10-14 16:27:31 +00007262 abi_ulong *v;
7263 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00007264 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
7265 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007266 v1 = tswapal(v[0]);
7267 v2 = tswapal(v[1]);
7268 v3 = tswapal(v[2]);
7269 v4 = tswapal(v[3]);
7270 v5 = tswapal(v[4]);
7271 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00007272 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00007273 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00007274 target_to_host_bitmask(v4, mmap_flags_tbl),
7275 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00007276 }
bellard31e31b82003-02-18 22:55:36 +00007277#else
ths5fafdf22007-09-16 21:08:06 +00007278 ret = get_errno(target_mmap(arg1, arg2, arg3,
7279 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00007280 arg5,
7281 arg6));
bellard31e31b82003-02-18 22:55:36 +00007282#endif
bellard6fb883e2003-07-09 17:12:39 +00007283 break;
thse5febef2007-04-01 18:31:35 +00007284#endif
bellarda315a142005-01-30 22:59:18 +00007285#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00007286 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00007287#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00007288#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00007289#endif
ths5fafdf22007-09-16 21:08:06 +00007290 ret = get_errno(target_mmap(arg1, arg2, arg3,
7291 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00007292 arg5,
bellardc573ff62004-01-04 15:51:36 +00007293 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00007294 break;
bellarda315a142005-01-30 22:59:18 +00007295#endif
bellard31e31b82003-02-18 22:55:36 +00007296 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00007297 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007298 break;
bellard9de5e442003-03-23 16:49:39 +00007299 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01007300 {
Andreas Färber0429a972013-08-26 18:14:44 +02007301 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01007302 /* Special hack to detect libc making the stack executable. */
7303 if ((arg3 & PROT_GROWSDOWN)
7304 && arg1 >= ts->info->stack_limit
7305 && arg1 <= ts->info->start_stack) {
7306 arg3 &= ~PROT_GROWSDOWN;
7307 arg2 = arg2 + arg1 - ts->info->stack_limit;
7308 arg1 = ts->info->stack_limit;
7309 }
7310 }
bellard54936002003-05-13 00:25:15 +00007311 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007312 break;
thse5febef2007-04-01 18:31:35 +00007313#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00007314 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00007315 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00007316 break;
thse5febef2007-04-01 18:31:35 +00007317#endif
pbrook53a59602006-03-25 19:31:22 +00007318 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00007319#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00007320 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00007321 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007322 break;
thse5febef2007-04-01 18:31:35 +00007323#endif
7324#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00007325 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00007326 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007327 break;
thse5febef2007-04-01 18:31:35 +00007328#endif
7329#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00007330 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00007331 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007332 break;
thse5febef2007-04-01 18:31:35 +00007333#endif
7334#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00007335 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05007336 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00007337 break;
thse5febef2007-04-01 18:31:35 +00007338#endif
7339#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00007340 case TARGET_NR_munlockall:
7341 ret = get_errno(munlockall());
7342 break;
thse5febef2007-04-01 18:31:35 +00007343#endif
bellard31e31b82003-02-18 22:55:36 +00007344 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00007345 if (!(p = lock_user_string(arg1)))
7346 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007347 ret = get_errno(truncate(p, arg2));
7348 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007349 break;
7350 case TARGET_NR_ftruncate:
7351 ret = get_errno(ftruncate(arg1, arg2));
7352 break;
7353 case TARGET_NR_fchmod:
7354 ret = get_errno(fchmod(arg1, arg2));
7355 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007356#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00007357 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00007358 if (!(p = lock_user_string(arg2)))
7359 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007360 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007361 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00007362 break;
7363#endif
bellard31e31b82003-02-18 22:55:36 +00007364 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07007365 /* Note that negative values are valid for getpriority, so we must
7366 differentiate based on errno settings. */
7367 errno = 0;
7368 ret = getpriority(arg1, arg2);
7369 if (ret == -1 && errno != 0) {
7370 ret = -host_to_target_errno(errno);
7371 break;
7372 }
7373#ifdef TARGET_ALPHA
7374 /* Return value is the unbiased priority. Signal no error. */
7375 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
7376#else
7377 /* Return value is a biased priority to avoid negative numbers. */
7378 ret = 20 - ret;
7379#endif
bellard31e31b82003-02-18 22:55:36 +00007380 break;
7381 case TARGET_NR_setpriority:
7382 ret = get_errno(setpriority(arg1, arg2, arg3));
7383 break;
bellardebc05482003-09-30 21:08:41 +00007384#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00007385 case TARGET_NR_profil:
7386 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007387#endif
bellard31e31b82003-02-18 22:55:36 +00007388 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00007389 if (!(p = lock_user_string(arg1)))
7390 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007391 ret = get_errno(statfs(path(p), &stfs));
7392 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007393 convert_statfs:
7394 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007395 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007396
bellard579a97f2007-11-11 14:26:47 +00007397 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
7398 goto efault;
7399 __put_user(stfs.f_type, &target_stfs->f_type);
7400 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7401 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7402 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7403 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7404 __put_user(stfs.f_files, &target_stfs->f_files);
7405 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7406 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7407 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7408 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007409 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7410 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00007411 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007412 }
7413 break;
7414 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00007415 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00007416 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00007417#ifdef TARGET_NR_statfs64
7418 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00007419 if (!(p = lock_user_string(arg1)))
7420 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007421 ret = get_errno(statfs(path(p), &stfs));
7422 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00007423 convert_statfs64:
7424 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007425 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007426
bellard579a97f2007-11-11 14:26:47 +00007427 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7428 goto efault;
7429 __put_user(stfs.f_type, &target_stfs->f_type);
7430 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7431 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7432 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7433 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7434 __put_user(stfs.f_files, &target_stfs->f_files);
7435 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7436 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7437 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7438 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007439 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7440 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007441 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007442 }
7443 break;
7444 case TARGET_NR_fstatfs64:
7445 ret = get_errno(fstatfs(arg1, &stfs));
7446 goto convert_statfs64;
7447#endif
bellardebc05482003-09-30 21:08:41 +00007448#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007449 case TARGET_NR_ioperm:
7450 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007451#endif
thse5febef2007-04-01 18:31:35 +00007452#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007453 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007454 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007455 break;
thse5febef2007-04-01 18:31:35 +00007456#endif
bellard3532fa72006-06-24 15:06:03 +00007457#ifdef TARGET_NR_accept
7458 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007459 ret = do_accept4(arg1, arg2, arg3, 0);
7460 break;
7461#endif
7462#ifdef TARGET_NR_accept4
7463 case TARGET_NR_accept4:
7464#ifdef CONFIG_ACCEPT4
7465 ret = do_accept4(arg1, arg2, arg3, arg4);
7466#else
7467 goto unimplemented;
7468#endif
bellard3532fa72006-06-24 15:06:03 +00007469 break;
7470#endif
7471#ifdef TARGET_NR_bind
7472 case TARGET_NR_bind:
7473 ret = do_bind(arg1, arg2, arg3);
7474 break;
7475#endif
7476#ifdef TARGET_NR_connect
7477 case TARGET_NR_connect:
7478 ret = do_connect(arg1, arg2, arg3);
7479 break;
7480#endif
7481#ifdef TARGET_NR_getpeername
7482 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007483 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007484 break;
7485#endif
7486#ifdef TARGET_NR_getsockname
7487 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007488 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007489 break;
7490#endif
7491#ifdef TARGET_NR_getsockopt
7492 case TARGET_NR_getsockopt:
7493 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7494 break;
7495#endif
7496#ifdef TARGET_NR_listen
7497 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007498 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007499 break;
7500#endif
7501#ifdef TARGET_NR_recv
7502 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007503 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007504 break;
7505#endif
7506#ifdef TARGET_NR_recvfrom
7507 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007508 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007509 break;
7510#endif
7511#ifdef TARGET_NR_recvmsg
7512 case TARGET_NR_recvmsg:
7513 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7514 break;
7515#endif
7516#ifdef TARGET_NR_send
7517 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007518 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007519 break;
7520#endif
7521#ifdef TARGET_NR_sendmsg
7522 case TARGET_NR_sendmsg:
7523 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7524 break;
7525#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007526#ifdef TARGET_NR_sendmmsg
7527 case TARGET_NR_sendmmsg:
7528 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7529 break;
7530 case TARGET_NR_recvmmsg:
7531 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7532 break;
7533#endif
bellard3532fa72006-06-24 15:06:03 +00007534#ifdef TARGET_NR_sendto
7535 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007536 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007537 break;
7538#endif
7539#ifdef TARGET_NR_shutdown
7540 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007541 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007542 break;
7543#endif
7544#ifdef TARGET_NR_socket
7545 case TARGET_NR_socket:
7546 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007547 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00007548 break;
7549#endif
7550#ifdef TARGET_NR_socketpair
7551 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007552 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007553 break;
7554#endif
7555#ifdef TARGET_NR_setsockopt
7556 case TARGET_NR_setsockopt:
7557 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7558 break;
7559#endif
ths7494b0f2007-02-11 18:26:53 +00007560
bellard31e31b82003-02-18 22:55:36 +00007561 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007562 if (!(p = lock_user_string(arg2)))
7563 goto efault;
thse5574482007-02-11 20:03:13 +00007564 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7565 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007566 break;
7567
bellard31e31b82003-02-18 22:55:36 +00007568 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007569 {
bellard66fb9762003-03-23 01:06:05 +00007570 struct itimerval value, ovalue, *pvalue;
7571
pbrook53a59602006-03-25 19:31:22 +00007572 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007573 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007574 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7575 || copy_from_user_timeval(&pvalue->it_value,
7576 arg2 + sizeof(struct target_timeval)))
7577 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007578 } else {
7579 pvalue = NULL;
7580 }
7581 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007582 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007583 if (copy_to_user_timeval(arg3,
7584 &ovalue.it_interval)
7585 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7586 &ovalue.it_value))
7587 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007588 }
7589 }
7590 break;
bellard31e31b82003-02-18 22:55:36 +00007591 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007592 {
bellard66fb9762003-03-23 01:06:05 +00007593 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007594
bellard66fb9762003-03-23 01:06:05 +00007595 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007596 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007597 if (copy_to_user_timeval(arg2,
7598 &value.it_interval)
7599 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7600 &value.it_value))
7601 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007602 }
7603 }
7604 break;
Chen Gang704eff62015-08-21 05:37:33 +08007605#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00007606 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007607 if (!(p = lock_user_string(arg1)))
7608 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007609 ret = get_errno(stat(path(p), &st));
7610 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007611 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007612#endif
7613#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00007614 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007615 if (!(p = lock_user_string(arg1)))
7616 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007617 ret = get_errno(lstat(path(p), &st));
7618 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007619 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007620#endif
bellard31e31b82003-02-18 22:55:36 +00007621 case TARGET_NR_fstat:
7622 {
7623 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08007624#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00007625 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08007626#endif
bellard31e31b82003-02-18 22:55:36 +00007627 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007628 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007629
bellard579a97f2007-11-11 14:26:47 +00007630 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7631 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007632 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007633 __put_user(st.st_dev, &target_st->st_dev);
7634 __put_user(st.st_ino, &target_st->st_ino);
7635 __put_user(st.st_mode, &target_st->st_mode);
7636 __put_user(st.st_uid, &target_st->st_uid);
7637 __put_user(st.st_gid, &target_st->st_gid);
7638 __put_user(st.st_nlink, &target_st->st_nlink);
7639 __put_user(st.st_rdev, &target_st->st_rdev);
7640 __put_user(st.st_size, &target_st->st_size);
7641 __put_user(st.st_blksize, &target_st->st_blksize);
7642 __put_user(st.st_blocks, &target_st->st_blocks);
7643 __put_user(st.st_atime, &target_st->target_st_atime);
7644 __put_user(st.st_mtime, &target_st->target_st_mtime);
7645 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007646 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007647 }
7648 }
7649 break;
bellardebc05482003-09-30 21:08:41 +00007650#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007651 case TARGET_NR_olduname:
7652 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007653#endif
7654#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007655 case TARGET_NR_iopl:
7656 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007657#endif
bellard31e31b82003-02-18 22:55:36 +00007658 case TARGET_NR_vhangup:
7659 ret = get_errno(vhangup());
7660 break;
bellardebc05482003-09-30 21:08:41 +00007661#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007662 case TARGET_NR_idle:
7663 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007664#endif
bellard42ad6ae2005-01-03 22:48:11 +00007665#ifdef TARGET_NR_syscall
7666 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007667 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7668 arg6, arg7, arg8, 0);
7669 break;
bellard42ad6ae2005-01-03 22:48:11 +00007670#endif
bellard31e31b82003-02-18 22:55:36 +00007671 case TARGET_NR_wait4:
7672 {
7673 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007674 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007675 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007676 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007677 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007678 if (target_rusage)
7679 rusage_ptr = &rusage;
7680 else
7681 rusage_ptr = NULL;
7682 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7683 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007684 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007685 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007686 if (put_user_s32(status, status_ptr))
7687 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007688 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007689 if (target_rusage) {
7690 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7691 if (rusage_err) {
7692 ret = rusage_err;
7693 }
7694 }
bellard31e31b82003-02-18 22:55:36 +00007695 }
7696 }
7697 break;
thse5febef2007-04-01 18:31:35 +00007698#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007699 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007700 if (!(p = lock_user_string(arg1)))
7701 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007702 ret = get_errno(swapoff(p));
7703 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007704 break;
thse5febef2007-04-01 18:31:35 +00007705#endif
bellard31e31b82003-02-18 22:55:36 +00007706 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007707 {
pbrook53a59602006-03-25 19:31:22 +00007708 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007709 struct sysinfo value;
7710 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007711 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007712 {
bellard579a97f2007-11-11 14:26:47 +00007713 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7714 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007715 __put_user(value.uptime, &target_value->uptime);
7716 __put_user(value.loads[0], &target_value->loads[0]);
7717 __put_user(value.loads[1], &target_value->loads[1]);
7718 __put_user(value.loads[2], &target_value->loads[2]);
7719 __put_user(value.totalram, &target_value->totalram);
7720 __put_user(value.freeram, &target_value->freeram);
7721 __put_user(value.sharedram, &target_value->sharedram);
7722 __put_user(value.bufferram, &target_value->bufferram);
7723 __put_user(value.totalswap, &target_value->totalswap);
7724 __put_user(value.freeswap, &target_value->freeswap);
7725 __put_user(value.procs, &target_value->procs);
7726 __put_user(value.totalhigh, &target_value->totalhigh);
7727 __put_user(value.freehigh, &target_value->freehigh);
7728 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007729 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007730 }
7731 }
7732 break;
thse5febef2007-04-01 18:31:35 +00007733#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007734 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007735 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7736 break;
thse5febef2007-04-01 18:31:35 +00007737#endif
aurel32e5289082009-04-18 16:16:12 +00007738#ifdef TARGET_NR_semget
7739 case TARGET_NR_semget:
7740 ret = get_errno(semget(arg1, arg2, arg3));
7741 break;
7742#endif
7743#ifdef TARGET_NR_semop
7744 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007745 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007746 break;
7747#endif
7748#ifdef TARGET_NR_semctl
7749 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01007750 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00007751 break;
7752#endif
aurel32eeb438c2008-10-13 21:08:55 +00007753#ifdef TARGET_NR_msgctl
7754 case TARGET_NR_msgctl:
7755 ret = do_msgctl(arg1, arg2, arg3);
7756 break;
7757#endif
7758#ifdef TARGET_NR_msgget
7759 case TARGET_NR_msgget:
7760 ret = get_errno(msgget(arg1, arg2));
7761 break;
7762#endif
7763#ifdef TARGET_NR_msgrcv
7764 case TARGET_NR_msgrcv:
7765 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7766 break;
7767#endif
7768#ifdef TARGET_NR_msgsnd
7769 case TARGET_NR_msgsnd:
7770 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7771 break;
7772#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007773#ifdef TARGET_NR_shmget
7774 case TARGET_NR_shmget:
7775 ret = get_errno(shmget(arg1, arg2, arg3));
7776 break;
7777#endif
7778#ifdef TARGET_NR_shmctl
7779 case TARGET_NR_shmctl:
7780 ret = do_shmctl(arg1, arg2, arg3);
7781 break;
7782#endif
7783#ifdef TARGET_NR_shmat
7784 case TARGET_NR_shmat:
7785 ret = do_shmat(arg1, arg2, arg3);
7786 break;
7787#endif
7788#ifdef TARGET_NR_shmdt
7789 case TARGET_NR_shmdt:
7790 ret = do_shmdt(arg1);
7791 break;
7792#endif
bellard31e31b82003-02-18 22:55:36 +00007793 case TARGET_NR_fsync:
7794 ret = get_errno(fsync(arg1));
7795 break;
bellard31e31b82003-02-18 22:55:36 +00007796 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007797 /* Linux manages to have three different orderings for its
7798 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7799 * match the kernel's CONFIG_CLONE_* settings.
7800 * Microblaze is further special in that it uses a sixth
7801 * implicit argument to clone for the TLS pointer.
7802 */
7803#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007804 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007805#elif defined(TARGET_CLONE_BACKWARDS)
7806 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7807#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007808 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007809#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007810 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007811#endif
bellard1b6b0292003-03-22 17:31:38 +00007812 break;
bellardec86b0f2003-04-11 00:15:04 +00007813#ifdef __NR_exit_group
7814 /* new thread calls */
7815 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007816#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007817 _mcleanup();
7818#endif
bellarde9009672005-04-26 20:42:36 +00007819 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007820 ret = get_errno(exit_group(arg1));
7821 break;
7822#endif
bellard31e31b82003-02-18 22:55:36 +00007823 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007824 if (!(p = lock_user_string(arg1)))
7825 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007826 ret = get_errno(setdomainname(p, arg2));
7827 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007828 break;
7829 case TARGET_NR_uname:
7830 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007831 {
7832 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007833
bellard579a97f2007-11-11 14:26:47 +00007834 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7835 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007836 ret = get_errno(sys_uname(buf));
7837 if (!is_error(ret)) {
7838 /* Overrite the native machine name with whatever is being
7839 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01007840 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007841 /* Allow the user to override the reported release. */
7842 if (qemu_uname_release && *qemu_uname_release)
7843 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007844 }
pbrook53a59602006-03-25 19:31:22 +00007845 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007846 }
bellard31e31b82003-02-18 22:55:36 +00007847 break;
bellard6dbad632003-03-16 18:05:05 +00007848#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007849 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007850 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007851 break;
j_mayer84409dd2007-04-06 08:56:50 +00007852#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007853 case TARGET_NR_vm86old:
7854 goto unimplemented;
7855 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007856 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007857 break;
7858#endif
j_mayer84409dd2007-04-06 08:56:50 +00007859#endif
bellard31e31b82003-02-18 22:55:36 +00007860 case TARGET_NR_adjtimex:
7861 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007862#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007863 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007864#endif
bellard31e31b82003-02-18 22:55:36 +00007865 case TARGET_NR_init_module:
7866 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007867#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007868 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007869#endif
bellard31e31b82003-02-18 22:55:36 +00007870 goto unimplemented;
7871 case TARGET_NR_quotactl:
7872 goto unimplemented;
7873 case TARGET_NR_getpgid:
7874 ret = get_errno(getpgid(arg1));
7875 break;
7876 case TARGET_NR_fchdir:
7877 ret = get_errno(fchdir(arg1));
7878 break;
j_mayer84409dd2007-04-06 08:56:50 +00007879#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007880 case TARGET_NR_bdflush:
7881 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007882#endif
thse5febef2007-04-01 18:31:35 +00007883#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007884 case TARGET_NR_sysfs:
7885 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007886#endif
bellard31e31b82003-02-18 22:55:36 +00007887 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007888 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007889 break;
thse5febef2007-04-01 18:31:35 +00007890#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007891 case TARGET_NR_afs_syscall:
7892 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007893#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007894#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007895 case TARGET_NR__llseek:
7896 {
7897 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007898#if !defined(__NR_llseek)
7899 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7900 if (res == -1) {
7901 ret = get_errno(res);
7902 } else {
7903 ret = 0;
7904 }
7905#else
bellard31e31b82003-02-18 22:55:36 +00007906 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007907#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007908 if ((ret == 0) && put_user_s64(res, arg4)) {
7909 goto efault;
7910 }
bellard31e31b82003-02-18 22:55:36 +00007911 }
7912 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007913#endif
Chen Gang704eff62015-08-21 05:37:33 +08007914#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00007915 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007916#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007917#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007918 {
pbrook53a59602006-03-25 19:31:22 +00007919 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007920 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007921 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007922
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05307923 dirp = g_try_malloc(count);
7924 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007925 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007926 goto fail;
7927 }
ths3b46e622007-09-17 08:09:54 +00007928
bellard4add45b2003-06-05 01:52:59 +00007929 ret = get_errno(sys_getdents(arg1, dirp, count));
7930 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007931 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007932 struct target_dirent *tde;
7933 int len = ret;
7934 int reclen, treclen;
7935 int count1, tnamelen;
7936
7937 count1 = 0;
7938 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007939 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7940 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007941 tde = target_dirp;
7942 while (len > 0) {
7943 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007944 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7945 assert(tnamelen >= 0);
7946 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7947 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007948 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007949 tde->d_ino = tswapal(de->d_ino);
7950 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007951 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007952 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007953 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007954 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007955 count1 += treclen;
7956 }
7957 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007958 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007959 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05307960 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00007961 }
7962#else
bellard31e31b82003-02-18 22:55:36 +00007963 {
aurel326556a832008-10-13 21:08:17 +00007964 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007965 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007966
bellard579a97f2007-11-11 14:26:47 +00007967 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7968 goto efault;
bellard72f03902003-02-18 23:33:18 +00007969 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007970 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007971 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007972 int len = ret;
7973 int reclen;
7974 de = dirp;
7975 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007976 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007977 if (reclen > len)
7978 break;
bellard8083a3e2003-03-24 23:12:16 +00007979 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007980 tswapls(&de->d_ino);
7981 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007982 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007983 len -= reclen;
7984 }
7985 }
pbrook53a59602006-03-25 19:31:22 +00007986 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007987 }
bellard4add45b2003-06-05 01:52:59 +00007988#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007989#else
7990 /* Implement getdents in terms of getdents64 */
7991 {
7992 struct linux_dirent64 *dirp;
7993 abi_long count = arg3;
7994
7995 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7996 if (!dirp) {
7997 goto efault;
7998 }
7999 ret = get_errno(sys_getdents64(arg1, dirp, count));
8000 if (!is_error(ret)) {
8001 /* Convert the dirent64 structs to target dirent. We do this
8002 * in-place, since we can guarantee that a target_dirent is no
8003 * larger than a dirent64; however this means we have to be
8004 * careful to read everything before writing in the new format.
8005 */
8006 struct linux_dirent64 *de;
8007 struct target_dirent *tde;
8008 int len = ret;
8009 int tlen = 0;
8010
8011 de = dirp;
8012 tde = (struct target_dirent *)dirp;
8013 while (len > 0) {
8014 int namelen, treclen;
8015 int reclen = de->d_reclen;
8016 uint64_t ino = de->d_ino;
8017 int64_t off = de->d_off;
8018 uint8_t type = de->d_type;
8019
8020 namelen = strlen(de->d_name);
8021 treclen = offsetof(struct target_dirent, d_name)
8022 + namelen + 2;
8023 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8024
8025 memmove(tde->d_name, de->d_name, namelen + 1);
8026 tde->d_ino = tswapal(ino);
8027 tde->d_off = tswapal(off);
8028 tde->d_reclen = tswap16(treclen);
8029 /* The target_dirent type is in what was formerly a padding
8030 * byte at the end of the structure:
8031 */
8032 *(((char *)tde) + treclen - 1) = type;
8033
8034 de = (struct linux_dirent64 *)((char *)de + reclen);
8035 tde = (struct target_dirent *)((char *)tde + treclen);
8036 len -= reclen;
8037 tlen += treclen;
8038 }
8039 ret = tlen;
8040 }
8041 unlock_user(dirp, arg2, ret);
8042 }
8043#endif
bellard31e31b82003-02-18 22:55:36 +00008044 break;
Chen Gang704eff62015-08-21 05:37:33 +08008045#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008046#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008047 case TARGET_NR_getdents64:
8048 {
aurel326556a832008-10-13 21:08:17 +00008049 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008050 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008051 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8052 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008053 ret = get_errno(sys_getdents64(arg1, dirp, count));
8054 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008055 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008056 int len = ret;
8057 int reclen;
8058 de = dirp;
8059 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008060 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008061 if (reclen > len)
8062 break;
bellard8083a3e2003-03-24 23:12:16 +00008063 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008064 tswap64s((uint64_t *)&de->d_ino);
8065 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008066 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008067 len -= reclen;
8068 }
8069 }
pbrook53a59602006-03-25 19:31:22 +00008070 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008071 }
8072 break;
bellarda541f292004-04-12 20:39:29 +00008073#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008074#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008075 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008076 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008077 break;
thse5febef2007-04-01 18:31:35 +00008078#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008079#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8080# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008081 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008082# endif
8083# ifdef TARGET_NR_ppoll
8084 case TARGET_NR_ppoll:
8085# endif
bellard9de5e442003-03-23 16:49:39 +00008086 {
pbrook53a59602006-03-25 19:31:22 +00008087 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008088 unsigned int nfds = arg2;
8089 int timeout = arg3;
8090 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008091 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008092
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008093 pfd = NULL;
8094 target_pfd = NULL;
8095 if (nfds) {
8096 target_pfd = lock_user(VERIFY_WRITE, arg1,
8097 sizeof(struct target_pollfd) * nfds, 1);
8098 if (!target_pfd) {
8099 goto efault;
8100 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008101
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008102 pfd = alloca(sizeof(struct pollfd) * nfds);
8103 for (i = 0; i < nfds; i++) {
8104 pfd[i].fd = tswap32(target_pfd[i].fd);
8105 pfd[i].events = tswap16(target_pfd[i].events);
8106 }
bellard9de5e442003-03-23 16:49:39 +00008107 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008108
8109# ifdef TARGET_NR_ppoll
8110 if (num == TARGET_NR_ppoll) {
8111 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8112 target_sigset_t *target_set;
8113 sigset_t _set, *set = &_set;
8114
8115 if (arg3) {
8116 if (target_to_host_timespec(timeout_ts, arg3)) {
8117 unlock_user(target_pfd, arg1, 0);
8118 goto efault;
8119 }
8120 } else {
8121 timeout_ts = NULL;
8122 }
8123
8124 if (arg4) {
8125 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
8126 if (!target_set) {
8127 unlock_user(target_pfd, arg1, 0);
8128 goto efault;
8129 }
8130 target_to_host_sigset(set, target_set);
8131 } else {
8132 set = NULL;
8133 }
8134
8135 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
8136
8137 if (!is_error(ret) && arg3) {
8138 host_to_target_timespec(arg3, timeout_ts);
8139 }
8140 if (arg4) {
8141 unlock_user(target_set, arg4, 0);
8142 }
8143 } else
8144# endif
8145 ret = get_errno(poll(pfd, nfds, timeout));
8146
bellard9de5e442003-03-23 16:49:39 +00008147 if (!is_error(ret)) {
8148 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00008149 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00008150 }
8151 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00008152 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00008153 }
8154 break;
thse5febef2007-04-01 18:31:35 +00008155#endif
bellard31e31b82003-02-18 22:55:36 +00008156 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00008157 /* NOTE: the flock constant seems to be the same for every
8158 Linux platform */
8159 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008160 break;
8161 case TARGET_NR_readv:
8162 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008163 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
8164 if (vec != NULL) {
8165 ret = get_errno(readv(arg1, vec, arg3));
8166 unlock_iovec(vec, arg2, arg3, 1);
8167 } else {
8168 ret = -host_to_target_errno(errno);
8169 }
bellard31e31b82003-02-18 22:55:36 +00008170 }
8171 break;
8172 case TARGET_NR_writev:
8173 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008174 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8175 if (vec != NULL) {
8176 ret = get_errno(writev(arg1, vec, arg3));
8177 unlock_iovec(vec, arg2, arg3, 0);
8178 } else {
8179 ret = -host_to_target_errno(errno);
8180 }
bellard31e31b82003-02-18 22:55:36 +00008181 }
8182 break;
8183 case TARGET_NR_getsid:
8184 ret = get_errno(getsid(arg1));
8185 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008186#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00008187 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00008188 ret = get_errno(fdatasync(arg1));
8189 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008190#endif
Chen Gang704eff62015-08-21 05:37:33 +08008191#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00008192 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00008193 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00008194 return value. */
ths0da46a62007-10-20 20:23:07 +00008195 ret = -TARGET_ENOTDIR;
8196 break;
Chen Gang704eff62015-08-21 05:37:33 +08008197#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05008198 case TARGET_NR_sched_getaffinity:
8199 {
8200 unsigned int mask_size;
8201 unsigned long *mask;
8202
8203 /*
8204 * sched_getaffinity needs multiples of ulong, so need to take
8205 * care of mismatches between target ulong and host ulong sizes.
8206 */
8207 if (arg2 & (sizeof(abi_ulong) - 1)) {
8208 ret = -TARGET_EINVAL;
8209 break;
8210 }
8211 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8212
8213 mask = alloca(mask_size);
8214 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
8215
8216 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01008217 if (ret > arg2) {
8218 /* More data returned than the caller's buffer will fit.
8219 * This only happens if sizeof(abi_long) < sizeof(long)
8220 * and the caller passed us a buffer holding an odd number
8221 * of abi_longs. If the host kernel is actually using the
8222 * extra 4 bytes then fail EINVAL; otherwise we can just
8223 * ignore them and only copy the interesting part.
8224 */
8225 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
8226 if (numcpus > arg2 * 8) {
8227 ret = -TARGET_EINVAL;
8228 break;
8229 }
8230 ret = arg2;
8231 }
8232
Mike McCormackcd18f052011-04-18 14:43:36 +09008233 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05008234 goto efault;
8235 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05008236 }
8237 }
8238 break;
8239 case TARGET_NR_sched_setaffinity:
8240 {
8241 unsigned int mask_size;
8242 unsigned long *mask;
8243
8244 /*
8245 * sched_setaffinity needs multiples of ulong, so need to take
8246 * care of mismatches between target ulong and host ulong sizes.
8247 */
8248 if (arg2 & (sizeof(abi_ulong) - 1)) {
8249 ret = -TARGET_EINVAL;
8250 break;
8251 }
8252 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8253
8254 mask = alloca(mask_size);
8255 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
8256 goto efault;
8257 }
8258 memcpy(mask, p, arg2);
8259 unlock_user_struct(p, arg2, 0);
8260
8261 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
8262 }
8263 break;
bellard31e31b82003-02-18 22:55:36 +00008264 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00008265 {
pbrook53a59602006-03-25 19:31:22 +00008266 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008267 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00008268
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008269 if (arg2 == 0) {
8270 return -TARGET_EINVAL;
8271 }
bellard579a97f2007-11-11 14:26:47 +00008272 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
8273 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008274 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008275 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00008276 ret = get_errno(sched_setparam(arg1, &schp));
8277 }
8278 break;
bellard31e31b82003-02-18 22:55:36 +00008279 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00008280 {
pbrook53a59602006-03-25 19:31:22 +00008281 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008282 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008283
8284 if (arg2 == 0) {
8285 return -TARGET_EINVAL;
8286 }
bellard5cd43932003-03-29 16:54:36 +00008287 ret = get_errno(sched_getparam(arg1, &schp));
8288 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008289 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
8290 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008291 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008292 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00008293 }
8294 }
8295 break;
bellard31e31b82003-02-18 22:55:36 +00008296 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00008297 {
pbrook53a59602006-03-25 19:31:22 +00008298 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008299 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008300 if (arg3 == 0) {
8301 return -TARGET_EINVAL;
8302 }
bellard579a97f2007-11-11 14:26:47 +00008303 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
8304 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008305 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008306 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00008307 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
8308 }
8309 break;
bellard31e31b82003-02-18 22:55:36 +00008310 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00008311 ret = get_errno(sched_getscheduler(arg1));
8312 break;
bellard31e31b82003-02-18 22:55:36 +00008313 case TARGET_NR_sched_yield:
8314 ret = get_errno(sched_yield());
8315 break;
8316 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00008317 ret = get_errno(sched_get_priority_max(arg1));
8318 break;
bellard31e31b82003-02-18 22:55:36 +00008319 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00008320 ret = get_errno(sched_get_priority_min(arg1));
8321 break;
bellard31e31b82003-02-18 22:55:36 +00008322 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00008323 {
bellard5cd43932003-03-29 16:54:36 +00008324 struct timespec ts;
8325 ret = get_errno(sched_rr_get_interval(arg1, &ts));
8326 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05008327 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00008328 }
8329 }
8330 break;
bellard31e31b82003-02-18 22:55:36 +00008331 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00008332 {
bellard1b6b0292003-03-22 17:31:38 +00008333 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00008334 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00008335 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00008336 if (is_error(ret) && arg2) {
8337 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00008338 }
8339 }
8340 break;
thse5febef2007-04-01 18:31:35 +00008341#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00008342 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00008343 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008344#endif
8345#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00008346 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00008347 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008348#endif
bellard31e31b82003-02-18 22:55:36 +00008349 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00008350 switch (arg1) {
8351 case PR_GET_PDEATHSIG:
8352 {
8353 int deathsig;
8354 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
8355 if (!is_error(ret) && arg2
8356 && put_user_ual(deathsig, arg2)) {
8357 goto efault;
thse5574482007-02-11 20:03:13 +00008358 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00008359 break;
8360 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00008361#ifdef PR_GET_NAME
8362 case PR_GET_NAME:
8363 {
8364 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
8365 if (!name) {
8366 goto efault;
8367 }
8368 ret = get_errno(prctl(arg1, (unsigned long)name,
8369 arg3, arg4, arg5));
8370 unlock_user(name, arg2, 16);
8371 break;
8372 }
8373 case PR_SET_NAME:
8374 {
8375 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
8376 if (!name) {
8377 goto efault;
8378 }
8379 ret = get_errno(prctl(arg1, (unsigned long)name,
8380 arg3, arg4, arg5));
8381 unlock_user(name, arg2, 0);
8382 break;
8383 }
8384#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00008385 default:
8386 /* Most prctl options have no pointer arguments */
8387 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
8388 break;
8389 }
ths39b9aae2007-02-11 18:36:44 +00008390 break;
bellardd2fd1af2007-11-14 18:08:56 +00008391#ifdef TARGET_NR_arch_prctl
8392 case TARGET_NR_arch_prctl:
8393#if defined(TARGET_I386) && !defined(TARGET_ABI32)
8394 ret = do_arch_prctl(cpu_env, arg1, arg2);
8395 break;
8396#else
8397 goto unimplemented;
8398#endif
8399#endif
aurel32f2c7ba12008-03-28 22:32:06 +00008400#ifdef TARGET_NR_pread64
8401 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00008402 if (regpairs_aligned(cpu_env)) {
8403 arg4 = arg5;
8404 arg5 = arg6;
8405 }
aurel32f2c7ba12008-03-28 22:32:06 +00008406 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8407 goto efault;
8408 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
8409 unlock_user(p, arg2, ret);
8410 break;
8411 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00008412 if (regpairs_aligned(cpu_env)) {
8413 arg4 = arg5;
8414 arg5 = arg6;
8415 }
aurel32f2c7ba12008-03-28 22:32:06 +00008416 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8417 goto efault;
8418 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
8419 unlock_user(p, arg2, 0);
8420 break;
8421#endif
bellard31e31b82003-02-18 22:55:36 +00008422 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00008423 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
8424 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008425 ret = get_errno(sys_getcwd1(p, arg2));
8426 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00008427 break;
8428 case TARGET_NR_capget:
8429 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00008430 {
8431 struct target_user_cap_header *target_header;
8432 struct target_user_cap_data *target_data = NULL;
8433 struct __user_cap_header_struct header;
8434 struct __user_cap_data_struct data[2];
8435 struct __user_cap_data_struct *dataptr = NULL;
8436 int i, target_datalen;
8437 int data_items = 1;
8438
8439 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
8440 goto efault;
8441 }
8442 header.version = tswap32(target_header->version);
8443 header.pid = tswap32(target_header->pid);
8444
Peter Maydellec864872014-03-19 16:07:30 +00008445 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008446 /* Version 2 and up takes pointer to two user_data structs */
8447 data_items = 2;
8448 }
8449
8450 target_datalen = sizeof(*target_data) * data_items;
8451
8452 if (arg2) {
8453 if (num == TARGET_NR_capget) {
8454 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8455 } else {
8456 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8457 }
8458 if (!target_data) {
8459 unlock_user_struct(target_header, arg1, 0);
8460 goto efault;
8461 }
8462
8463 if (num == TARGET_NR_capset) {
8464 for (i = 0; i < data_items; i++) {
8465 data[i].effective = tswap32(target_data[i].effective);
8466 data[i].permitted = tswap32(target_data[i].permitted);
8467 data[i].inheritable = tswap32(target_data[i].inheritable);
8468 }
8469 }
8470
8471 dataptr = data;
8472 }
8473
8474 if (num == TARGET_NR_capget) {
8475 ret = get_errno(capget(&header, dataptr));
8476 } else {
8477 ret = get_errno(capset(&header, dataptr));
8478 }
8479
8480 /* The kernel always updates version for both capget and capset */
8481 target_header->version = tswap32(header.version);
8482 unlock_user_struct(target_header, arg1, 1);
8483
8484 if (arg2) {
8485 if (num == TARGET_NR_capget) {
8486 for (i = 0; i < data_items; i++) {
8487 target_data[i].effective = tswap32(data[i].effective);
8488 target_data[i].permitted = tswap32(data[i].permitted);
8489 target_data[i].inheritable = tswap32(data[i].inheritable);
8490 }
8491 unlock_user(target_data, arg2, target_datalen);
8492 } else {
8493 unlock_user(target_data, arg2, 0);
8494 }
8495 }
8496 break;
8497 }
bellard31e31b82003-02-18 22:55:36 +00008498 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01008499 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008500 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008501
8502#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008503 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008504 {
8505 off_t *offp = NULL;
8506 off_t off;
8507 if (arg3) {
8508 ret = get_user_sal(off, arg3);
8509 if (is_error(ret)) {
8510 break;
8511 }
8512 offp = &off;
8513 }
8514 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8515 if (!is_error(ret) && arg3) {
8516 abi_long ret2 = put_user_sal(off, arg3);
8517 if (is_error(ret2)) {
8518 ret = ret2;
8519 }
8520 }
8521 break;
8522 }
8523#ifdef TARGET_NR_sendfile64
8524 case TARGET_NR_sendfile64:
8525 {
8526 off_t *offp = NULL;
8527 off_t off;
8528 if (arg3) {
8529 ret = get_user_s64(off, arg3);
8530 if (is_error(ret)) {
8531 break;
8532 }
8533 offp = &off;
8534 }
8535 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8536 if (!is_error(ret) && arg3) {
8537 abi_long ret2 = put_user_s64(off, arg3);
8538 if (is_error(ret2)) {
8539 ret = ret2;
8540 }
8541 }
8542 break;
8543 }
8544#endif
8545#else
8546 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008547#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008548 case TARGET_NR_sendfile64:
8549#endif
bellard5cd43932003-03-29 16:54:36 +00008550 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008551#endif
8552
bellardebc05482003-09-30 21:08:41 +00008553#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008554 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008555 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008556#endif
8557#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008558 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008559 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008560#endif
bellard048f6b42005-11-26 18:47:20 +00008561#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008562 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008563 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8564 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008565 break;
bellard048f6b42005-11-26 18:47:20 +00008566#endif
bellardebc05482003-09-30 21:08:41 +00008567#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008568 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008569 {
8570 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008571 int resource = target_to_host_resource(arg1);
8572 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008573 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008574 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008575 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8576 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008577 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8578 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008579 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008580 }
8581 break;
8582 }
bellardebc05482003-09-30 21:08:41 +00008583#endif
bellarda315a142005-01-30 22:59:18 +00008584#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008585 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008586 if (!(p = lock_user_string(arg1)))
8587 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008588 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8589 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008590 break;
bellarda315a142005-01-30 22:59:18 +00008591#endif
8592#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008593 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008594 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008595 break;
bellarda315a142005-01-30 22:59:18 +00008596#endif
8597#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008598 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008599 if (!(p = lock_user_string(arg1)))
8600 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008601 ret = get_errno(stat(path(p), &st));
8602 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008603 if (!is_error(ret))
8604 ret = host_to_target_stat64(cpu_env, arg2, &st);
8605 break;
bellarda315a142005-01-30 22:59:18 +00008606#endif
8607#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008608 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008609 if (!(p = lock_user_string(arg1)))
8610 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008611 ret = get_errno(lstat(path(p), &st));
8612 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008613 if (!is_error(ret))
8614 ret = host_to_target_stat64(cpu_env, arg2, &st);
8615 break;
bellarda315a142005-01-30 22:59:18 +00008616#endif
8617#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008618 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008619 ret = get_errno(fstat(arg1, &st));
8620 if (!is_error(ret))
8621 ret = host_to_target_stat64(cpu_env, arg2, &st);
8622 break;
bellardec86b0f2003-04-11 00:15:04 +00008623#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008624#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008625#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008626 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008627#endif
8628#ifdef TARGET_NR_newfstatat
8629 case TARGET_NR_newfstatat:
8630#endif
balrog6a24a772008-09-20 02:23:36 +00008631 if (!(p = lock_user_string(arg2)))
8632 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008633 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008634 if (!is_error(ret))
8635 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008636 break;
bellarda315a142005-01-30 22:59:18 +00008637#endif
Chen Gang704eff62015-08-21 05:37:33 +08008638#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00008639 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008640 if (!(p = lock_user_string(arg1)))
8641 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008642 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8643 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008644 break;
Chen Gang704eff62015-08-21 05:37:33 +08008645#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03008646#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008647 case TARGET_NR_getuid:
8648 ret = get_errno(high2lowuid(getuid()));
8649 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008650#endif
8651#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008652 case TARGET_NR_getgid:
8653 ret = get_errno(high2lowgid(getgid()));
8654 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008655#endif
8656#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008657 case TARGET_NR_geteuid:
8658 ret = get_errno(high2lowuid(geteuid()));
8659 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008660#endif
8661#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008662 case TARGET_NR_getegid:
8663 ret = get_errno(high2lowgid(getegid()));
8664 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008665#endif
bellard67867302003-11-23 17:05:30 +00008666 case TARGET_NR_setreuid:
8667 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8668 break;
8669 case TARGET_NR_setregid:
8670 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8671 break;
8672 case TARGET_NR_getgroups:
8673 {
8674 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008675 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008676 gid_t *grouplist;
8677 int i;
8678
8679 grouplist = alloca(gidsetsize * sizeof(gid_t));
8680 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008681 if (gidsetsize == 0)
8682 break;
bellard67867302003-11-23 17:05:30 +00008683 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008684 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008685 if (!target_grouplist)
8686 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008687 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008688 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008689 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008690 }
8691 }
8692 break;
8693 case TARGET_NR_setgroups:
8694 {
8695 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008696 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008697 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008698 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008699 if (gidsetsize) {
8700 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008701 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008702 if (!target_grouplist) {
8703 ret = -TARGET_EFAULT;
8704 goto fail;
8705 }
8706 for (i = 0; i < gidsetsize; i++) {
8707 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8708 }
8709 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008710 }
bellard67867302003-11-23 17:05:30 +00008711 ret = get_errno(setgroups(gidsetsize, grouplist));
8712 }
8713 break;
8714 case TARGET_NR_fchown:
8715 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8716 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008717#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008718 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008719 if (!(p = lock_user_string(arg2)))
8720 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008721 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8722 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008723 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008724 break;
8725#endif
bellard67867302003-11-23 17:05:30 +00008726#ifdef TARGET_NR_setresuid
8727 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008728 ret = get_errno(setresuid(low2highuid(arg1),
8729 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008730 low2highuid(arg3)));
8731 break;
8732#endif
8733#ifdef TARGET_NR_getresuid
8734 case TARGET_NR_getresuid:
8735 {
pbrook53a59602006-03-25 19:31:22 +00008736 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008737 ret = get_errno(getresuid(&ruid, &euid, &suid));
8738 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008739 if (put_user_id(high2lowuid(ruid), arg1)
8740 || put_user_id(high2lowuid(euid), arg2)
8741 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008742 goto efault;
bellard67867302003-11-23 17:05:30 +00008743 }
8744 }
8745 break;
8746#endif
8747#ifdef TARGET_NR_getresgid
8748 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008749 ret = get_errno(setresgid(low2highgid(arg1),
8750 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008751 low2highgid(arg3)));
8752 break;
8753#endif
8754#ifdef TARGET_NR_getresgid
8755 case TARGET_NR_getresgid:
8756 {
pbrook53a59602006-03-25 19:31:22 +00008757 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008758 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8759 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008760 if (put_user_id(high2lowgid(rgid), arg1)
8761 || put_user_id(high2lowgid(egid), arg2)
8762 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008763 goto efault;
bellard67867302003-11-23 17:05:30 +00008764 }
8765 }
8766 break;
8767#endif
Chen Gang704eff62015-08-21 05:37:33 +08008768#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00008769 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008770 if (!(p = lock_user_string(arg1)))
8771 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008772 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8773 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008774 break;
Chen Gang704eff62015-08-21 05:37:33 +08008775#endif
bellard67867302003-11-23 17:05:30 +00008776 case TARGET_NR_setuid:
8777 ret = get_errno(setuid(low2highuid(arg1)));
8778 break;
8779 case TARGET_NR_setgid:
8780 ret = get_errno(setgid(low2highgid(arg1)));
8781 break;
8782 case TARGET_NR_setfsuid:
8783 ret = get_errno(setfsuid(arg1));
8784 break;
8785 case TARGET_NR_setfsgid:
8786 ret = get_errno(setfsgid(arg1));
8787 break;
bellard67867302003-11-23 17:05:30 +00008788
bellarda315a142005-01-30 22:59:18 +00008789#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008790 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008791 if (!(p = lock_user_string(arg1)))
8792 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008793 ret = get_errno(lchown(p, arg2, arg3));
8794 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008795 break;
bellarda315a142005-01-30 22:59:18 +00008796#endif
8797#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008798 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008799 ret = get_errno(getuid());
8800 break;
bellarda315a142005-01-30 22:59:18 +00008801#endif
aurel3264b4d282008-11-14 17:20:15 +00008802
8803#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8804 /* Alpha specific */
8805 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008806 {
8807 uid_t euid;
8808 euid=geteuid();
8809 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8810 }
aurel3264b4d282008-11-14 17:20:15 +00008811 ret = get_errno(getuid());
8812 break;
8813#endif
8814#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8815 /* Alpha specific */
8816 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008817 {
8818 uid_t egid;
8819 egid=getegid();
8820 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8821 }
aurel3264b4d282008-11-14 17:20:15 +00008822 ret = get_errno(getgid());
8823 break;
8824#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008825#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8826 /* Alpha specific */
8827 case TARGET_NR_osf_getsysinfo:
8828 ret = -TARGET_EOPNOTSUPP;
8829 switch (arg1) {
8830 case TARGET_GSI_IEEE_FP_CONTROL:
8831 {
8832 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8833
8834 /* Copied from linux ieee_fpcr_to_swcr. */
8835 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8836 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8837 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8838 | SWCR_TRAP_ENABLE_DZE
8839 | SWCR_TRAP_ENABLE_OVF);
8840 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8841 | SWCR_TRAP_ENABLE_INE);
8842 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8843 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8844
8845 if (put_user_u64 (swcr, arg2))
8846 goto efault;
8847 ret = 0;
8848 }
8849 break;
8850
8851 /* case GSI_IEEE_STATE_AT_SIGNAL:
8852 -- Not implemented in linux kernel.
8853 case GSI_UACPROC:
8854 -- Retrieves current unaligned access state; not much used.
8855 case GSI_PROC_TYPE:
8856 -- Retrieves implver information; surely not used.
8857 case GSI_GET_HWRPB:
8858 -- Grabs a copy of the HWRPB; surely not used.
8859 */
8860 }
8861 break;
8862#endif
8863#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8864 /* Alpha specific */
8865 case TARGET_NR_osf_setsysinfo:
8866 ret = -TARGET_EOPNOTSUPP;
8867 switch (arg1) {
8868 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008869 {
8870 uint64_t swcr, fpcr, orig_fpcr;
8871
Richard Henderson6e06d512012-06-01 09:08:21 -07008872 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008873 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008874 }
8875 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008876 fpcr = orig_fpcr & FPCR_DYN_MASK;
8877
8878 /* Copied from linux ieee_swcr_to_fpcr. */
8879 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8880 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8881 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8882 | SWCR_TRAP_ENABLE_DZE
8883 | SWCR_TRAP_ENABLE_OVF)) << 48;
8884 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8885 | SWCR_TRAP_ENABLE_INE)) << 57;
8886 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8887 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8888
Richard Henderson6e06d512012-06-01 09:08:21 -07008889 cpu_alpha_store_fpcr(cpu_env, fpcr);
8890 ret = 0;
8891 }
8892 break;
8893
8894 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8895 {
8896 uint64_t exc, fpcr, orig_fpcr;
8897 int si_code;
8898
8899 if (get_user_u64(exc, arg2)) {
8900 goto efault;
8901 }
8902
8903 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8904
8905 /* We only add to the exception status here. */
8906 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8907
8908 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008909 ret = 0;
8910
Richard Henderson6e06d512012-06-01 09:08:21 -07008911 /* Old exceptions are not signaled. */
8912 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008913
Richard Henderson6e06d512012-06-01 09:08:21 -07008914 /* If any exceptions set by this call,
8915 and are unmasked, send a signal. */
8916 si_code = 0;
8917 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8918 si_code = TARGET_FPE_FLTRES;
8919 }
8920 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8921 si_code = TARGET_FPE_FLTUND;
8922 }
8923 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8924 si_code = TARGET_FPE_FLTOVF;
8925 }
8926 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8927 si_code = TARGET_FPE_FLTDIV;
8928 }
8929 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8930 si_code = TARGET_FPE_FLTINV;
8931 }
8932 if (si_code != 0) {
8933 target_siginfo_t info;
8934 info.si_signo = SIGFPE;
8935 info.si_errno = 0;
8936 info.si_code = si_code;
8937 info._sifields._sigfault._addr
8938 = ((CPUArchState *)cpu_env)->pc;
8939 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008940 }
8941 }
8942 break;
8943
8944 /* case SSI_NVPAIRS:
8945 -- Used with SSIN_UACPROC to enable unaligned accesses.
8946 case SSI_IEEE_STATE_AT_SIGNAL:
8947 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8948 -- Not implemented in linux kernel
8949 */
8950 }
8951 break;
8952#endif
8953#ifdef TARGET_NR_osf_sigprocmask
8954 /* Alpha specific. */
8955 case TARGET_NR_osf_sigprocmask:
8956 {
8957 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008958 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008959 sigset_t set, oldset;
8960
8961 switch(arg1) {
8962 case TARGET_SIG_BLOCK:
8963 how = SIG_BLOCK;
8964 break;
8965 case TARGET_SIG_UNBLOCK:
8966 how = SIG_UNBLOCK;
8967 break;
8968 case TARGET_SIG_SETMASK:
8969 how = SIG_SETMASK;
8970 break;
8971 default:
8972 ret = -TARGET_EINVAL;
8973 goto fail;
8974 }
8975 mask = arg2;
8976 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008977 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008978 host_to_target_old_sigset(&mask, &oldset);
8979 ret = mask;
8980 }
8981 break;
8982#endif
aurel3264b4d282008-11-14 17:20:15 +00008983
bellarda315a142005-01-30 22:59:18 +00008984#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008985 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008986 ret = get_errno(getgid());
8987 break;
bellarda315a142005-01-30 22:59:18 +00008988#endif
8989#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008990 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008991 ret = get_errno(geteuid());
8992 break;
bellarda315a142005-01-30 22:59:18 +00008993#endif
8994#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008995 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008996 ret = get_errno(getegid());
8997 break;
bellarda315a142005-01-30 22:59:18 +00008998#endif
8999#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009000 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009001 ret = get_errno(setreuid(arg1, arg2));
9002 break;
bellarda315a142005-01-30 22:59:18 +00009003#endif
9004#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009005 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009006 ret = get_errno(setregid(arg1, arg2));
9007 break;
bellarda315a142005-01-30 22:59:18 +00009008#endif
9009#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009010 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009011 {
9012 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009013 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009014 gid_t *grouplist;
9015 int i;
9016
9017 grouplist = alloca(gidsetsize * sizeof(gid_t));
9018 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009019 if (gidsetsize == 0)
9020 break;
bellard99c475a2005-01-31 20:45:13 +00009021 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009022 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9023 if (!target_grouplist) {
9024 ret = -TARGET_EFAULT;
9025 goto fail;
9026 }
balroga2155fc2008-09-20 02:12:08 +00009027 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009028 target_grouplist[i] = tswap32(grouplist[i]);
9029 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009030 }
9031 }
9032 break;
bellarda315a142005-01-30 22:59:18 +00009033#endif
9034#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009035 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009036 {
9037 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009038 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009039 gid_t *grouplist;
9040 int i;
ths3b46e622007-09-17 08:09:54 +00009041
bellard99c475a2005-01-31 20:45:13 +00009042 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009043 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9044 if (!target_grouplist) {
9045 ret = -TARGET_EFAULT;
9046 goto fail;
9047 }
bellard99c475a2005-01-31 20:45:13 +00009048 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009049 grouplist[i] = tswap32(target_grouplist[i]);
9050 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009051 ret = get_errno(setgroups(gidsetsize, grouplist));
9052 }
9053 break;
bellarda315a142005-01-30 22:59:18 +00009054#endif
9055#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009056 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009057 ret = get_errno(fchown(arg1, arg2, arg3));
9058 break;
bellarda315a142005-01-30 22:59:18 +00009059#endif
9060#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009061 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009062 ret = get_errno(setresuid(arg1, arg2, arg3));
9063 break;
bellarda315a142005-01-30 22:59:18 +00009064#endif
9065#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009066 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009067 {
pbrook53a59602006-03-25 19:31:22 +00009068 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009069 ret = get_errno(getresuid(&ruid, &euid, &suid));
9070 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009071 if (put_user_u32(ruid, arg1)
9072 || put_user_u32(euid, arg2)
9073 || put_user_u32(suid, arg3))
9074 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009075 }
9076 }
9077 break;
bellarda315a142005-01-30 22:59:18 +00009078#endif
9079#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009080 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009081 ret = get_errno(setresgid(arg1, arg2, arg3));
9082 break;
bellarda315a142005-01-30 22:59:18 +00009083#endif
9084#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009085 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009086 {
pbrook53a59602006-03-25 19:31:22 +00009087 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009088 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9089 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009090 if (put_user_u32(rgid, arg1)
9091 || put_user_u32(egid, arg2)
9092 || put_user_u32(sgid, arg3))
9093 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009094 }
9095 }
9096 break;
bellarda315a142005-01-30 22:59:18 +00009097#endif
9098#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009099 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009100 if (!(p = lock_user_string(arg1)))
9101 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009102 ret = get_errno(chown(p, arg2, arg3));
9103 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009104 break;
bellarda315a142005-01-30 22:59:18 +00009105#endif
9106#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009107 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00009108 ret = get_errno(setuid(arg1));
9109 break;
bellarda315a142005-01-30 22:59:18 +00009110#endif
9111#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009112 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00009113 ret = get_errno(setgid(arg1));
9114 break;
bellarda315a142005-01-30 22:59:18 +00009115#endif
9116#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009117 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009118 ret = get_errno(setfsuid(arg1));
9119 break;
bellarda315a142005-01-30 22:59:18 +00009120#endif
9121#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00009122 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00009123 ret = get_errno(setfsgid(arg1));
9124 break;
bellarda315a142005-01-30 22:59:18 +00009125#endif
bellard67867302003-11-23 17:05:30 +00009126
bellard31e31b82003-02-18 22:55:36 +00009127 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00009128 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00009129#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00009130 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00009131 {
9132 void *a;
9133 ret = -TARGET_EFAULT;
9134 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
9135 goto efault;
9136 if (!(p = lock_user_string(arg3)))
9137 goto mincore_fail;
9138 ret = get_errno(mincore(a, arg2, p));
9139 unlock_user(p, arg3, ret);
9140 mincore_fail:
9141 unlock_user(a, arg1, 0);
9142 }
9143 break;
bellardffa65c32004-01-04 23:57:22 +00009144#endif
aurel32408321b2008-10-01 21:46:32 +00009145#ifdef TARGET_NR_arm_fadvise64_64
9146 case TARGET_NR_arm_fadvise64_64:
9147 {
9148 /*
9149 * arm_fadvise64_64 looks like fadvise64_64 but
9150 * with different argument order
9151 */
9152 abi_long temp;
9153 temp = arg3;
9154 arg3 = arg4;
9155 arg4 = temp;
9156 }
9157#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009158#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00009159#ifdef TARGET_NR_fadvise64_64
9160 case TARGET_NR_fadvise64_64:
9161#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009162#ifdef TARGET_NR_fadvise64
9163 case TARGET_NR_fadvise64:
9164#endif
9165#ifdef TARGET_S390X
9166 switch (arg4) {
9167 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
9168 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
9169 case 6: arg4 = POSIX_FADV_DONTNEED; break;
9170 case 7: arg4 = POSIX_FADV_NOREUSE; break;
9171 default: break;
9172 }
9173#endif
9174 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00009175 break;
9176#endif
bellardffa65c32004-01-04 23:57:22 +00009177#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00009178 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00009179 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08009180 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00009181 This will break MADV_DONTNEED.
9182 This is a hint, so ignoring and returning success is ok. */
9183 ret = get_errno(0);
9184 break;
bellardffa65c32004-01-04 23:57:22 +00009185#endif
blueswir1992f48a2007-10-14 16:27:31 +00009186#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00009187 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00009188 {
thsb1e341e2007-03-20 21:50:52 +00009189 int cmd;
bellard77e46722003-04-29 20:39:06 +00009190 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00009191 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00009192#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00009193 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00009194#endif
bellard77e46722003-04-29 20:39:06 +00009195
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009196 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00009197 if (cmd == -TARGET_EINVAL) {
9198 ret = cmd;
9199 break;
9200 }
thsb1e341e2007-03-20 21:50:52 +00009201
bellard60cd49d2003-03-16 22:53:56 +00009202 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00009203 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00009204#ifdef TARGET_ARM
9205 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009206 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9207 goto efault;
ths58134272007-03-31 18:59:32 +00009208 fl.l_type = tswap16(target_efl->l_type);
9209 fl.l_whence = tswap16(target_efl->l_whence);
9210 fl.l_start = tswap64(target_efl->l_start);
9211 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009212 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00009213 unlock_user_struct(target_efl, arg3, 0);
9214 } else
9215#endif
9216 {
bellard9ee1fa22007-11-11 15:11:19 +00009217 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9218 goto efault;
ths58134272007-03-31 18:59:32 +00009219 fl.l_type = tswap16(target_fl->l_type);
9220 fl.l_whence = tswap16(target_fl->l_whence);
9221 fl.l_start = tswap64(target_fl->l_start);
9222 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009223 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00009224 unlock_user_struct(target_fl, arg3, 0);
9225 }
thsb1e341e2007-03-20 21:50:52 +00009226 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009227 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00009228#ifdef TARGET_ARM
9229 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009230 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
9231 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009232 target_efl->l_type = tswap16(fl.l_type);
9233 target_efl->l_whence = tswap16(fl.l_whence);
9234 target_efl->l_start = tswap64(fl.l_start);
9235 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009236 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009237 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009238 } else
9239#endif
9240 {
bellard9ee1fa22007-11-11 15:11:19 +00009241 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
9242 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009243 target_fl->l_type = tswap16(fl.l_type);
9244 target_fl->l_whence = tswap16(fl.l_whence);
9245 target_fl->l_start = tswap64(fl.l_start);
9246 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009247 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009248 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009249 }
bellard77e46722003-04-29 20:39:06 +00009250 }
9251 break;
9252
thsb1e341e2007-03-20 21:50:52 +00009253 case TARGET_F_SETLK64:
9254 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00009255#ifdef TARGET_ARM
9256 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009257 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9258 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009259 fl.l_type = tswap16(target_efl->l_type);
9260 fl.l_whence = tswap16(target_efl->l_whence);
9261 fl.l_start = tswap64(target_efl->l_start);
9262 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009263 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009264 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009265 } else
9266#endif
9267 {
bellard9ee1fa22007-11-11 15:11:19 +00009268 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9269 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009270 fl.l_type = tswap16(target_fl->l_type);
9271 fl.l_whence = tswap16(target_fl->l_whence);
9272 fl.l_start = tswap64(target_fl->l_start);
9273 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009274 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009275 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009276 }
thsb1e341e2007-03-20 21:50:52 +00009277 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009278 break;
bellard60cd49d2003-03-16 22:53:56 +00009279 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009280 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00009281 break;
9282 }
bellard77e46722003-04-29 20:39:06 +00009283 break;
9284 }
bellard60cd49d2003-03-16 22:53:56 +00009285#endif
ths7d600c82006-12-08 01:32:58 +00009286#ifdef TARGET_NR_cacheflush
9287 case TARGET_NR_cacheflush:
9288 /* self-modifying code is handled automatically, so nothing needed */
9289 ret = 0;
9290 break;
9291#endif
bellardebc05482003-09-30 21:08:41 +00009292#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00009293 case TARGET_NR_security:
9294 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009295#endif
bellardc573ff62004-01-04 15:51:36 +00009296#ifdef TARGET_NR_getpagesize
9297 case TARGET_NR_getpagesize:
9298 ret = TARGET_PAGE_SIZE;
9299 break;
9300#endif
bellard31e31b82003-02-18 22:55:36 +00009301 case TARGET_NR_gettid:
9302 ret = get_errno(gettid());
9303 break;
thse5febef2007-04-01 18:31:35 +00009304#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00009305 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00009306#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03009307 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00009308 arg2 = arg3;
9309 arg3 = arg4;
9310 arg4 = arg5;
9311 }
aurel322054ac92008-10-13 21:08:07 +00009312 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
9313#else
9314 ret = get_errno(readahead(arg1, arg2, arg3));
9315#endif
9316 break;
thse5febef2007-04-01 18:31:35 +00009317#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009318#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00009319#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00009320 case TARGET_NR_listxattr:
9321 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00009322 {
9323 void *p, *b = 0;
9324 if (arg2) {
9325 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9326 if (!b) {
9327 ret = -TARGET_EFAULT;
9328 break;
9329 }
9330 }
9331 p = lock_user_string(arg1);
9332 if (p) {
9333 if (num == TARGET_NR_listxattr) {
9334 ret = get_errno(listxattr(p, b, arg3));
9335 } else {
9336 ret = get_errno(llistxattr(p, b, arg3));
9337 }
9338 } else {
9339 ret = -TARGET_EFAULT;
9340 }
9341 unlock_user(p, arg1, 0);
9342 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03009343 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00009344 }
9345 case TARGET_NR_flistxattr:
9346 {
9347 void *b = 0;
9348 if (arg2) {
9349 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9350 if (!b) {
9351 ret = -TARGET_EFAULT;
9352 break;
9353 }
9354 }
9355 ret = get_errno(flistxattr(arg1, b, arg3));
9356 unlock_user(b, arg2, arg3);
9357 break;
9358 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009359 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009360 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009361 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009362 void *p, *n, *v = 0;
9363 if (arg3) {
9364 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9365 if (!v) {
9366 ret = -TARGET_EFAULT;
9367 break;
9368 }
9369 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009370 p = lock_user_string(arg1);
9371 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009372 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009373 if (num == TARGET_NR_setxattr) {
9374 ret = get_errno(setxattr(p, n, v, arg4, arg5));
9375 } else {
9376 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
9377 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009378 } else {
9379 ret = -TARGET_EFAULT;
9380 }
9381 unlock_user(p, arg1, 0);
9382 unlock_user(n, arg2, 0);
9383 unlock_user(v, arg3, 0);
9384 }
9385 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009386 case TARGET_NR_fsetxattr:
9387 {
9388 void *n, *v = 0;
9389 if (arg3) {
9390 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9391 if (!v) {
9392 ret = -TARGET_EFAULT;
9393 break;
9394 }
9395 }
9396 n = lock_user_string(arg2);
9397 if (n) {
9398 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
9399 } else {
9400 ret = -TARGET_EFAULT;
9401 }
9402 unlock_user(n, arg2, 0);
9403 unlock_user(v, arg3, 0);
9404 }
9405 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009406 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009407 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009408 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009409 void *p, *n, *v = 0;
9410 if (arg3) {
9411 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9412 if (!v) {
9413 ret = -TARGET_EFAULT;
9414 break;
9415 }
9416 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009417 p = lock_user_string(arg1);
9418 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009419 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009420 if (num == TARGET_NR_getxattr) {
9421 ret = get_errno(getxattr(p, n, v, arg4));
9422 } else {
9423 ret = get_errno(lgetxattr(p, n, v, arg4));
9424 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009425 } else {
9426 ret = -TARGET_EFAULT;
9427 }
9428 unlock_user(p, arg1, 0);
9429 unlock_user(n, arg2, 0);
9430 unlock_user(v, arg3, arg4);
9431 }
9432 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009433 case TARGET_NR_fgetxattr:
9434 {
9435 void *n, *v = 0;
9436 if (arg3) {
9437 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9438 if (!v) {
9439 ret = -TARGET_EFAULT;
9440 break;
9441 }
9442 }
9443 n = lock_user_string(arg2);
9444 if (n) {
9445 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9446 } else {
9447 ret = -TARGET_EFAULT;
9448 }
9449 unlock_user(n, arg2, 0);
9450 unlock_user(v, arg3, arg4);
9451 }
9452 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009453 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009454 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009455 {
9456 void *p, *n;
9457 p = lock_user_string(arg1);
9458 n = lock_user_string(arg2);
9459 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009460 if (num == TARGET_NR_removexattr) {
9461 ret = get_errno(removexattr(p, n));
9462 } else {
9463 ret = get_errno(lremovexattr(p, n));
9464 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009465 } else {
9466 ret = -TARGET_EFAULT;
9467 }
9468 unlock_user(p, arg1, 0);
9469 unlock_user(n, arg2, 0);
9470 }
9471 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009472 case TARGET_NR_fremovexattr:
9473 {
9474 void *n;
9475 n = lock_user_string(arg2);
9476 if (n) {
9477 ret = get_errno(fremovexattr(arg1, n));
9478 } else {
9479 ret = -TARGET_EFAULT;
9480 }
9481 unlock_user(n, arg2, 0);
9482 }
9483 break;
bellardebc05482003-09-30 21:08:41 +00009484#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009485#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009486#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009487 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009488#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009489 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009490 ret = 0;
9491 break;
edgar_iglef967792009-01-07 14:19:38 +00009492#elif defined(TARGET_CRIS)
9493 if (arg1 & 0xff)
9494 ret = -TARGET_EINVAL;
9495 else {
9496 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9497 ret = 0;
9498 }
9499 break;
bellard8d18e892007-11-14 15:18:40 +00009500#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9501 ret = do_set_thread_area(cpu_env, arg1);
9502 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009503#elif defined(TARGET_M68K)
9504 {
Andreas Färber0429a972013-08-26 18:14:44 +02009505 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009506 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009507 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009508 break;
9509 }
ths6f5b89a2007-03-02 20:48:00 +00009510#else
9511 goto unimplemented_nowarn;
9512#endif
9513#endif
9514#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009515 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009516#if defined(TARGET_I386) && defined(TARGET_ABI32)
9517 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009518 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009519#elif defined(TARGET_M68K)
9520 {
Andreas Färber0429a972013-08-26 18:14:44 +02009521 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009522 ret = ts->tp_value;
9523 break;
9524 }
bellard8d18e892007-11-14 15:18:40 +00009525#else
bellard5cd43932003-03-29 16:54:36 +00009526 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009527#endif
bellard8d18e892007-11-14 15:18:40 +00009528#endif
bellard48dc41e2006-06-21 18:15:50 +00009529#ifdef TARGET_NR_getdomainname
9530 case TARGET_NR_getdomainname:
9531 goto unimplemented_nowarn;
9532#endif
ths6f5b89a2007-03-02 20:48:00 +00009533
thsb5906f92007-03-19 13:32:45 +00009534#ifdef TARGET_NR_clock_gettime
9535 case TARGET_NR_clock_gettime:
9536 {
9537 struct timespec ts;
9538 ret = get_errno(clock_gettime(arg1, &ts));
9539 if (!is_error(ret)) {
9540 host_to_target_timespec(arg2, &ts);
9541 }
9542 break;
9543 }
9544#endif
9545#ifdef TARGET_NR_clock_getres
9546 case TARGET_NR_clock_getres:
9547 {
9548 struct timespec ts;
9549 ret = get_errno(clock_getres(arg1, &ts));
9550 if (!is_error(ret)) {
9551 host_to_target_timespec(arg2, &ts);
9552 }
9553 break;
9554 }
9555#endif
pbrook63d76512008-05-29 13:43:29 +00009556#ifdef TARGET_NR_clock_nanosleep
9557 case TARGET_NR_clock_nanosleep:
9558 {
9559 struct timespec ts;
9560 target_to_host_timespec(&ts, arg3);
9561 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9562 if (arg4)
9563 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009564
9565#if defined(TARGET_PPC)
9566 /* clock_nanosleep is odd in that it returns positive errno values.
9567 * On PPC, CR0 bit 3 should be set in such a situation. */
9568 if (ret) {
9569 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9570 }
9571#endif
pbrook63d76512008-05-29 13:43:29 +00009572 break;
9573 }
9574#endif
thsb5906f92007-03-19 13:32:45 +00009575
ths6f5b89a2007-03-02 20:48:00 +00009576#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9577 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009578 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9579 break;
ths6f5b89a2007-03-02 20:48:00 +00009580#endif
9581
ths3ae43202007-09-16 21:39:48 +00009582#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009583 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009584 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009585 break;
9586#endif
9587
ths3ae43202007-09-16 21:39:48 +00009588#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009589 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009590 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9591 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009592 break;
9593#endif
9594
ths4f2b1fe2007-06-21 21:57:12 +00009595#ifdef TARGET_NR_set_robust_list
9596 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009597 case TARGET_NR_get_robust_list:
9598 /* The ABI for supporting robust futexes has userspace pass
9599 * the kernel a pointer to a linked list which is updated by
9600 * userspace after the syscall; the list is walked by the kernel
9601 * when the thread exits. Since the linked list in QEMU guest
9602 * memory isn't a valid linked list for the host and we have
9603 * no way to reliably intercept the thread-death event, we can't
9604 * support these. Silently return ENOSYS so that guest userspace
9605 * falls back to a non-robust futex implementation (which should
9606 * be OK except in the corner case of the guest crashing while
9607 * holding a mutex that is shared with another process via
9608 * shared memory).
9609 */
9610 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009611#endif
9612
Peter Maydell1acae9f2013-07-02 14:04:12 +01009613#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009614 case TARGET_NR_utimensat:
9615 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009616 struct timespec *tsp, ts[2];
9617 if (!arg3) {
9618 tsp = NULL;
9619 } else {
9620 target_to_host_timespec(ts, arg3);
9621 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9622 tsp = ts;
9623 }
ths9007f0e2007-09-25 17:50:37 +00009624 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009625 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009626 else {
bellard579a97f2007-11-11 14:26:47 +00009627 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009628 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009629 goto fail;
9630 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009631 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009632 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009633 }
9634 }
9635 break;
9636#endif
pbrookbd0c5662008-05-29 14:34:11 +00009637 case TARGET_NR_futex:
9638 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9639 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009640#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009641 case TARGET_NR_inotify_init:
9642 ret = get_errno(sys_inotify_init());
9643 break;
9644#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009645#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009646#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9647 case TARGET_NR_inotify_init1:
9648 ret = get_errno(sys_inotify_init1(arg1));
9649 break;
9650#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009651#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009652#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009653 case TARGET_NR_inotify_add_watch:
9654 p = lock_user_string(arg2);
9655 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9656 unlock_user(p, arg2, 0);
9657 break;
9658#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009659#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009660 case TARGET_NR_inotify_rm_watch:
9661 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9662 break;
9663#endif
ths9007f0e2007-09-25 17:50:37 +00009664
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009665#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009666 case TARGET_NR_mq_open:
9667 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009668 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009669
9670 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009671 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009672 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009673 attrp = &posix_mq_attr;
9674 } else {
9675 attrp = 0;
9676 }
9677 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009678 unlock_user (p, arg1, 0);
9679 }
9680 break;
9681
9682 case TARGET_NR_mq_unlink:
9683 p = lock_user_string(arg1 - 1);
9684 ret = get_errno(mq_unlink(p));
9685 unlock_user (p, arg1, 0);
9686 break;
9687
9688 case TARGET_NR_mq_timedsend:
9689 {
9690 struct timespec ts;
9691
9692 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9693 if (arg5 != 0) {
9694 target_to_host_timespec(&ts, arg5);
9695 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9696 host_to_target_timespec(arg5, &ts);
9697 }
9698 else
9699 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9700 unlock_user (p, arg2, arg3);
9701 }
9702 break;
9703
9704 case TARGET_NR_mq_timedreceive:
9705 {
9706 struct timespec ts;
9707 unsigned int prio;
9708
9709 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9710 if (arg5 != 0) {
9711 target_to_host_timespec(&ts, arg5);
9712 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9713 host_to_target_timespec(arg5, &ts);
9714 }
9715 else
9716 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9717 unlock_user (p, arg2, arg3);
9718 if (arg4 != 0)
9719 put_user_u32(prio, arg4);
9720 }
9721 break;
9722
9723 /* Not implemented for now... */
9724/* case TARGET_NR_mq_notify: */
9725/* break; */
9726
9727 case TARGET_NR_mq_getsetattr:
9728 {
9729 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9730 ret = 0;
9731 if (arg3 != 0) {
9732 ret = mq_getattr(arg1, &posix_mq_attr_out);
9733 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9734 }
9735 if (arg2 != 0) {
9736 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9737 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9738 }
9739
9740 }
9741 break;
9742#endif
9743
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309744#ifdef CONFIG_SPLICE
9745#ifdef TARGET_NR_tee
9746 case TARGET_NR_tee:
9747 {
9748 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9749 }
9750 break;
9751#endif
9752#ifdef TARGET_NR_splice
9753 case TARGET_NR_splice:
9754 {
9755 loff_t loff_in, loff_out;
9756 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +01009757 if (arg2) {
9758 if (get_user_u64(loff_in, arg2)) {
9759 goto efault;
9760 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309761 ploff_in = &loff_in;
9762 }
Andreas Schwab17644b32015-03-10 17:11:35 +01009763 if (arg4) {
9764 if (get_user_u64(loff_out, arg4)) {
9765 goto efault;
9766 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309767 ploff_out = &loff_out;
9768 }
9769 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +01009770 if (arg2) {
9771 if (put_user_u64(loff_in, arg2)) {
9772 goto efault;
9773 }
9774 }
9775 if (arg4) {
9776 if (put_user_u64(loff_out, arg4)) {
9777 goto efault;
9778 }
9779 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309780 }
9781 break;
9782#endif
9783#ifdef TARGET_NR_vmsplice
9784 case TARGET_NR_vmsplice:
9785 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009786 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9787 if (vec != NULL) {
9788 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9789 unlock_iovec(vec, arg2, arg3, 0);
9790 } else {
9791 ret = -host_to_target_errno(errno);
9792 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309793 }
9794 break;
9795#endif
9796#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009797#ifdef CONFIG_EVENTFD
9798#if defined(TARGET_NR_eventfd)
9799 case TARGET_NR_eventfd:
9800 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +02009801 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009802 break;
9803#endif
9804#if defined(TARGET_NR_eventfd2)
9805 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009806 {
9807 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9808 if (arg2 & TARGET_O_NONBLOCK) {
9809 host_flags |= O_NONBLOCK;
9810 }
9811 if (arg2 & TARGET_O_CLOEXEC) {
9812 host_flags |= O_CLOEXEC;
9813 }
9814 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02009815 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009816 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009817 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009818#endif
9819#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009820#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9821 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009822#if TARGET_ABI_BITS == 32
9823 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9824 target_offset64(arg5, arg6)));
9825#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009826 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009827#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009828 break;
9829#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009830#if defined(CONFIG_SYNC_FILE_RANGE)
9831#if defined(TARGET_NR_sync_file_range)
9832 case TARGET_NR_sync_file_range:
9833#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009834#if defined(TARGET_MIPS)
9835 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9836 target_offset64(arg5, arg6), arg7));
9837#else
Peter Maydellc727f472011-01-06 11:05:10 +00009838 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9839 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009840#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009841#else
9842 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9843#endif
9844 break;
9845#endif
9846#if defined(TARGET_NR_sync_file_range2)
9847 case TARGET_NR_sync_file_range2:
9848 /* This is like sync_file_range but the arguments are reordered */
9849#if TARGET_ABI_BITS == 32
9850 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9851 target_offset64(arg5, arg6), arg2));
9852#else
9853 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9854#endif
9855 break;
9856#endif
9857#endif
Laurent Viviere36800c2015-10-02 14:48:09 +02009858#if defined(TARGET_NR_signalfd4)
9859 case TARGET_NR_signalfd4:
9860 ret = do_signalfd4(arg1, arg2, arg4);
9861 break;
9862#endif
9863#if defined(TARGET_NR_signalfd)
9864 case TARGET_NR_signalfd:
9865 ret = do_signalfd4(arg1, arg2, 0);
9866 break;
9867#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009868#if defined(CONFIG_EPOLL)
9869#if defined(TARGET_NR_epoll_create)
9870 case TARGET_NR_epoll_create:
9871 ret = get_errno(epoll_create(arg1));
9872 break;
9873#endif
9874#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9875 case TARGET_NR_epoll_create1:
9876 ret = get_errno(epoll_create1(arg1));
9877 break;
9878#endif
9879#if defined(TARGET_NR_epoll_ctl)
9880 case TARGET_NR_epoll_ctl:
9881 {
9882 struct epoll_event ep;
9883 struct epoll_event *epp = 0;
9884 if (arg4) {
9885 struct target_epoll_event *target_ep;
9886 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9887 goto efault;
9888 }
9889 ep.events = tswap32(target_ep->events);
9890 /* The epoll_data_t union is just opaque data to the kernel,
9891 * so we transfer all 64 bits across and need not worry what
9892 * actual data type it is.
9893 */
9894 ep.data.u64 = tswap64(target_ep->data.u64);
9895 unlock_user_struct(target_ep, arg4, 0);
9896 epp = &ep;
9897 }
9898 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9899 break;
9900 }
9901#endif
9902
9903#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9904#define IMPLEMENT_EPOLL_PWAIT
9905#endif
9906#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9907#if defined(TARGET_NR_epoll_wait)
9908 case TARGET_NR_epoll_wait:
9909#endif
9910#if defined(IMPLEMENT_EPOLL_PWAIT)
9911 case TARGET_NR_epoll_pwait:
9912#endif
9913 {
9914 struct target_epoll_event *target_ep;
9915 struct epoll_event *ep;
9916 int epfd = arg1;
9917 int maxevents = arg3;
9918 int timeout = arg4;
9919
9920 target_ep = lock_user(VERIFY_WRITE, arg2,
9921 maxevents * sizeof(struct target_epoll_event), 1);
9922 if (!target_ep) {
9923 goto efault;
9924 }
9925
9926 ep = alloca(maxevents * sizeof(struct epoll_event));
9927
9928 switch (num) {
9929#if defined(IMPLEMENT_EPOLL_PWAIT)
9930 case TARGET_NR_epoll_pwait:
9931 {
9932 target_sigset_t *target_set;
9933 sigset_t _set, *set = &_set;
9934
9935 if (arg5) {
9936 target_set = lock_user(VERIFY_READ, arg5,
9937 sizeof(target_sigset_t), 1);
9938 if (!target_set) {
9939 unlock_user(target_ep, arg2, 0);
9940 goto efault;
9941 }
9942 target_to_host_sigset(set, target_set);
9943 unlock_user(target_set, arg5, 0);
9944 } else {
9945 set = NULL;
9946 }
9947
9948 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9949 break;
9950 }
9951#endif
9952#if defined(TARGET_NR_epoll_wait)
9953 case TARGET_NR_epoll_wait:
9954 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9955 break;
9956#endif
9957 default:
9958 ret = -TARGET_ENOSYS;
9959 }
9960 if (!is_error(ret)) {
9961 int i;
9962 for (i = 0; i < ret; i++) {
9963 target_ep[i].events = tswap32(ep[i].events);
9964 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9965 }
9966 }
9967 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9968 break;
9969 }
9970#endif
9971#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009972#ifdef TARGET_NR_prlimit64
9973 case TARGET_NR_prlimit64:
9974 {
9975 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9976 struct target_rlimit64 *target_rnew, *target_rold;
9977 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +01009978 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +01009979 if (arg3) {
9980 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9981 goto efault;
9982 }
9983 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9984 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9985 unlock_user_struct(target_rnew, arg3, 0);
9986 rnewp = &rnew;
9987 }
9988
Felix Janda95018012014-12-02 22:11:17 +01009989 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +01009990 if (!is_error(ret) && arg4) {
9991 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9992 goto efault;
9993 }
9994 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9995 target_rold->rlim_max = tswap64(rold.rlim_max);
9996 unlock_user_struct(target_rold, arg4, 1);
9997 }
9998 break;
9999 }
10000#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010001#ifdef TARGET_NR_gethostname
10002 case TARGET_NR_gethostname:
10003 {
10004 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10005 if (name) {
10006 ret = get_errno(gethostname(name, arg2));
10007 unlock_user(name, arg1, arg2);
10008 } else {
10009 ret = -TARGET_EFAULT;
10010 }
10011 break;
10012 }
10013#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010014#ifdef TARGET_NR_atomic_cmpxchg_32
10015 case TARGET_NR_atomic_cmpxchg_32:
10016 {
10017 /* should use start_exclusive from main.c */
10018 abi_ulong mem_value;
10019 if (get_user_u32(mem_value, arg6)) {
10020 target_siginfo_t info;
10021 info.si_signo = SIGSEGV;
10022 info.si_errno = 0;
10023 info.si_code = TARGET_SEGV_MAPERR;
10024 info._sifields._sigfault._addr = arg6;
10025 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10026 ret = 0xdeadbeef;
10027
10028 }
10029 if (mem_value == arg2)
10030 put_user_u32(arg1, arg6);
10031 ret = mem_value;
10032 break;
10033 }
10034#endif
10035#ifdef TARGET_NR_atomic_barrier
10036 case TARGET_NR_atomic_barrier:
10037 {
10038 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010039 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010040 break;
10041 }
10042#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010043
10044#ifdef TARGET_NR_timer_create
10045 case TARGET_NR_timer_create:
10046 {
10047 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10048
10049 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010050
10051 int clkid = arg1;
10052 int timer_index = next_free_host_timer();
10053
10054 if (timer_index < 0) {
10055 ret = -TARGET_EAGAIN;
10056 } else {
10057 timer_t *phtimer = g_posix_timers + timer_index;
10058
10059 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010060 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010061 ret = target_to_host_sigevent(phost_sevp, arg2);
10062 if (ret != 0) {
10063 break;
10064 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010065 }
10066
10067 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10068 if (ret) {
10069 phtimer = NULL;
10070 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010071 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010072 goto efault;
10073 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010074 }
10075 }
10076 break;
10077 }
10078#endif
10079
10080#ifdef TARGET_NR_timer_settime
10081 case TARGET_NR_timer_settime:
10082 {
10083 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
10084 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010085 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010086
Alexander Grafaecc8862014-11-10 21:33:03 +010010087 if (timerid < 0) {
10088 ret = timerid;
10089 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010090 ret = -TARGET_EINVAL;
10091 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010092 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010093 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
10094
10095 target_to_host_itimerspec(&hspec_new, arg3);
10096 ret = get_errno(
10097 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
10098 host_to_target_itimerspec(arg2, &hspec_old);
10099 }
10100 break;
10101 }
10102#endif
10103
10104#ifdef TARGET_NR_timer_gettime
10105 case TARGET_NR_timer_gettime:
10106 {
10107 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010108 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010109
Alexander Grafaecc8862014-11-10 21:33:03 +010010110 if (timerid < 0) {
10111 ret = timerid;
10112 } else if (!arg2) {
10113 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010114 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010115 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010116 struct itimerspec hspec;
10117 ret = get_errno(timer_gettime(htimer, &hspec));
10118
10119 if (host_to_target_itimerspec(arg2, &hspec)) {
10120 ret = -TARGET_EFAULT;
10121 }
10122 }
10123 break;
10124 }
10125#endif
10126
10127#ifdef TARGET_NR_timer_getoverrun
10128 case TARGET_NR_timer_getoverrun:
10129 {
10130 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010131 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010132
Alexander Grafaecc8862014-11-10 21:33:03 +010010133 if (timerid < 0) {
10134 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010135 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010136 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010137 ret = get_errno(timer_getoverrun(htimer));
10138 }
Laurent Viviere36800c2015-10-02 14:48:09 +020010139 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010140 break;
10141 }
10142#endif
10143
10144#ifdef TARGET_NR_timer_delete
10145 case TARGET_NR_timer_delete:
10146 {
10147 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010148 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010149
Alexander Grafaecc8862014-11-10 21:33:03 +010010150 if (timerid < 0) {
10151 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010152 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010153 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010154 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020010155 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010156 }
10157 break;
10158 }
10159#endif
10160
Riku Voipio51834342014-06-22 11:25:42 +010010161#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
10162 case TARGET_NR_timerfd_create:
10163 ret = get_errno(timerfd_create(arg1,
10164 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
10165 break;
10166#endif
10167
10168#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
10169 case TARGET_NR_timerfd_gettime:
10170 {
10171 struct itimerspec its_curr;
10172
10173 ret = get_errno(timerfd_gettime(arg1, &its_curr));
10174
10175 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
10176 goto efault;
10177 }
10178 }
10179 break;
10180#endif
10181
10182#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
10183 case TARGET_NR_timerfd_settime:
10184 {
10185 struct itimerspec its_new, its_old, *p_new;
10186
10187 if (arg3) {
10188 if (target_to_host_itimerspec(&its_new, arg3)) {
10189 goto efault;
10190 }
10191 p_new = &its_new;
10192 } else {
10193 p_new = NULL;
10194 }
10195
10196 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
10197
10198 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
10199 goto efault;
10200 }
10201 }
10202 break;
10203#endif
10204
Paul Burtonab31cda2014-06-22 11:25:43 +010010205#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
10206 case TARGET_NR_ioprio_get:
10207 ret = get_errno(ioprio_get(arg1, arg2));
10208 break;
10209#endif
10210
10211#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
10212 case TARGET_NR_ioprio_set:
10213 ret = get_errno(ioprio_set(arg1, arg2, arg3));
10214 break;
10215#endif
10216
Riku Voipio9af5c902014-08-12 15:58:57 +030010217#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
10218 case TARGET_NR_setns:
10219 ret = get_errno(setns(arg1, arg2));
10220 break;
10221#endif
10222#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
10223 case TARGET_NR_unshare:
10224 ret = get_errno(unshare(arg1));
10225 break;
10226#endif
10227
bellard31e31b82003-02-18 22:55:36 +000010228 default:
10229 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000010230 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000010231#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 +000010232 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000010233#endif
ths0da46a62007-10-20 20:23:07 +000010234 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000010235 break;
10236 }
bellard579a97f2007-11-11 14:26:47 +000010237fail:
bellardc573ff62004-01-04 15:51:36 +000010238#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000010239 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000010240#endif
thsb92c47c2007-11-01 00:07:38 +000010241 if(do_strace)
10242 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000010243 return ret;
bellard579a97f2007-11-11 14:26:47 +000010244efault:
10245 ret = -TARGET_EFAULT;
10246 goto fail;
bellard31e31b82003-02-18 22:55:36 +000010247}