blob: 5c0d111770c0d72f6fbe13a6dd3dd187ab512825 [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"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020021#include "qemu/cutils.h"
22#include "qemu/path.h"
bellard31e31b82003-02-18 22:55:36 +000023#include <elf.h>
24#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010025#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000026#include <sys/ipc.h>
27#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000029#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010030#include <sys/file.h>
31#include <sys/fsuid.h>
32#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000033#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000036#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000037#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020038#ifdef __ia64__
39int __clone2(int (*fn)(void *), void *child_stack_base,
40 size_t stack_size, int flags, void *arg, ...);
41#endif
bellard31e31b82003-02-18 22:55:36 +000042#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000043#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000044#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000045#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000046#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000047#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000048#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000049#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000050#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000051#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020052#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000053//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000054#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000055#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020056#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000057#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020058#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030059#ifdef CONFIG_TIMERFD
60#include <sys/timerfd.h>
61#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020062#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000063#include <sys/gmon.h>
64#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030065#ifdef CONFIG_EVENTFD
66#include <sys/eventfd.h>
67#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000068#ifdef CONFIG_EPOLL
69#include <sys/epoll.h>
70#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070071#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010072#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000074#ifdef CONFIG_SENDFILE
75#include <sys/sendfile.h>
76#endif
bellard31e31b82003-02-18 22:55:36 +000077
78#define termios host_termios
79#define winsize host_winsize
80#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000081#define sgttyb host_sgttyb /* same as target */
82#define tchars host_tchars /* same as target */
83#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000084
85#include <linux/termios.h>
86#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000087#include <linux/cdrom.h>
88#include <linux/hdreg.h>
89#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000090#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000091#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030092#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000093#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000094#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020096#include <linux/fb.h>
97#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010098#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +000099#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100100#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200101#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100102#include <linux/blkpg.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200103#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200104#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200105#include <linux/rtnetlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200106#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200107#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000108#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200109#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000110
bellard3ef693a2003-03-23 20:17:16 +0000111#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000112
pbrookd865bab2008-06-07 22:12:17 +0000113#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
114 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000115
bellard72f03902003-02-18 23:33:18 +0000116//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100117/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
118 * once. This exercises the codepaths for restart.
119 */
120//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000121
bellard1a9353d2003-03-16 20:28:50 +0000122//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000123#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
124#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000125
Peter Maydellb28a1f32016-05-27 15:51:47 +0100126/* This is the size of the host kernel's sigset_t, needed where we make
127 * direct system calls that take a sigset_t pointer and a size.
128 */
129#define SIGSET_T_SIZE (_NSIG / 8)
bellard70a194b2003-08-11 22:20:16 +0000130
bellard70a194b2003-08-11 22:20:16 +0000131#undef _syscall0
132#undef _syscall1
133#undef _syscall2
134#undef _syscall3
135#undef _syscall4
136#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000137#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000138
bellard83fcb512006-06-14 13:37:16 +0000139#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000140static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000141{ \
142 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000143}
144
bellard83fcb512006-06-14 13:37:16 +0000145#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000146static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000147{ \
148 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000149}
150
bellard83fcb512006-06-14 13:37:16 +0000151#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000152static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000153{ \
154 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000155}
156
bellard83fcb512006-06-14 13:37:16 +0000157#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000158static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000159{ \
160 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000161}
162
bellard83fcb512006-06-14 13:37:16 +0000163#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000164static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000165{ \
166 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000167}
168
bellard83fcb512006-06-14 13:37:16 +0000169#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
170 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000171static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000172{ \
173 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000174}
bellard83fcb512006-06-14 13:37:16 +0000175
176
177#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
178 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000179static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
180 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000181{ \
182 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
183}
184
bellard70a194b2003-08-11 22:20:16 +0000185
bellard31e31b82003-02-18 22:55:36 +0000186#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000187#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000188#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000189#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000190#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000191#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000192#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000193#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000194#define __NR_sys_inotify_init __NR_inotify_init
195#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
196#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000197
Alexander Graf42a39fb2011-04-15 17:32:45 +0200198#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
199 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000200#define __NR__llseek __NR_lseek
201#endif
202
James Hogana29e5ba2014-03-25 21:51:08 +0000203/* Newer kernel ports have llseek() instead of _llseek() */
204#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
205#define TARGET_NR__llseek TARGET_NR_llseek
206#endif
207
bellard72f03902003-02-18 23:33:18 +0000208#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000209_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000210#else
ths0da46a62007-10-20 20:23:07 +0000211/* This is a replacement for the host gettid() and must return a host
212 errno. */
bellard72f03902003-02-18 23:33:18 +0000213static int gettid(void) {
214 return -ENOSYS;
215}
216#endif
Chen Gang704eff62015-08-21 05:37:33 +0800217#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100219#endif
220#if !defined(__NR_getdents) || \
221 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000222_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
223#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700224#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000225_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
226 loff_t *, res, uint, wh);
227#endif
228_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
229_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000230#ifdef __NR_exit_group
231_syscall1(int,exit_group,int,error_code)
232#endif
233#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
234_syscall1(int,set_tid_address,int *,tidptr)
235#endif
aurel323b3f24a2009-04-15 16:12:13 +0000236#if defined(TARGET_NR_futex) && defined(__NR_futex)
237_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
238 const struct timespec *,timeout,int *,uaddr2,int,val3)
239#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500240#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
241_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
242 unsigned long *, user_mask_ptr);
243#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
244_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
245 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200246_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
247 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000248_syscall2(int, capget, struct __user_cap_header_struct *, header,
249 struct __user_cap_data_struct *, data);
250_syscall2(int, capset, struct __user_cap_header_struct *, header,
251 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100252#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
253_syscall2(int, ioprio_get, int, which, int, who)
254#endif
255#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
256_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
257#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100258#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
259_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
260#endif
aurel323b3f24a2009-04-15 16:12:13 +0000261
262static bitmask_transtbl fcntl_flags_tbl[] = {
263 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
264 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
265 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
266 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
267 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
268 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
269 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
270 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700271 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000272 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
273 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
274 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
275 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000276#if defined(O_DIRECT)
277 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
278#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700279#if defined(O_NOATIME)
280 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
281#endif
282#if defined(O_CLOEXEC)
283 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
284#endif
285#if defined(O_PATH)
286 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
287#endif
288 /* Don't terminate the list prematurely on 64-bit host+guest. */
289#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
290 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
291#endif
aurel323b3f24a2009-04-15 16:12:13 +0000292 { 0, 0, 0, 0 }
293};
294
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100295typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100296typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200297typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100298 TargetFdDataFunc host_to_target_data;
299 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100300 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200301} TargetFdTrans;
302
303static TargetFdTrans **target_fd_trans;
304
305static unsigned int target_fd_max;
306
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200307static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
308{
309 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
310 return target_fd_trans[fd]->target_to_host_data;
311 }
312 return NULL;
313}
314
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100315static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200316{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100317 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100318 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200319 }
320 return NULL;
321}
322
Laurent Vivier7b36f782015-10-28 21:40:44 +0100323static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
324{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100325 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100326 return target_fd_trans[fd]->target_to_host_addr;
327 }
328 return NULL;
329}
330
Laurent Viviere36800c2015-10-02 14:48:09 +0200331static void fd_trans_register(int fd, TargetFdTrans *trans)
332{
333 unsigned int oldmax;
334
335 if (fd >= target_fd_max) {
336 oldmax = target_fd_max;
337 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100338 target_fd_trans = g_renew(TargetFdTrans *,
339 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200340 memset((void *)(target_fd_trans + oldmax), 0,
341 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
342 }
343 target_fd_trans[fd] = trans;
344}
345
346static void fd_trans_unregister(int fd)
347{
348 if (fd >= 0 && fd < target_fd_max) {
349 target_fd_trans[fd] = NULL;
350 }
351}
352
353static void fd_trans_dup(int oldfd, int newfd)
354{
355 fd_trans_unregister(newfd);
356 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
357 fd_trans_register(newfd, target_fd_trans[oldfd]);
358 }
359}
360
aurel323b3f24a2009-04-15 16:12:13 +0000361static int sys_getcwd1(char *buf, size_t size)
362{
363 if (getcwd(buf, size) == NULL) {
364 /* getcwd() sets errno */
365 return (-1);
366 }
aurel32aaf4ad32009-04-16 14:17:14 +0000367 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000368}
369
Peter Maydell1acae9f2013-07-02 14:04:12 +0100370#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300371#ifdef CONFIG_UTIMENSAT
372static int sys_utimensat(int dirfd, const char *pathname,
373 const struct timespec times[2], int flags)
374{
375 if (pathname == NULL)
376 return futimens(dirfd, times);
377 else
378 return utimensat(dirfd, pathname, times, flags);
379}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100380#elif defined(__NR_utimensat)
381#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000382_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
383 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100384#else
385static int sys_utimensat(int dirfd, const char *pathname,
386 const struct timespec times[2], int flags)
387{
388 errno = ENOSYS;
389 return -1;
390}
ths9007f0e2007-09-25 17:50:37 +0000391#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100392#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000393
394#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000395#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000396
aurel3239b59762008-10-01 21:46:50 +0000397#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000398static int sys_inotify_init(void)
399{
400 return (inotify_init());
401}
aurel3239b59762008-10-01 21:46:50 +0000402#endif
403#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000404static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
405{
406 return (inotify_add_watch(fd, pathname, mask));
407}
aurel3239b59762008-10-01 21:46:50 +0000408#endif
409#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000410static int sys_inotify_rm_watch(int fd, int32_t wd)
411{
aurel328690e422009-04-17 13:50:32 +0000412 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000413}
aurel3239b59762008-10-01 21:46:50 +0000414#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000415#ifdef CONFIG_INOTIFY1
416#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
417static int sys_inotify_init1(int flags)
418{
419 return (inotify_init1(flags));
420}
421#endif
422#endif
aurel323b3f24a2009-04-15 16:12:13 +0000423#else
424/* Userspace can usually survive runtime without inotify */
425#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000426#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000427#undef TARGET_NR_inotify_add_watch
428#undef TARGET_NR_inotify_rm_watch
429#endif /* CONFIG_INOTIFY */
430
Peter Maydell163a05a2011-06-27 17:44:52 +0100431#if defined(TARGET_NR_prlimit64)
432#ifndef __NR_prlimit64
433# define __NR_prlimit64 -1
434#endif
435#define __NR_sys_prlimit64 __NR_prlimit64
436/* The glibc rlimit structure may not be that used by the underlying syscall */
437struct host_rlimit64 {
438 uint64_t rlim_cur;
439 uint64_t rlim_max;
440};
441_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
442 const struct host_rlimit64 *, new_limit,
443 struct host_rlimit64 *, old_limit)
444#endif
445
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100446
447#if defined(TARGET_NR_timer_create)
448/* Maxiumum of 32 active POSIX timers allowed at any one time. */
449static timer_t g_posix_timers[32] = { 0, } ;
450
451static inline int next_free_host_timer(void)
452{
453 int k ;
454 /* FIXME: Does finding the next free slot require a lock? */
455 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
456 if (g_posix_timers[k] == 0) {
457 g_posix_timers[k] = (timer_t) 1;
458 return k;
459 }
460 }
461 return -1;
462}
463#endif
464
Riku Voipio48e515d2011-07-12 15:40:51 +0300465/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000466#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300467static inline int regpairs_aligned(void *cpu_env) {
468 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
469}
470#elif defined(TARGET_MIPS)
471static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000472#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
473/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
474 * of registers which translates to the same as ARM/MIPS, because we start with
475 * r3 as arg1 */
476static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300477#else
478static inline int regpairs_aligned(void *cpu_env) { return 0; }
479#endif
480
thsb92c47c2007-11-01 00:07:38 +0000481#define ERRNO_TABLE_SIZE 1200
482
483/* target_to_host_errno_table[] is initialized from
484 * host_to_target_errno_table[] in syscall_init(). */
485static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
486};
487
ths637947f2007-06-01 12:09:19 +0000488/*
thsfe8f0962007-07-12 10:59:21 +0000489 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000490 * minus the errnos that are not actually generic to all archs.
491 */
thsb92c47c2007-11-01 00:07:38 +0000492static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800493 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000494 [EIDRM] = TARGET_EIDRM,
495 [ECHRNG] = TARGET_ECHRNG,
496 [EL2NSYNC] = TARGET_EL2NSYNC,
497 [EL3HLT] = TARGET_EL3HLT,
498 [EL3RST] = TARGET_EL3RST,
499 [ELNRNG] = TARGET_ELNRNG,
500 [EUNATCH] = TARGET_EUNATCH,
501 [ENOCSI] = TARGET_ENOCSI,
502 [EL2HLT] = TARGET_EL2HLT,
503 [EDEADLK] = TARGET_EDEADLK,
504 [ENOLCK] = TARGET_ENOLCK,
505 [EBADE] = TARGET_EBADE,
506 [EBADR] = TARGET_EBADR,
507 [EXFULL] = TARGET_EXFULL,
508 [ENOANO] = TARGET_ENOANO,
509 [EBADRQC] = TARGET_EBADRQC,
510 [EBADSLT] = TARGET_EBADSLT,
511 [EBFONT] = TARGET_EBFONT,
512 [ENOSTR] = TARGET_ENOSTR,
513 [ENODATA] = TARGET_ENODATA,
514 [ETIME] = TARGET_ETIME,
515 [ENOSR] = TARGET_ENOSR,
516 [ENONET] = TARGET_ENONET,
517 [ENOPKG] = TARGET_ENOPKG,
518 [EREMOTE] = TARGET_EREMOTE,
519 [ENOLINK] = TARGET_ENOLINK,
520 [EADV] = TARGET_EADV,
521 [ESRMNT] = TARGET_ESRMNT,
522 [ECOMM] = TARGET_ECOMM,
523 [EPROTO] = TARGET_EPROTO,
524 [EDOTDOT] = TARGET_EDOTDOT,
525 [EMULTIHOP] = TARGET_EMULTIHOP,
526 [EBADMSG] = TARGET_EBADMSG,
527 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
528 [EOVERFLOW] = TARGET_EOVERFLOW,
529 [ENOTUNIQ] = TARGET_ENOTUNIQ,
530 [EBADFD] = TARGET_EBADFD,
531 [EREMCHG] = TARGET_EREMCHG,
532 [ELIBACC] = TARGET_ELIBACC,
533 [ELIBBAD] = TARGET_ELIBBAD,
534 [ELIBSCN] = TARGET_ELIBSCN,
535 [ELIBMAX] = TARGET_ELIBMAX,
536 [ELIBEXEC] = TARGET_ELIBEXEC,
537 [EILSEQ] = TARGET_EILSEQ,
538 [ENOSYS] = TARGET_ENOSYS,
539 [ELOOP] = TARGET_ELOOP,
540 [ERESTART] = TARGET_ERESTART,
541 [ESTRPIPE] = TARGET_ESTRPIPE,
542 [ENOTEMPTY] = TARGET_ENOTEMPTY,
543 [EUSERS] = TARGET_EUSERS,
544 [ENOTSOCK] = TARGET_ENOTSOCK,
545 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
546 [EMSGSIZE] = TARGET_EMSGSIZE,
547 [EPROTOTYPE] = TARGET_EPROTOTYPE,
548 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
549 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
550 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
551 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
552 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
553 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
554 [EADDRINUSE] = TARGET_EADDRINUSE,
555 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
556 [ENETDOWN] = TARGET_ENETDOWN,
557 [ENETUNREACH] = TARGET_ENETUNREACH,
558 [ENETRESET] = TARGET_ENETRESET,
559 [ECONNABORTED] = TARGET_ECONNABORTED,
560 [ECONNRESET] = TARGET_ECONNRESET,
561 [ENOBUFS] = TARGET_ENOBUFS,
562 [EISCONN] = TARGET_EISCONN,
563 [ENOTCONN] = TARGET_ENOTCONN,
564 [EUCLEAN] = TARGET_EUCLEAN,
565 [ENOTNAM] = TARGET_ENOTNAM,
566 [ENAVAIL] = TARGET_ENAVAIL,
567 [EISNAM] = TARGET_EISNAM,
568 [EREMOTEIO] = TARGET_EREMOTEIO,
569 [ESHUTDOWN] = TARGET_ESHUTDOWN,
570 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
571 [ETIMEDOUT] = TARGET_ETIMEDOUT,
572 [ECONNREFUSED] = TARGET_ECONNREFUSED,
573 [EHOSTDOWN] = TARGET_EHOSTDOWN,
574 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
575 [EALREADY] = TARGET_EALREADY,
576 [EINPROGRESS] = TARGET_EINPROGRESS,
577 [ESTALE] = TARGET_ESTALE,
578 [ECANCELED] = TARGET_ECANCELED,
579 [ENOMEDIUM] = TARGET_ENOMEDIUM,
580 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000581#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000582 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000583#endif
584#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000585 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000586#endif
587#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000588 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000589#endif
590#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000591 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000592#endif
593#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000594 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000595#endif
596#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000597 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000598#endif
thsb92c47c2007-11-01 00:07:38 +0000599};
ths637947f2007-06-01 12:09:19 +0000600
601static inline int host_to_target_errno(int err)
602{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100603 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
604 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000605 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100606 }
ths637947f2007-06-01 12:09:19 +0000607 return err;
608}
609
thsb92c47c2007-11-01 00:07:38 +0000610static inline int target_to_host_errno(int err)
611{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100612 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
613 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000614 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100615 }
thsb92c47c2007-11-01 00:07:38 +0000616 return err;
617}
618
blueswir1992f48a2007-10-14 16:27:31 +0000619static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000620{
621 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000622 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000623 else
624 return ret;
625}
626
blueswir1992f48a2007-10-14 16:27:31 +0000627static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000628{
blueswir1992f48a2007-10-14 16:27:31 +0000629 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000630}
631
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100632const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000633{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100634 if (err == TARGET_ERESTARTSYS) {
635 return "To be restarted";
636 }
637 if (err == TARGET_QEMU_ESIGRETURN) {
638 return "Successful exit from sigreturn";
639 }
640
Alexander Graf962b2892011-11-21 12:04:07 +0100641 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
642 return NULL;
643 }
thsb92c47c2007-11-01 00:07:38 +0000644 return strerror(target_to_host_errno(err));
645}
646
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100647#define safe_syscall0(type, name) \
648static type safe_##name(void) \
649{ \
650 return safe_syscall(__NR_##name); \
651}
652
653#define safe_syscall1(type, name, type1, arg1) \
654static type safe_##name(type1 arg1) \
655{ \
656 return safe_syscall(__NR_##name, arg1); \
657}
658
659#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
660static type safe_##name(type1 arg1, type2 arg2) \
661{ \
662 return safe_syscall(__NR_##name, arg1, arg2); \
663}
664
665#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
666static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
667{ \
668 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
669}
670
671#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
672 type4, arg4) \
673static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
674{ \
675 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
676}
677
678#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
679 type4, arg4, type5, arg5) \
680static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
681 type5 arg5) \
682{ \
683 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
684}
685
686#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
687 type4, arg4, type5, arg5, type6, arg6) \
688static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
689 type5 arg5, type6 arg6) \
690{ \
691 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
692}
693
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100694safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
695safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100696safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
697 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100698safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
699 struct rusage *, rusage)
700safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
701 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100702safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100703safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
704 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100705safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
706 struct timespec *, tsp, const sigset_t *, sigmask,
707 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100708safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
709 int, maxevents, int, timeout, const sigset_t *, sigmask,
710 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100711safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
712 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100713safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100714safe_syscall2(int, kill, pid_t, pid, int, sig)
715safe_syscall2(int, tkill, int, tid, int, sig)
716safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100717safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
718safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100719safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
720 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100721safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
722 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
723safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
724 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
725safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
726safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100727safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100728safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
729 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100730safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
731 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100732safe_syscall2(int, nanosleep, const struct timespec *, req,
733 struct timespec *, rem)
734#ifdef TARGET_NR_clock_nanosleep
735safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
736 const struct timespec *, req, struct timespec *, rem)
737#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100738#ifdef __NR_msgsnd
739safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
740 int, flags)
741safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
742 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100743safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
744 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100745#else
746/* This host kernel architecture uses a single ipc syscall; fake up
747 * wrappers for the sub-operations to hide this implementation detail.
748 * Annoyingly we can't include linux/ipc.h to get the constant definitions
749 * for the call parameter because some structs in there conflict with the
750 * sys/ipc.h ones. So we just define them here, and rely on them being
751 * the same for all host architectures.
752 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100753#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100754#define Q_MSGSND 11
755#define Q_MSGRCV 12
756#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
757
758safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
759 void *, ptr, long, fifth)
760static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
761{
762 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
763}
764static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
765{
766 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
767}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100768static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
769 const struct timespec *timeout)
770{
771 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
772 (long)timeout);
773}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100774#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100775#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
776safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
777 size_t, len, unsigned, prio, const struct timespec *, timeout)
778safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
779 size_t, len, unsigned *, prio, const struct timespec *, timeout)
780#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100781/* We do ioctl like this rather than via safe_syscall3 to preserve the
782 * "third argument might be integer or pointer or not present" behaviour of
783 * the libc function.
784 */
785#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100786
Paul Burton8289d112014-06-22 11:25:33 +0100787static inline int host_to_target_sock_type(int host_type)
788{
789 int target_type;
790
791 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
792 case SOCK_DGRAM:
793 target_type = TARGET_SOCK_DGRAM;
794 break;
795 case SOCK_STREAM:
796 target_type = TARGET_SOCK_STREAM;
797 break;
798 default:
799 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
800 break;
801 }
802
803#if defined(SOCK_CLOEXEC)
804 if (host_type & SOCK_CLOEXEC) {
805 target_type |= TARGET_SOCK_CLOEXEC;
806 }
807#endif
808
809#if defined(SOCK_NONBLOCK)
810 if (host_type & SOCK_NONBLOCK) {
811 target_type |= TARGET_SOCK_NONBLOCK;
812 }
813#endif
814
815 return target_type;
816}
817
blueswir1992f48a2007-10-14 16:27:31 +0000818static abi_ulong target_brk;
819static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000820static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000821
blueswir1992f48a2007-10-14 16:27:31 +0000822void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000823{
blueswir14c1de732007-07-07 20:45:44 +0000824 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000825 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000826}
827
vincent4d1de872011-06-14 21:56:33 +0000828//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
829#define DEBUGF_BRK(message, args...)
830
ths0da46a62007-10-20 20:23:07 +0000831/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000832abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000833{
blueswir1992f48a2007-10-14 16:27:31 +0000834 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000835 int new_alloc_size;
836
Paul Brook3a0c6c42012-02-09 19:04:27 +0000837 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000838
vincent4d1de872011-06-14 21:56:33 +0000839 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000840 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000841 return target_brk;
842 }
843 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000844 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
845 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000846 return target_brk;
847 }
bellard31e31b82003-02-18 22:55:36 +0000848
vincent4d1de872011-06-14 21:56:33 +0000849 /* If the new brk is less than the highest page reserved to the
850 * target heap allocation, set it and we're almost done... */
851 if (new_brk <= brk_page) {
852 /* Heap contents are initialized to zero, as for anonymous
853 * mapped pages. */
854 if (new_brk > target_brk) {
855 memset(g2h(target_brk), 0, new_brk - target_brk);
856 }
bellard31e31b82003-02-18 22:55:36 +0000857 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000858 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000859 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000860 }
861
Peter Maydell00faf082011-04-18 16:34:24 +0100862 /* We need to allocate more memory after the brk... Note that
863 * we don't use MAP_FIXED because that will map over the top of
864 * any existing mapping (like the one with the host libc or qemu
865 * itself); instead we treat "mapped but at wrong address" as
866 * a failure and unmap again.
867 */
vincent4d1de872011-06-14 21:56:33 +0000868 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000869 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000870 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100871 MAP_ANON|MAP_PRIVATE, 0, 0));
872
873 if (mapped_addr == brk_page) {
CĂ©dric VINCENT70afc342011-08-26 10:56:50 +0200874 /* Heap contents are initialized to zero, as for anonymous
875 * mapped pages. Technically the new pages are already
876 * initialized to zero since they *are* anonymous mapped
877 * pages, however we have to take care with the contents that
878 * come from the remaining part of the previous page: it may
879 * contains garbage data due to a previous heap usage (grown
880 * then shrunken). */
881 memset(g2h(target_brk), 0, brk_page - target_brk);
882
Peter Maydell00faf082011-04-18 16:34:24 +0100883 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000884 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000885 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
886 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100887 return target_brk;
888 } else if (mapped_addr != -1) {
889 /* Mapped but at wrong address, meaning there wasn't actually
890 * enough space for this brk.
891 */
892 target_munmap(mapped_addr, new_alloc_size);
893 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000894 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000895 }
896 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000897 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100898 }
balrog7ab240a2008-04-26 12:17:34 +0000899
Richard Henderson7dd46c02010-05-03 10:07:49 -0700900#if defined(TARGET_ALPHA)
901 /* We (partially) emulate OSF/1 on Alpha, which requires we
902 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100903 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700904#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100905 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000906 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000907}
908
ths26edcf42007-12-09 02:25:24 +0000909static inline abi_long copy_from_user_fdset(fd_set *fds,
910 abi_ulong target_fds_addr,
911 int n)
bellard31e31b82003-02-18 22:55:36 +0000912{
ths26edcf42007-12-09 02:25:24 +0000913 int i, nw, j, k;
914 abi_ulong b, *target_fds;
915
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200916 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000917 if (!(target_fds = lock_user(VERIFY_READ,
918 target_fds_addr,
919 sizeof(abi_ulong) * nw,
920 1)))
921 return -TARGET_EFAULT;
922
923 FD_ZERO(fds);
924 k = 0;
925 for (i = 0; i < nw; i++) {
926 /* grab the abi_ulong */
927 __get_user(b, &target_fds[i]);
928 for (j = 0; j < TARGET_ABI_BITS; j++) {
929 /* check the bit inside the abi_ulong */
930 if ((b >> j) & 1)
931 FD_SET(k, fds);
932 k++;
bellard31e31b82003-02-18 22:55:36 +0000933 }
bellard31e31b82003-02-18 22:55:36 +0000934 }
ths26edcf42007-12-09 02:25:24 +0000935
936 unlock_user(target_fds, target_fds_addr, 0);
937
938 return 0;
bellard31e31b82003-02-18 22:55:36 +0000939}
940
Mike Frysinger055e0902011-06-03 17:01:49 -0400941static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
942 abi_ulong target_fds_addr,
943 int n)
944{
945 if (target_fds_addr) {
946 if (copy_from_user_fdset(fds, target_fds_addr, n))
947 return -TARGET_EFAULT;
948 *fds_ptr = fds;
949 } else {
950 *fds_ptr = NULL;
951 }
952 return 0;
953}
954
ths26edcf42007-12-09 02:25:24 +0000955static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
956 const fd_set *fds,
957 int n)
bellard31e31b82003-02-18 22:55:36 +0000958{
bellard31e31b82003-02-18 22:55:36 +0000959 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000960 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000961 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000962
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200963 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000964 if (!(target_fds = lock_user(VERIFY_WRITE,
965 target_fds_addr,
966 sizeof(abi_ulong) * nw,
967 0)))
968 return -TARGET_EFAULT;
969
970 k = 0;
971 for (i = 0; i < nw; i++) {
972 v = 0;
973 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000974 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000975 k++;
bellard31e31b82003-02-18 22:55:36 +0000976 }
ths26edcf42007-12-09 02:25:24 +0000977 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000978 }
ths26edcf42007-12-09 02:25:24 +0000979
980 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
981
982 return 0;
bellard31e31b82003-02-18 22:55:36 +0000983}
984
bellardc596ed12003-07-13 17:32:31 +0000985#if defined(__alpha__)
986#define HOST_HZ 1024
987#else
988#define HOST_HZ 100
989#endif
990
blueswir1992f48a2007-10-14 16:27:31 +0000991static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000992{
993#if HOST_HZ == TARGET_HZ
994 return ticks;
995#else
996 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
997#endif
998}
999
bellard579a97f2007-11-11 14:26:47 +00001000static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1001 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001002{
pbrook53a59602006-03-25 19:31:22 +00001003 struct target_rusage *target_rusage;
1004
bellard579a97f2007-11-11 14:26:47 +00001005 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1006 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001007 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1008 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1009 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1010 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1011 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1012 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1013 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1014 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1015 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1016 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1017 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1018 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1019 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1020 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1021 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1022 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1023 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1024 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001025 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001026
1027 return 0;
bellardb4091862003-05-16 15:39:34 +00001028}
1029
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001030static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001031{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001032 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001033 rlim_t result;
1034
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001035 target_rlim_swap = tswapal(target_rlim);
1036 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1037 return RLIM_INFINITY;
1038
1039 result = target_rlim_swap;
1040 if (target_rlim_swap != (rlim_t)result)
1041 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001042
1043 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001044}
1045
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001046static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001047{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001048 abi_ulong target_rlim_swap;
1049 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001050
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001051 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001052 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001053 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001054 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001055 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001056
1057 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001058}
1059
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001060static inline int target_to_host_resource(int code)
1061{
1062 switch (code) {
1063 case TARGET_RLIMIT_AS:
1064 return RLIMIT_AS;
1065 case TARGET_RLIMIT_CORE:
1066 return RLIMIT_CORE;
1067 case TARGET_RLIMIT_CPU:
1068 return RLIMIT_CPU;
1069 case TARGET_RLIMIT_DATA:
1070 return RLIMIT_DATA;
1071 case TARGET_RLIMIT_FSIZE:
1072 return RLIMIT_FSIZE;
1073 case TARGET_RLIMIT_LOCKS:
1074 return RLIMIT_LOCKS;
1075 case TARGET_RLIMIT_MEMLOCK:
1076 return RLIMIT_MEMLOCK;
1077 case TARGET_RLIMIT_MSGQUEUE:
1078 return RLIMIT_MSGQUEUE;
1079 case TARGET_RLIMIT_NICE:
1080 return RLIMIT_NICE;
1081 case TARGET_RLIMIT_NOFILE:
1082 return RLIMIT_NOFILE;
1083 case TARGET_RLIMIT_NPROC:
1084 return RLIMIT_NPROC;
1085 case TARGET_RLIMIT_RSS:
1086 return RLIMIT_RSS;
1087 case TARGET_RLIMIT_RTPRIO:
1088 return RLIMIT_RTPRIO;
1089 case TARGET_RLIMIT_SIGPENDING:
1090 return RLIMIT_SIGPENDING;
1091 case TARGET_RLIMIT_STACK:
1092 return RLIMIT_STACK;
1093 default:
1094 return code;
1095 }
1096}
1097
ths788f5ec2007-12-09 02:37:05 +00001098static inline abi_long copy_from_user_timeval(struct timeval *tv,
1099 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001100{
pbrook53a59602006-03-25 19:31:22 +00001101 struct target_timeval *target_tv;
1102
ths788f5ec2007-12-09 02:37:05 +00001103 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001104 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001105
1106 __get_user(tv->tv_sec, &target_tv->tv_sec);
1107 __get_user(tv->tv_usec, &target_tv->tv_usec);
1108
1109 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001110
1111 return 0;
bellard31e31b82003-02-18 22:55:36 +00001112}
1113
ths788f5ec2007-12-09 02:37:05 +00001114static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1115 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001116{
pbrook53a59602006-03-25 19:31:22 +00001117 struct target_timeval *target_tv;
1118
ths788f5ec2007-12-09 02:37:05 +00001119 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001120 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001121
1122 __put_user(tv->tv_sec, &target_tv->tv_sec);
1123 __put_user(tv->tv_usec, &target_tv->tv_usec);
1124
1125 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001126
1127 return 0;
bellard31e31b82003-02-18 22:55:36 +00001128}
1129
Paul Burtonef4467e2014-06-22 11:25:40 +01001130static inline abi_long copy_from_user_timezone(struct timezone *tz,
1131 abi_ulong target_tz_addr)
1132{
1133 struct target_timezone *target_tz;
1134
1135 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1136 return -TARGET_EFAULT;
1137 }
1138
1139 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1140 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1141
1142 unlock_user_struct(target_tz, target_tz_addr, 0);
1143
1144 return 0;
1145}
1146
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001147#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1148#include <mqueue.h>
1149
aurel3224e10032009-04-15 16:11:43 +00001150static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1151 abi_ulong target_mq_attr_addr)
1152{
1153 struct target_mq_attr *target_mq_attr;
1154
1155 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1156 target_mq_attr_addr, 1))
1157 return -TARGET_EFAULT;
1158
1159 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1160 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1161 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1162 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1163
1164 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1165
1166 return 0;
1167}
1168
1169static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1170 const struct mq_attr *attr)
1171{
1172 struct target_mq_attr *target_mq_attr;
1173
1174 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1175 target_mq_attr_addr, 0))
1176 return -TARGET_EFAULT;
1177
1178 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1179 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1180 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1181 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1182
1183 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1184
1185 return 0;
1186}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001187#endif
bellard31e31b82003-02-18 22:55:36 +00001188
Mike Frysinger055e0902011-06-03 17:01:49 -04001189#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001190/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001191static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001192 abi_ulong rfd_addr, abi_ulong wfd_addr,
1193 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001194{
1195 fd_set rfds, wfds, efds;
1196 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001197 struct timeval tv;
1198 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001199 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001200
Mike Frysinger055e0902011-06-03 17:01:49 -04001201 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1202 if (ret) {
1203 return ret;
pbrook53a59602006-03-25 19:31:22 +00001204 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001205 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1206 if (ret) {
1207 return ret;
pbrook53a59602006-03-25 19:31:22 +00001208 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001209 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1210 if (ret) {
1211 return ret;
pbrook53a59602006-03-25 19:31:22 +00001212 }
ths3b46e622007-09-17 08:09:54 +00001213
ths26edcf42007-12-09 02:25:24 +00001214 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001215 if (copy_from_user_timeval(&tv, target_tv_addr))
1216 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001217 ts.tv_sec = tv.tv_sec;
1218 ts.tv_nsec = tv.tv_usec * 1000;
1219 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001220 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001221 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001222 }
ths26edcf42007-12-09 02:25:24 +00001223
Peter Maydell6df9d382016-05-12 18:47:51 +01001224 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1225 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001226
ths26edcf42007-12-09 02:25:24 +00001227 if (!is_error(ret)) {
1228 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1229 return -TARGET_EFAULT;
1230 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1231 return -TARGET_EFAULT;
1232 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1233 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001234
Peter Maydell6df9d382016-05-12 18:47:51 +01001235 if (target_tv_addr) {
1236 tv.tv_sec = ts.tv_sec;
1237 tv.tv_usec = ts.tv_nsec / 1000;
1238 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1239 return -TARGET_EFAULT;
1240 }
1241 }
bellard31e31b82003-02-18 22:55:36 +00001242 }
bellard579a97f2007-11-11 14:26:47 +00001243
bellard31e31b82003-02-18 22:55:36 +00001244 return ret;
1245}
Mike Frysinger055e0902011-06-03 17:01:49 -04001246#endif
bellard31e31b82003-02-18 22:55:36 +00001247
Riku Voipio099d6b02009-05-05 12:10:04 +03001248static abi_long do_pipe2(int host_pipe[], int flags)
1249{
1250#ifdef CONFIG_PIPE2
1251 return pipe2(host_pipe, flags);
1252#else
1253 return -ENOSYS;
1254#endif
1255}
1256
Richard Hendersonfb41a662010-05-03 10:07:52 -07001257static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1258 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001259{
1260 int host_pipe[2];
1261 abi_long ret;
1262 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1263
1264 if (is_error(ret))
1265 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001266
1267 /* Several targets have special calling conventions for the original
1268 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1269 if (!is_pipe2) {
1270#if defined(TARGET_ALPHA)
1271 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1272 return host_pipe[0];
1273#elif defined(TARGET_MIPS)
1274 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1275 return host_pipe[0];
1276#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001277 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001278 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001279#elif defined(TARGET_SPARC)
1280 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1281 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001282#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001283 }
1284
Riku Voipio099d6b02009-05-05 12:10:04 +03001285 if (put_user_s32(host_pipe[0], pipedes)
1286 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1287 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001288 return get_errno(ret);
1289}
1290
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001291static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1292 abi_ulong target_addr,
1293 socklen_t len)
1294{
1295 struct target_ip_mreqn *target_smreqn;
1296
1297 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1298 if (!target_smreqn)
1299 return -TARGET_EFAULT;
1300 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1301 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1302 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001303 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001304 unlock_user(target_smreqn, target_addr, 0);
1305
1306 return 0;
1307}
1308
Laurent Vivier7b36f782015-10-28 21:40:44 +01001309static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001310 abi_ulong target_addr,
1311 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001312{
aurel32607175e2009-04-15 16:11:59 +00001313 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1314 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001315 struct target_sockaddr *target_saddr;
1316
Laurent Vivier7b36f782015-10-28 21:40:44 +01001317 if (fd_trans_target_to_host_addr(fd)) {
1318 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1319 }
1320
bellard579a97f2007-11-11 14:26:47 +00001321 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1322 if (!target_saddr)
1323 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001324
1325 sa_family = tswap16(target_saddr->sa_family);
1326
1327 /* Oops. The caller might send a incomplete sun_path; sun_path
1328 * must be terminated by \0 (see the manual page), but
1329 * unfortunately it is quite common to specify sockaddr_un
1330 * length as "strlen(x->sun_path)" while it should be
1331 * "strlen(...) + 1". We'll fix that here if needed.
1332 * Linux kernel has a similar feature.
1333 */
1334
1335 if (sa_family == AF_UNIX) {
1336 if (len < unix_maxlen && len > 0) {
1337 char *cp = (char*)target_saddr;
1338
1339 if ( cp[len-1] && !cp[len] )
1340 len++;
1341 }
1342 if (len > unix_maxlen)
1343 len = unix_maxlen;
1344 }
1345
pbrook53a59602006-03-25 19:31:22 +00001346 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001347 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001348 if (sa_family == AF_NETLINK) {
1349 struct sockaddr_nl *nladdr;
1350
1351 nladdr = (struct sockaddr_nl *)addr;
1352 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1353 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1354 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001355 struct target_sockaddr_ll *lladdr;
1356
1357 lladdr = (struct target_sockaddr_ll *)addr;
1358 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1359 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1360 }
pbrook53a59602006-03-25 19:31:22 +00001361 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001362
1363 return 0;
bellard7854b052003-03-29 17:22:23 +00001364}
1365
bellard579a97f2007-11-11 14:26:47 +00001366static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1367 struct sockaddr *addr,
1368 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001369{
pbrook53a59602006-03-25 19:31:22 +00001370 struct target_sockaddr *target_saddr;
1371
bellard579a97f2007-11-11 14:26:47 +00001372 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1373 if (!target_saddr)
1374 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001375 memcpy(target_saddr, addr, len);
1376 target_saddr->sa_family = tswap16(addr->sa_family);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001377 if (addr->sa_family == AF_NETLINK) {
1378 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1379 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1380 target_nl->nl_groups = tswap32(target_nl->nl_groups);
1381 }
pbrook53a59602006-03-25 19:31:22 +00001382 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001383
1384 return 0;
bellard7854b052003-03-29 17:22:23 +00001385}
1386
bellard5a4a8982007-11-11 17:39:18 +00001387static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1388 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001389{
1390 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001391 abi_long msg_controllen;
1392 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001393 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001394 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001395
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001396 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001397 if (msg_controllen < sizeof (struct target_cmsghdr))
1398 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001399 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001400 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001401 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001402 if (!target_cmsg)
1403 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001404
1405 while (cmsg && target_cmsg) {
1406 void *data = CMSG_DATA(cmsg);
1407 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1408
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001409 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001410 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1411
1412 space += CMSG_SPACE(len);
1413 if (space > msgh->msg_controllen) {
1414 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001415 /* This is a QEMU bug, since we allocated the payload
1416 * area ourselves (unlike overflow in host-to-target
1417 * conversion, which is just the guest giving us a buffer
1418 * that's too small). It can't happen for the payload types
1419 * we currently support; if it becomes an issue in future
1420 * we would need to improve our allocation strategy to
1421 * something more intelligent than "twice the size of the
1422 * target buffer we're reading from".
1423 */
bellard31febb72005-12-18 20:03:27 +00001424 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001425 break;
1426 }
1427
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001428 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1429 cmsg->cmsg_level = SOL_SOCKET;
1430 } else {
1431 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1432 }
bellard7854b052003-03-29 17:22:23 +00001433 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1434 cmsg->cmsg_len = CMSG_LEN(len);
1435
Alex Suykov30b8b682014-12-23 07:52:58 +02001436 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001437 int *fd = (int *)data;
1438 int *target_fd = (int *)target_data;
1439 int i, numfds = len / sizeof(int);
1440
Peter Maydell876e23c2015-05-26 19:46:32 +01001441 for (i = 0; i < numfds; i++) {
1442 __get_user(fd[i], target_fd + i);
1443 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001444 } else if (cmsg->cmsg_level == SOL_SOCKET
1445 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1446 struct ucred *cred = (struct ucred *)data;
1447 struct target_ucred *target_cred =
1448 (struct target_ucred *)target_data;
1449
Peter Maydell876e23c2015-05-26 19:46:32 +01001450 __get_user(cred->pid, &target_cred->pid);
1451 __get_user(cred->uid, &target_cred->uid);
1452 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001453 } else {
1454 gemu_log("Unsupported ancillary data: %d/%d\n",
1455 cmsg->cmsg_level, cmsg->cmsg_type);
1456 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001457 }
1458
1459 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001460 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1461 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001462 }
bellard5a4a8982007-11-11 17:39:18 +00001463 unlock_user(target_cmsg, target_cmsg_addr, 0);
1464 the_end:
bellard7854b052003-03-29 17:22:23 +00001465 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001466 return 0;
bellard7854b052003-03-29 17:22:23 +00001467}
1468
bellard5a4a8982007-11-11 17:39:18 +00001469static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1470 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001471{
1472 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001473 abi_long msg_controllen;
1474 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001475 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001476 socklen_t space = 0;
1477
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001478 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001479 if (msg_controllen < sizeof (struct target_cmsghdr))
1480 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001481 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001482 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001483 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001484 if (!target_cmsg)
1485 return -TARGET_EFAULT;
1486
bellard7854b052003-03-29 17:22:23 +00001487 while (cmsg && target_cmsg) {
1488 void *data = CMSG_DATA(cmsg);
1489 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1490
1491 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001492 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001493
Peter Maydellc2aeb252015-05-26 19:46:31 +01001494 /* We never copy a half-header but may copy half-data;
1495 * this is Linux's behaviour in put_cmsg(). Note that
1496 * truncation here is a guest problem (which we report
1497 * to the guest via the CTRUNC bit), unlike truncation
1498 * in target_to_host_cmsg, which is a QEMU bug.
1499 */
1500 if (msg_controllen < sizeof(struct cmsghdr)) {
1501 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001502 break;
1503 }
1504
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001505 if (cmsg->cmsg_level == SOL_SOCKET) {
1506 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1507 } else {
1508 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1509 }
bellard7854b052003-03-29 17:22:23 +00001510 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001511
Peter Maydellc2aeb252015-05-26 19:46:31 +01001512 tgt_len = TARGET_CMSG_LEN(len);
1513
1514 /* Payload types which need a different size of payload on
1515 * the target must adjust tgt_len here.
1516 */
1517 switch (cmsg->cmsg_level) {
1518 case SOL_SOCKET:
1519 switch (cmsg->cmsg_type) {
1520 case SO_TIMESTAMP:
1521 tgt_len = sizeof(struct target_timeval);
1522 break;
1523 default:
1524 break;
1525 }
1526 default:
1527 break;
1528 }
1529
1530 if (msg_controllen < tgt_len) {
1531 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1532 tgt_len = msg_controllen;
1533 }
1534
1535 /* We must now copy-and-convert len bytes of payload
1536 * into tgt_len bytes of destination space. Bear in mind
1537 * that in both source and destination we may be dealing
1538 * with a truncated value!
1539 */
Huw Davies52b65492014-04-17 14:02:47 +01001540 switch (cmsg->cmsg_level) {
1541 case SOL_SOCKET:
1542 switch (cmsg->cmsg_type) {
1543 case SCM_RIGHTS:
1544 {
1545 int *fd = (int *)data;
1546 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001547 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001548
Peter Maydell876e23c2015-05-26 19:46:32 +01001549 for (i = 0; i < numfds; i++) {
1550 __put_user(fd[i], target_fd + i);
1551 }
Huw Davies52b65492014-04-17 14:02:47 +01001552 break;
1553 }
1554 case SO_TIMESTAMP:
1555 {
1556 struct timeval *tv = (struct timeval *)data;
1557 struct target_timeval *target_tv =
1558 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001559
Peter Maydellc2aeb252015-05-26 19:46:31 +01001560 if (len != sizeof(struct timeval) ||
1561 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001562 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001563 }
Huw Davies52b65492014-04-17 14:02:47 +01001564
1565 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001566 __put_user(tv->tv_sec, &target_tv->tv_sec);
1567 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001568 break;
1569 }
Huw Davies4bc29752014-04-17 14:02:48 +01001570 case SCM_CREDENTIALS:
1571 {
1572 struct ucred *cred = (struct ucred *)data;
1573 struct target_ucred *target_cred =
1574 (struct target_ucred *)target_data;
1575
1576 __put_user(cred->pid, &target_cred->pid);
1577 __put_user(cred->uid, &target_cred->uid);
1578 __put_user(cred->gid, &target_cred->gid);
1579 break;
1580 }
Huw Davies52b65492014-04-17 14:02:47 +01001581 default:
1582 goto unimplemented;
1583 }
1584 break;
1585
1586 default:
1587 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001588 gemu_log("Unsupported ancillary data: %d/%d\n",
1589 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001590 memcpy(target_data, data, MIN(len, tgt_len));
1591 if (tgt_len > len) {
1592 memset(target_data + len, 0, tgt_len - len);
1593 }
bellard7854b052003-03-29 17:22:23 +00001594 }
1595
Peter Maydellc2aeb252015-05-26 19:46:31 +01001596 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001597 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001598 if (msg_controllen < tgt_space) {
1599 tgt_space = msg_controllen;
1600 }
1601 msg_controllen -= tgt_space;
1602 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001603 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001604 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1605 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001606 }
bellard5a4a8982007-11-11 17:39:18 +00001607 unlock_user(target_cmsg, target_cmsg_addr, space);
1608 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001609 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001610 return 0;
bellard7854b052003-03-29 17:22:23 +00001611}
1612
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001613static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1614{
1615 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1616 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1617 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1618 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1619 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1620}
1621
1622static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1623 size_t len,
1624 abi_long (*host_to_target_nlmsg)
1625 (struct nlmsghdr *))
1626{
1627 uint32_t nlmsg_len;
1628 abi_long ret;
1629
1630 while (len > sizeof(struct nlmsghdr)) {
1631
1632 nlmsg_len = nlh->nlmsg_len;
1633 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1634 nlmsg_len > len) {
1635 break;
1636 }
1637
1638 switch (nlh->nlmsg_type) {
1639 case NLMSG_DONE:
1640 tswap_nlmsghdr(nlh);
1641 return 0;
1642 case NLMSG_NOOP:
1643 break;
1644 case NLMSG_ERROR:
1645 {
1646 struct nlmsgerr *e = NLMSG_DATA(nlh);
1647 e->error = tswap32(e->error);
1648 tswap_nlmsghdr(&e->msg);
1649 tswap_nlmsghdr(nlh);
1650 return 0;
1651 }
1652 default:
1653 ret = host_to_target_nlmsg(nlh);
1654 if (ret < 0) {
1655 tswap_nlmsghdr(nlh);
1656 return ret;
1657 }
1658 break;
1659 }
1660 tswap_nlmsghdr(nlh);
1661 len -= NLMSG_ALIGN(nlmsg_len);
1662 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1663 }
1664 return 0;
1665}
1666
1667static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1668 size_t len,
1669 abi_long (*target_to_host_nlmsg)
1670 (struct nlmsghdr *))
1671{
1672 int ret;
1673
1674 while (len > sizeof(struct nlmsghdr)) {
1675 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1676 tswap32(nlh->nlmsg_len) > len) {
1677 break;
1678 }
1679 tswap_nlmsghdr(nlh);
1680 switch (nlh->nlmsg_type) {
1681 case NLMSG_DONE:
1682 return 0;
1683 case NLMSG_NOOP:
1684 break;
1685 case NLMSG_ERROR:
1686 {
1687 struct nlmsgerr *e = NLMSG_DATA(nlh);
1688 e->error = tswap32(e->error);
1689 tswap_nlmsghdr(&e->msg);
1690 }
1691 default:
1692 ret = target_to_host_nlmsg(nlh);
1693 if (ret < 0) {
1694 return ret;
1695 }
1696 }
1697 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1698 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1699 }
1700 return 0;
1701}
1702
Laurent Vivier575b22b2016-06-02 22:14:15 +02001703#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001704static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1705 size_t len,
1706 abi_long (*host_to_target_rtattr)
1707 (struct rtattr *))
1708{
1709 unsigned short rta_len;
1710 abi_long ret;
1711
1712 while (len > sizeof(struct rtattr)) {
1713 rta_len = rtattr->rta_len;
1714 if (rta_len < sizeof(struct rtattr) ||
1715 rta_len > len) {
1716 break;
1717 }
1718 ret = host_to_target_rtattr(rtattr);
1719 rtattr->rta_len = tswap16(rtattr->rta_len);
1720 rtattr->rta_type = tswap16(rtattr->rta_type);
1721 if (ret < 0) {
1722 return ret;
1723 }
1724 len -= RTA_ALIGN(rta_len);
1725 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1726 }
1727 return 0;
1728}
1729
1730static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
1731{
1732 uint32_t *u32;
1733 struct rtnl_link_stats *st;
1734 struct rtnl_link_stats64 *st64;
1735 struct rtnl_link_ifmap *map;
1736
1737 switch (rtattr->rta_type) {
1738 /* binary stream */
1739 case IFLA_ADDRESS:
1740 case IFLA_BROADCAST:
1741 /* string */
1742 case IFLA_IFNAME:
1743 case IFLA_QDISC:
1744 break;
1745 /* uin8_t */
1746 case IFLA_OPERSTATE:
1747 case IFLA_LINKMODE:
1748 case IFLA_CARRIER:
1749 case IFLA_PROTO_DOWN:
1750 break;
1751 /* uint32_t */
1752 case IFLA_MTU:
1753 case IFLA_LINK:
1754 case IFLA_WEIGHT:
1755 case IFLA_TXQLEN:
1756 case IFLA_CARRIER_CHANGES:
1757 case IFLA_NUM_RX_QUEUES:
1758 case IFLA_NUM_TX_QUEUES:
1759 case IFLA_PROMISCUITY:
1760 case IFLA_EXT_MASK:
1761 case IFLA_LINK_NETNSID:
1762 case IFLA_GROUP:
1763 case IFLA_MASTER:
1764 case IFLA_NUM_VF:
1765 u32 = RTA_DATA(rtattr);
1766 *u32 = tswap32(*u32);
1767 break;
1768 /* struct rtnl_link_stats */
1769 case IFLA_STATS:
1770 st = RTA_DATA(rtattr);
1771 st->rx_packets = tswap32(st->rx_packets);
1772 st->tx_packets = tswap32(st->tx_packets);
1773 st->rx_bytes = tswap32(st->rx_bytes);
1774 st->tx_bytes = tswap32(st->tx_bytes);
1775 st->rx_errors = tswap32(st->rx_errors);
1776 st->tx_errors = tswap32(st->tx_errors);
1777 st->rx_dropped = tswap32(st->rx_dropped);
1778 st->tx_dropped = tswap32(st->tx_dropped);
1779 st->multicast = tswap32(st->multicast);
1780 st->collisions = tswap32(st->collisions);
1781
1782 /* detailed rx_errors: */
1783 st->rx_length_errors = tswap32(st->rx_length_errors);
1784 st->rx_over_errors = tswap32(st->rx_over_errors);
1785 st->rx_crc_errors = tswap32(st->rx_crc_errors);
1786 st->rx_frame_errors = tswap32(st->rx_frame_errors);
1787 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
1788 st->rx_missed_errors = tswap32(st->rx_missed_errors);
1789
1790 /* detailed tx_errors */
1791 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
1792 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
1793 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
1794 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
1795 st->tx_window_errors = tswap32(st->tx_window_errors);
1796
1797 /* for cslip etc */
1798 st->rx_compressed = tswap32(st->rx_compressed);
1799 st->tx_compressed = tswap32(st->tx_compressed);
1800 break;
1801 /* struct rtnl_link_stats64 */
1802 case IFLA_STATS64:
1803 st64 = RTA_DATA(rtattr);
1804 st64->rx_packets = tswap64(st64->rx_packets);
1805 st64->tx_packets = tswap64(st64->tx_packets);
1806 st64->rx_bytes = tswap64(st64->rx_bytes);
1807 st64->tx_bytes = tswap64(st64->tx_bytes);
1808 st64->rx_errors = tswap64(st64->rx_errors);
1809 st64->tx_errors = tswap64(st64->tx_errors);
1810 st64->rx_dropped = tswap64(st64->rx_dropped);
1811 st64->tx_dropped = tswap64(st64->tx_dropped);
1812 st64->multicast = tswap64(st64->multicast);
1813 st64->collisions = tswap64(st64->collisions);
1814
1815 /* detailed rx_errors: */
1816 st64->rx_length_errors = tswap64(st64->rx_length_errors);
1817 st64->rx_over_errors = tswap64(st64->rx_over_errors);
1818 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
1819 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
1820 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
1821 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
1822
1823 /* detailed tx_errors */
1824 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
1825 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
1826 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
1827 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
1828 st64->tx_window_errors = tswap64(st64->tx_window_errors);
1829
1830 /* for cslip etc */
1831 st64->rx_compressed = tswap64(st64->rx_compressed);
1832 st64->tx_compressed = tswap64(st64->tx_compressed);
1833 break;
1834 /* struct rtnl_link_ifmap */
1835 case IFLA_MAP:
1836 map = RTA_DATA(rtattr);
1837 map->mem_start = tswap64(map->mem_start);
1838 map->mem_end = tswap64(map->mem_end);
1839 map->base_addr = tswap64(map->base_addr);
1840 map->irq = tswap16(map->irq);
1841 break;
1842 /* nested */
1843 case IFLA_AF_SPEC:
1844 case IFLA_LINKINFO:
1845 /* FIXME: implement nested type */
1846 gemu_log("Unimplemented nested type %d\n", rtattr->rta_type);
1847 break;
1848 default:
1849 gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type);
1850 break;
1851 }
1852 return 0;
1853}
1854
1855static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
1856{
1857 uint32_t *u32;
1858 struct ifa_cacheinfo *ci;
1859
1860 switch (rtattr->rta_type) {
1861 /* binary: depends on family type */
1862 case IFA_ADDRESS:
1863 case IFA_LOCAL:
1864 break;
1865 /* string */
1866 case IFA_LABEL:
1867 break;
1868 /* u32 */
1869 case IFA_FLAGS:
1870 case IFA_BROADCAST:
1871 u32 = RTA_DATA(rtattr);
1872 *u32 = tswap32(*u32);
1873 break;
1874 /* struct ifa_cacheinfo */
1875 case IFA_CACHEINFO:
1876 ci = RTA_DATA(rtattr);
1877 ci->ifa_prefered = tswap32(ci->ifa_prefered);
1878 ci->ifa_valid = tswap32(ci->ifa_valid);
1879 ci->cstamp = tswap32(ci->cstamp);
1880 ci->tstamp = tswap32(ci->tstamp);
1881 break;
1882 default:
1883 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
1884 break;
1885 }
1886 return 0;
1887}
1888
1889static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
1890{
1891 uint32_t *u32;
1892 switch (rtattr->rta_type) {
1893 /* binary: depends on family type */
1894 case RTA_GATEWAY:
1895 case RTA_DST:
1896 case RTA_PREFSRC:
1897 break;
1898 /* u32 */
1899 case RTA_PRIORITY:
1900 case RTA_TABLE:
1901 case RTA_OIF:
1902 u32 = RTA_DATA(rtattr);
1903 *u32 = tswap32(*u32);
1904 break;
1905 default:
1906 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
1907 break;
1908 }
1909 return 0;
1910}
1911
1912static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
1913 uint32_t rtattr_len)
1914{
1915 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1916 host_to_target_data_link_rtattr);
1917}
1918
1919static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
1920 uint32_t rtattr_len)
1921{
1922 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1923 host_to_target_data_addr_rtattr);
1924}
1925
1926static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
1927 uint32_t rtattr_len)
1928{
1929 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1930 host_to_target_data_route_rtattr);
1931}
1932
1933static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
1934{
1935 uint32_t nlmsg_len;
1936 struct ifinfomsg *ifi;
1937 struct ifaddrmsg *ifa;
1938 struct rtmsg *rtm;
1939
1940 nlmsg_len = nlh->nlmsg_len;
1941 switch (nlh->nlmsg_type) {
1942 case RTM_NEWLINK:
1943 case RTM_DELLINK:
1944 case RTM_GETLINK:
1945 ifi = NLMSG_DATA(nlh);
1946 ifi->ifi_type = tswap16(ifi->ifi_type);
1947 ifi->ifi_index = tswap32(ifi->ifi_index);
1948 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1949 ifi->ifi_change = tswap32(ifi->ifi_change);
1950 host_to_target_link_rtattr(IFLA_RTA(ifi),
1951 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1952 break;
1953 case RTM_NEWADDR:
1954 case RTM_DELADDR:
1955 case RTM_GETADDR:
1956 ifa = NLMSG_DATA(nlh);
1957 ifa->ifa_index = tswap32(ifa->ifa_index);
1958 host_to_target_addr_rtattr(IFA_RTA(ifa),
1959 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1960 break;
1961 case RTM_NEWROUTE:
1962 case RTM_DELROUTE:
1963 case RTM_GETROUTE:
1964 rtm = NLMSG_DATA(nlh);
1965 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1966 host_to_target_route_rtattr(RTM_RTA(rtm),
1967 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1968 break;
1969 default:
1970 return -TARGET_EINVAL;
1971 }
1972 return 0;
1973}
1974
1975static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1976 size_t len)
1977{
1978 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1979}
1980
1981static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1982 size_t len,
1983 abi_long (*target_to_host_rtattr)
1984 (struct rtattr *))
1985{
1986 abi_long ret;
1987
1988 while (len >= sizeof(struct rtattr)) {
1989 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
1990 tswap16(rtattr->rta_len) > len) {
1991 break;
1992 }
1993 rtattr->rta_len = tswap16(rtattr->rta_len);
1994 rtattr->rta_type = tswap16(rtattr->rta_type);
1995 ret = target_to_host_rtattr(rtattr);
1996 if (ret < 0) {
1997 return ret;
1998 }
1999 len -= RTA_ALIGN(rtattr->rta_len);
2000 rtattr = (struct rtattr *)(((char *)rtattr) +
2001 RTA_ALIGN(rtattr->rta_len));
2002 }
2003 return 0;
2004}
2005
2006static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2007{
2008 switch (rtattr->rta_type) {
2009 default:
2010 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
2011 break;
2012 }
2013 return 0;
2014}
2015
2016static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2017{
2018 switch (rtattr->rta_type) {
2019 /* binary: depends on family type */
2020 case IFA_LOCAL:
2021 case IFA_ADDRESS:
2022 break;
2023 default:
2024 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2025 break;
2026 }
2027 return 0;
2028}
2029
2030static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2031{
2032 uint32_t *u32;
2033 switch (rtattr->rta_type) {
2034 /* binary: depends on family type */
2035 case RTA_DST:
2036 case RTA_SRC:
2037 case RTA_GATEWAY:
2038 break;
2039 /* u32 */
2040 case RTA_OIF:
2041 u32 = RTA_DATA(rtattr);
2042 *u32 = tswap32(*u32);
2043 break;
2044 default:
2045 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2046 break;
2047 }
2048 return 0;
2049}
2050
2051static void target_to_host_link_rtattr(struct rtattr *rtattr,
2052 uint32_t rtattr_len)
2053{
2054 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2055 target_to_host_data_link_rtattr);
2056}
2057
2058static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2059 uint32_t rtattr_len)
2060{
2061 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2062 target_to_host_data_addr_rtattr);
2063}
2064
2065static void target_to_host_route_rtattr(struct rtattr *rtattr,
2066 uint32_t rtattr_len)
2067{
2068 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2069 target_to_host_data_route_rtattr);
2070}
2071
2072static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2073{
2074 struct ifinfomsg *ifi;
2075 struct ifaddrmsg *ifa;
2076 struct rtmsg *rtm;
2077
2078 switch (nlh->nlmsg_type) {
2079 case RTM_GETLINK:
2080 break;
2081 case RTM_NEWLINK:
2082 case RTM_DELLINK:
2083 ifi = NLMSG_DATA(nlh);
2084 ifi->ifi_type = tswap16(ifi->ifi_type);
2085 ifi->ifi_index = tswap32(ifi->ifi_index);
2086 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2087 ifi->ifi_change = tswap32(ifi->ifi_change);
2088 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2089 NLMSG_LENGTH(sizeof(*ifi)));
2090 break;
2091 case RTM_GETADDR:
2092 case RTM_NEWADDR:
2093 case RTM_DELADDR:
2094 ifa = NLMSG_DATA(nlh);
2095 ifa->ifa_index = tswap32(ifa->ifa_index);
2096 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2097 NLMSG_LENGTH(sizeof(*ifa)));
2098 break;
2099 case RTM_GETROUTE:
2100 break;
2101 case RTM_NEWROUTE:
2102 case RTM_DELROUTE:
2103 rtm = NLMSG_DATA(nlh);
2104 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2105 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2106 NLMSG_LENGTH(sizeof(*rtm)));
2107 break;
2108 default:
2109 return -TARGET_EOPNOTSUPP;
2110 }
2111 return 0;
2112}
2113
2114static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2115{
2116 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2117}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002118#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002119
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002120static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2121{
2122 switch (nlh->nlmsg_type) {
2123 default:
2124 gemu_log("Unknown host audit message type %d\n",
2125 nlh->nlmsg_type);
2126 return -TARGET_EINVAL;
2127 }
2128 return 0;
2129}
2130
2131static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2132 size_t len)
2133{
2134 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2135}
2136
2137static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2138{
2139 switch (nlh->nlmsg_type) {
2140 case AUDIT_USER:
2141 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2142 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2143 break;
2144 default:
2145 gemu_log("Unknown target audit message type %d\n",
2146 nlh->nlmsg_type);
2147 return -TARGET_EINVAL;
2148 }
2149
2150 return 0;
2151}
2152
2153static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2154{
2155 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2156}
2157
ths0da46a62007-10-20 20:23:07 +00002158/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002159static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002160 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002161{
blueswir1992f48a2007-10-14 16:27:31 +00002162 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002163 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002164 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002165 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002166
bellard8853f862004-02-22 14:57:26 +00002167 switch(level) {
2168 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002169 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002170 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002171 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002172
bellard2f619692007-11-16 10:46:05 +00002173 if (get_user_u32(val, optval_addr))
2174 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002175 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2176 break;
2177 case SOL_IP:
2178 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002179 case IP_TOS:
2180 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002181 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002182 case IP_ROUTER_ALERT:
2183 case IP_RECVOPTS:
2184 case IP_RETOPTS:
2185 case IP_PKTINFO:
2186 case IP_MTU_DISCOVER:
2187 case IP_RECVERR:
2188 case IP_RECVTOS:
2189#ifdef IP_FREEBIND
2190 case IP_FREEBIND:
2191#endif
2192 case IP_MULTICAST_TTL:
2193 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002194 val = 0;
2195 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002196 if (get_user_u32(val, optval_addr))
2197 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002198 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002199 if (get_user_u8(val, optval_addr))
2200 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002201 }
2202 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2203 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002204 case IP_ADD_MEMBERSHIP:
2205 case IP_DROP_MEMBERSHIP:
2206 if (optlen < sizeof (struct target_ip_mreq) ||
2207 optlen > sizeof (struct target_ip_mreqn))
2208 return -TARGET_EINVAL;
2209
2210 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2211 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2212 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2213 break;
2214
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002215 case IP_BLOCK_SOURCE:
2216 case IP_UNBLOCK_SOURCE:
2217 case IP_ADD_SOURCE_MEMBERSHIP:
2218 case IP_DROP_SOURCE_MEMBERSHIP:
2219 if (optlen != sizeof (struct target_ip_mreq_source))
2220 return -TARGET_EINVAL;
2221
2222 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2223 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2224 unlock_user (ip_mreq_source, optval_addr, 0);
2225 break;
2226
bellard8853f862004-02-22 14:57:26 +00002227 default:
2228 goto unimplemented;
2229 }
2230 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002231 case SOL_IPV6:
2232 switch (optname) {
2233 case IPV6_MTU_DISCOVER:
2234 case IPV6_MTU:
2235 case IPV6_V6ONLY:
2236 case IPV6_RECVPKTINFO:
2237 val = 0;
2238 if (optlen < sizeof(uint32_t)) {
2239 return -TARGET_EINVAL;
2240 }
2241 if (get_user_u32(val, optval_addr)) {
2242 return -TARGET_EFAULT;
2243 }
2244 ret = get_errno(setsockopt(sockfd, level, optname,
2245 &val, sizeof(val)));
2246 break;
2247 default:
2248 goto unimplemented;
2249 }
2250 break;
Jing Huang920394d2012-07-24 13:59:23 +00002251 case SOL_RAW:
2252 switch (optname) {
2253 case ICMP_FILTER:
2254 /* struct icmp_filter takes an u32 value */
2255 if (optlen < sizeof(uint32_t)) {
2256 return -TARGET_EINVAL;
2257 }
2258
2259 if (get_user_u32(val, optval_addr)) {
2260 return -TARGET_EFAULT;
2261 }
2262 ret = get_errno(setsockopt(sockfd, level, optname,
2263 &val, sizeof(val)));
2264 break;
2265
2266 default:
2267 goto unimplemented;
2268 }
2269 break;
bellard3532fa72006-06-24 15:06:03 +00002270 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002271 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002272 case TARGET_SO_RCVTIMEO:
2273 {
2274 struct timeval tv;
2275
2276 optname = SO_RCVTIMEO;
2277
2278set_timeout:
2279 if (optlen != sizeof(struct target_timeval)) {
2280 return -TARGET_EINVAL;
2281 }
2282
2283 if (copy_from_user_timeval(&tv, optval_addr)) {
2284 return -TARGET_EFAULT;
2285 }
2286
2287 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2288 &tv, sizeof(tv)));
2289 return ret;
2290 }
2291 case TARGET_SO_SNDTIMEO:
2292 optname = SO_SNDTIMEO;
2293 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002294 case TARGET_SO_ATTACH_FILTER:
2295 {
2296 struct target_sock_fprog *tfprog;
2297 struct target_sock_filter *tfilter;
2298 struct sock_fprog fprog;
2299 struct sock_filter *filter;
2300 int i;
2301
2302 if (optlen != sizeof(*tfprog)) {
2303 return -TARGET_EINVAL;
2304 }
2305 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2306 return -TARGET_EFAULT;
2307 }
2308 if (!lock_user_struct(VERIFY_READ, tfilter,
2309 tswapal(tfprog->filter), 0)) {
2310 unlock_user_struct(tfprog, optval_addr, 1);
2311 return -TARGET_EFAULT;
2312 }
2313
2314 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302315 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002316 if (filter == NULL) {
2317 unlock_user_struct(tfilter, tfprog->filter, 1);
2318 unlock_user_struct(tfprog, optval_addr, 1);
2319 return -TARGET_ENOMEM;
2320 }
2321 for (i = 0; i < fprog.len; i++) {
2322 filter[i].code = tswap16(tfilter[i].code);
2323 filter[i].jt = tfilter[i].jt;
2324 filter[i].jf = tfilter[i].jf;
2325 filter[i].k = tswap32(tfilter[i].k);
2326 }
2327 fprog.filter = filter;
2328
2329 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2330 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302331 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002332
2333 unlock_user_struct(tfilter, tfprog->filter, 1);
2334 unlock_user_struct(tfprog, optval_addr, 1);
2335 return ret;
2336 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002337 case TARGET_SO_BINDTODEVICE:
2338 {
2339 char *dev_ifname, *addr_ifname;
2340
2341 if (optlen > IFNAMSIZ - 1) {
2342 optlen = IFNAMSIZ - 1;
2343 }
2344 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2345 if (!dev_ifname) {
2346 return -TARGET_EFAULT;
2347 }
2348 optname = SO_BINDTODEVICE;
2349 addr_ifname = alloca(IFNAMSIZ);
2350 memcpy(addr_ifname, dev_ifname, optlen);
2351 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002352 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2353 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002354 unlock_user (dev_ifname, optval_addr, 0);
2355 return ret;
2356 }
bellard8853f862004-02-22 14:57:26 +00002357 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002358 case TARGET_SO_DEBUG:
2359 optname = SO_DEBUG;
2360 break;
2361 case TARGET_SO_REUSEADDR:
2362 optname = SO_REUSEADDR;
2363 break;
2364 case TARGET_SO_TYPE:
2365 optname = SO_TYPE;
2366 break;
2367 case TARGET_SO_ERROR:
2368 optname = SO_ERROR;
2369 break;
2370 case TARGET_SO_DONTROUTE:
2371 optname = SO_DONTROUTE;
2372 break;
2373 case TARGET_SO_BROADCAST:
2374 optname = SO_BROADCAST;
2375 break;
2376 case TARGET_SO_SNDBUF:
2377 optname = SO_SNDBUF;
2378 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002379 case TARGET_SO_SNDBUFFORCE:
2380 optname = SO_SNDBUFFORCE;
2381 break;
bellard3532fa72006-06-24 15:06:03 +00002382 case TARGET_SO_RCVBUF:
2383 optname = SO_RCVBUF;
2384 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002385 case TARGET_SO_RCVBUFFORCE:
2386 optname = SO_RCVBUFFORCE;
2387 break;
bellard3532fa72006-06-24 15:06:03 +00002388 case TARGET_SO_KEEPALIVE:
2389 optname = SO_KEEPALIVE;
2390 break;
2391 case TARGET_SO_OOBINLINE:
2392 optname = SO_OOBINLINE;
2393 break;
2394 case TARGET_SO_NO_CHECK:
2395 optname = SO_NO_CHECK;
2396 break;
2397 case TARGET_SO_PRIORITY:
2398 optname = SO_PRIORITY;
2399 break;
bellard5e83e8e2005-03-01 22:32:06 +00002400#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002401 case TARGET_SO_BSDCOMPAT:
2402 optname = SO_BSDCOMPAT;
2403 break;
bellard5e83e8e2005-03-01 22:32:06 +00002404#endif
bellard3532fa72006-06-24 15:06:03 +00002405 case TARGET_SO_PASSCRED:
2406 optname = SO_PASSCRED;
2407 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002408 case TARGET_SO_PASSSEC:
2409 optname = SO_PASSSEC;
2410 break;
bellard3532fa72006-06-24 15:06:03 +00002411 case TARGET_SO_TIMESTAMP:
2412 optname = SO_TIMESTAMP;
2413 break;
2414 case TARGET_SO_RCVLOWAT:
2415 optname = SO_RCVLOWAT;
2416 break;
bellard8853f862004-02-22 14:57:26 +00002417 break;
2418 default:
2419 goto unimplemented;
2420 }
bellard3532fa72006-06-24 15:06:03 +00002421 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002422 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002423
bellard2f619692007-11-16 10:46:05 +00002424 if (get_user_u32(val, optval_addr))
2425 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002426 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002427 break;
bellard7854b052003-03-29 17:22:23 +00002428 default:
bellard8853f862004-02-22 14:57:26 +00002429 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002430 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002431 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002432 }
bellard8853f862004-02-22 14:57:26 +00002433 return ret;
bellard7854b052003-03-29 17:22:23 +00002434}
2435
ths0da46a62007-10-20 20:23:07 +00002436/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002437static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002438 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002439{
blueswir1992f48a2007-10-14 16:27:31 +00002440 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002441 int len, val;
2442 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002443
2444 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002445 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002446 level = SOL_SOCKET;
2447 switch (optname) {
2448 /* These don't just return a single integer */
2449 case TARGET_SO_LINGER:
2450 case TARGET_SO_RCVTIMEO:
2451 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002452 case TARGET_SO_PEERNAME:
2453 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002454 case TARGET_SO_PEERCRED: {
2455 struct ucred cr;
2456 socklen_t crlen;
2457 struct target_ucred *tcr;
2458
2459 if (get_user_u32(len, optlen)) {
2460 return -TARGET_EFAULT;
2461 }
2462 if (len < 0) {
2463 return -TARGET_EINVAL;
2464 }
2465
2466 crlen = sizeof(cr);
2467 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2468 &cr, &crlen));
2469 if (ret < 0) {
2470 return ret;
2471 }
2472 if (len > crlen) {
2473 len = crlen;
2474 }
2475 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2476 return -TARGET_EFAULT;
2477 }
2478 __put_user(cr.pid, &tcr->pid);
2479 __put_user(cr.uid, &tcr->uid);
2480 __put_user(cr.gid, &tcr->gid);
2481 unlock_user_struct(tcr, optval_addr, 1);
2482 if (put_user_u32(len, optlen)) {
2483 return -TARGET_EFAULT;
2484 }
2485 break;
2486 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002487 /* Options with 'int' argument. */
2488 case TARGET_SO_DEBUG:
2489 optname = SO_DEBUG;
2490 goto int_case;
2491 case TARGET_SO_REUSEADDR:
2492 optname = SO_REUSEADDR;
2493 goto int_case;
2494 case TARGET_SO_TYPE:
2495 optname = SO_TYPE;
2496 goto int_case;
2497 case TARGET_SO_ERROR:
2498 optname = SO_ERROR;
2499 goto int_case;
2500 case TARGET_SO_DONTROUTE:
2501 optname = SO_DONTROUTE;
2502 goto int_case;
2503 case TARGET_SO_BROADCAST:
2504 optname = SO_BROADCAST;
2505 goto int_case;
2506 case TARGET_SO_SNDBUF:
2507 optname = SO_SNDBUF;
2508 goto int_case;
2509 case TARGET_SO_RCVBUF:
2510 optname = SO_RCVBUF;
2511 goto int_case;
2512 case TARGET_SO_KEEPALIVE:
2513 optname = SO_KEEPALIVE;
2514 goto int_case;
2515 case TARGET_SO_OOBINLINE:
2516 optname = SO_OOBINLINE;
2517 goto int_case;
2518 case TARGET_SO_NO_CHECK:
2519 optname = SO_NO_CHECK;
2520 goto int_case;
2521 case TARGET_SO_PRIORITY:
2522 optname = SO_PRIORITY;
2523 goto int_case;
2524#ifdef SO_BSDCOMPAT
2525 case TARGET_SO_BSDCOMPAT:
2526 optname = SO_BSDCOMPAT;
2527 goto int_case;
2528#endif
2529 case TARGET_SO_PASSCRED:
2530 optname = SO_PASSCRED;
2531 goto int_case;
2532 case TARGET_SO_TIMESTAMP:
2533 optname = SO_TIMESTAMP;
2534 goto int_case;
2535 case TARGET_SO_RCVLOWAT:
2536 optname = SO_RCVLOWAT;
2537 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002538 case TARGET_SO_ACCEPTCONN:
2539 optname = SO_ACCEPTCONN;
2540 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002541 default:
bellard2efbe912005-07-23 15:10:20 +00002542 goto int_case;
2543 }
2544 break;
2545 case SOL_TCP:
2546 /* TCP options all take an 'int' value. */
2547 int_case:
bellard2f619692007-11-16 10:46:05 +00002548 if (get_user_u32(len, optlen))
2549 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002550 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002551 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002552 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002553 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2554 if (ret < 0)
2555 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002556 if (optname == SO_TYPE) {
2557 val = host_to_target_sock_type(val);
2558 }
bellard2efbe912005-07-23 15:10:20 +00002559 if (len > lv)
2560 len = lv;
bellard2f619692007-11-16 10:46:05 +00002561 if (len == 4) {
2562 if (put_user_u32(val, optval_addr))
2563 return -TARGET_EFAULT;
2564 } else {
2565 if (put_user_u8(val, optval_addr))
2566 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002567 }
bellard2f619692007-11-16 10:46:05 +00002568 if (put_user_u32(len, optlen))
2569 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002570 break;
2571 case SOL_IP:
2572 switch(optname) {
2573 case IP_TOS:
2574 case IP_TTL:
2575 case IP_HDRINCL:
2576 case IP_ROUTER_ALERT:
2577 case IP_RECVOPTS:
2578 case IP_RETOPTS:
2579 case IP_PKTINFO:
2580 case IP_MTU_DISCOVER:
2581 case IP_RECVERR:
2582 case IP_RECVTOS:
2583#ifdef IP_FREEBIND
2584 case IP_FREEBIND:
2585#endif
2586 case IP_MULTICAST_TTL:
2587 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002588 if (get_user_u32(len, optlen))
2589 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002590 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002591 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002592 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002593 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2594 if (ret < 0)
2595 return ret;
bellard2efbe912005-07-23 15:10:20 +00002596 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002597 len = 1;
bellard2f619692007-11-16 10:46:05 +00002598 if (put_user_u32(len, optlen)
2599 || put_user_u8(val, optval_addr))
2600 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002601 } else {
bellard2efbe912005-07-23 15:10:20 +00002602 if (len > sizeof(int))
2603 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002604 if (put_user_u32(len, optlen)
2605 || put_user_u32(val, optval_addr))
2606 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002607 }
bellard8853f862004-02-22 14:57:26 +00002608 break;
bellard2efbe912005-07-23 15:10:20 +00002609 default:
thsc02f4992007-12-18 02:39:59 +00002610 ret = -TARGET_ENOPROTOOPT;
2611 break;
bellard8853f862004-02-22 14:57:26 +00002612 }
2613 break;
2614 default:
2615 unimplemented:
2616 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2617 level, optname);
thsc02f4992007-12-18 02:39:59 +00002618 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002619 break;
2620 }
2621 return ret;
bellard7854b052003-03-29 17:22:23 +00002622}
2623
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002624static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2625 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002626{
2627 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002628 struct iovec *vec;
2629 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002630 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002631 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002632 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002633
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002634 if (count == 0) {
2635 errno = 0;
2636 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002637 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002638 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002639 errno = EINVAL;
2640 return NULL;
2641 }
2642
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302643 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002644 if (vec == NULL) {
2645 errno = ENOMEM;
2646 return NULL;
2647 }
2648
2649 target_vec = lock_user(VERIFY_READ, target_addr,
2650 count * sizeof(struct target_iovec), 1);
2651 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002652 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002653 goto fail2;
2654 }
2655
2656 /* ??? If host page size > target page size, this will result in a
2657 value larger than what we can actually support. */
2658 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2659 total_len = 0;
2660
2661 for (i = 0; i < count; i++) {
2662 abi_ulong base = tswapal(target_vec[i].iov_base);
2663 abi_long len = tswapal(target_vec[i].iov_len);
2664
2665 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002666 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002667 goto fail;
2668 } else if (len == 0) {
2669 /* Zero length pointer is ignored. */
2670 vec[i].iov_base = 0;
2671 } else {
2672 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002673 /* If the first buffer pointer is bad, this is a fault. But
2674 * subsequent bad buffers will result in a partial write; this
2675 * is realized by filling the vector with null pointers and
2676 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002677 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002678 if (i == 0) {
2679 err = EFAULT;
2680 goto fail;
2681 } else {
2682 bad_address = true;
2683 }
2684 }
2685 if (bad_address) {
2686 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002687 }
2688 if (len > max_len - total_len) {
2689 len = max_len - total_len;
2690 }
2691 }
2692 vec[i].iov_len = len;
2693 total_len += len;
2694 }
2695
2696 unlock_user(target_vec, target_addr, 0);
2697 return vec;
2698
2699 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002700 while (--i >= 0) {
2701 if (tswapal(target_vec[i].iov_len) > 0) {
2702 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2703 }
2704 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002705 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002706 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302707 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002708 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002709 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002710}
2711
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002712static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2713 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002714{
2715 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002716 int i;
2717
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002718 target_vec = lock_user(VERIFY_READ, target_addr,
2719 count * sizeof(struct target_iovec), 1);
2720 if (target_vec) {
2721 for (i = 0; i < count; i++) {
2722 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002723 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002724 if (len < 0) {
2725 break;
2726 }
balrogd732dcb2008-10-28 10:21:03 +00002727 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2728 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002729 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002730 }
bellard579a97f2007-11-11 14:26:47 +00002731
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302732 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002733}
2734
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002735static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002736{
2737 int host_type = 0;
2738 int target_type = *type;
2739
2740 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2741 case TARGET_SOCK_DGRAM:
2742 host_type = SOCK_DGRAM;
2743 break;
2744 case TARGET_SOCK_STREAM:
2745 host_type = SOCK_STREAM;
2746 break;
2747 default:
2748 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2749 break;
2750 }
2751 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002752#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002753 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002754#else
2755 return -TARGET_EINVAL;
2756#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002757 }
2758 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002759#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002760 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002761#elif !defined(O_NONBLOCK)
2762 return -TARGET_EINVAL;
2763#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002764 }
2765 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002766 return 0;
2767}
2768
2769/* Try to emulate socket type flags after socket creation. */
2770static int sock_flags_fixup(int fd, int target_type)
2771{
2772#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2773 if (target_type & TARGET_SOCK_NONBLOCK) {
2774 int flags = fcntl(fd, F_GETFL);
2775 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2776 close(fd);
2777 return -TARGET_EINVAL;
2778 }
2779 }
2780#endif
2781 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002782}
2783
Laurent Vivier0cf22722015-10-28 21:40:45 +01002784static abi_long packet_target_to_host_sockaddr(void *host_addr,
2785 abi_ulong target_addr,
2786 socklen_t len)
2787{
2788 struct sockaddr *addr = host_addr;
2789 struct target_sockaddr *target_saddr;
2790
2791 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2792 if (!target_saddr) {
2793 return -TARGET_EFAULT;
2794 }
2795
2796 memcpy(addr, target_saddr, len);
2797 addr->sa_family = tswap16(target_saddr->sa_family);
2798 /* spkt_protocol is big-endian */
2799
2800 unlock_user(target_saddr, target_addr, 0);
2801 return 0;
2802}
2803
2804static TargetFdTrans target_packet_trans = {
2805 .target_to_host_addr = packet_target_to_host_sockaddr,
2806};
2807
Laurent Vivier575b22b2016-06-02 22:14:15 +02002808#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002809static abi_long netlink_route_target_to_host(void *buf, size_t len)
2810{
2811 return target_to_host_nlmsg_route(buf, len);
2812}
2813
2814static abi_long netlink_route_host_to_target(void *buf, size_t len)
2815{
2816 return host_to_target_nlmsg_route(buf, len);
2817}
2818
2819static TargetFdTrans target_netlink_route_trans = {
2820 .target_to_host_data = netlink_route_target_to_host,
2821 .host_to_target_data = netlink_route_host_to_target,
2822};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002823#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002824
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002825static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2826{
2827 return target_to_host_nlmsg_audit(buf, len);
2828}
2829
2830static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2831{
2832 return host_to_target_nlmsg_audit(buf, len);
2833}
2834
2835static TargetFdTrans target_netlink_audit_trans = {
2836 .target_to_host_data = netlink_audit_target_to_host,
2837 .host_to_target_data = netlink_audit_host_to_target,
2838};
2839
ths0da46a62007-10-20 20:23:07 +00002840/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002841static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002842{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002843 int target_type = type;
2844 int ret;
2845
2846 ret = target_to_host_sock_type(&type);
2847 if (ret) {
2848 return ret;
2849 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002850
Laurent Vivier575b22b2016-06-02 22:14:15 +02002851 if (domain == PF_NETLINK && !(
2852#ifdef CONFIG_RTNETLINK
2853 protocol == NETLINK_ROUTE ||
2854#endif
2855 protocol == NETLINK_KOBJECT_UEVENT ||
2856 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002857 return -EPFNOSUPPORT;
2858 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002859
2860 if (domain == AF_PACKET ||
2861 (domain == AF_INET && type == SOCK_PACKET)) {
2862 protocol = tswap16(protocol);
2863 }
2864
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002865 ret = get_errno(socket(domain, type, protocol));
2866 if (ret >= 0) {
2867 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002868 if (type == SOCK_PACKET) {
2869 /* Manage an obsolete case :
2870 * if socket type is SOCK_PACKET, bind by name
2871 */
2872 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002873 } else if (domain == PF_NETLINK) {
2874 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002875#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002876 case NETLINK_ROUTE:
2877 fd_trans_register(ret, &target_netlink_route_trans);
2878 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002879#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002880 case NETLINK_KOBJECT_UEVENT:
2881 /* nothing to do: messages are strings */
2882 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002883 case NETLINK_AUDIT:
2884 fd_trans_register(ret, &target_netlink_audit_trans);
2885 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002886 default:
2887 g_assert_not_reached();
2888 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002889 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002890 }
2891 return ret;
bellard3532fa72006-06-24 15:06:03 +00002892}
2893
ths0da46a62007-10-20 20:23:07 +00002894/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002895static abi_long do_bind(int sockfd, abi_ulong target_addr,
2896 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002897{
aurel328f7aeaf2009-01-30 19:47:57 +00002898 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002899 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002900
Blue Swirl38724252010-09-18 05:53:14 +00002901 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002902 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002903 }
aurel328f7aeaf2009-01-30 19:47:57 +00002904
aurel32607175e2009-04-15 16:11:59 +00002905 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002906
Laurent Vivier7b36f782015-10-28 21:40:44 +01002907 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002908 if (ret)
2909 return ret;
2910
bellard3532fa72006-06-24 15:06:03 +00002911 return get_errno(bind(sockfd, addr, addrlen));
2912}
2913
ths0da46a62007-10-20 20:23:07 +00002914/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002915static abi_long do_connect(int sockfd, abi_ulong target_addr,
2916 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002917{
aurel328f7aeaf2009-01-30 19:47:57 +00002918 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002919 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002920
Blue Swirl38724252010-09-18 05:53:14 +00002921 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002922 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002923 }
aurel328f7aeaf2009-01-30 19:47:57 +00002924
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002925 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002926
Laurent Vivier7b36f782015-10-28 21:40:44 +01002927 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002928 if (ret)
2929 return ret;
2930
Peter Maydell2a3c7612016-06-06 19:58:03 +01002931 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002932}
2933
Alexander Graff19e00d2014-03-02 19:36:42 +00002934/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2935static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2936 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002937{
balrog6de645c2008-10-28 10:26:29 +00002938 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002939 struct msghdr msg;
2940 int count;
2941 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002942 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002943
bellard3532fa72006-06-24 15:06:03 +00002944 if (msgp->msg_name) {
2945 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002946 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002947 ret = target_to_host_sockaddr(fd, msg.msg_name,
2948 tswapal(msgp->msg_name),
2949 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002950 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002951 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002952 }
bellard3532fa72006-06-24 15:06:03 +00002953 } else {
2954 msg.msg_name = NULL;
2955 msg.msg_namelen = 0;
2956 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002957 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002958 msg.msg_control = alloca(msg.msg_controllen);
2959 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002960
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002961 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002962 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002963 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2964 target_vec, count, send);
2965 if (vec == NULL) {
2966 ret = -host_to_target_errno(errno);
2967 goto out2;
2968 }
bellard3532fa72006-06-24 15:06:03 +00002969 msg.msg_iovlen = count;
2970 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002971
bellard3532fa72006-06-24 15:06:03 +00002972 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002973 if (fd_trans_target_to_host_data(fd)) {
2974 ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base,
2975 msg.msg_iov->iov_len);
2976 } else {
2977 ret = target_to_host_cmsg(&msg, msgp);
2978 }
2979 if (ret == 0) {
Peter Maydell66687532016-06-06 19:58:04 +01002980 ret = get_errno(safe_sendmsg(fd, &msg, flags));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002981 }
bellard3532fa72006-06-24 15:06:03 +00002982 } else {
Peter Maydell66687532016-06-06 19:58:04 +01002983 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002984 if (!is_error(ret)) {
2985 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002986 if (fd_trans_host_to_target_data(fd)) {
2987 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
2988 msg.msg_iov->iov_len);
2989 } else {
2990 ret = host_to_target_cmsg(msgp, &msg);
2991 }
Jing Huangca619062012-07-24 13:58:02 +00002992 if (!is_error(ret)) {
2993 msgp->msg_namelen = tswap32(msg.msg_namelen);
2994 if (msg.msg_name != NULL) {
2995 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2996 msg.msg_name, msg.msg_namelen);
2997 if (ret) {
2998 goto out;
2999 }
3000 }
3001
balrog6de645c2008-10-28 10:26:29 +00003002 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003003 }
balrog6de645c2008-10-28 10:26:29 +00003004 }
bellard3532fa72006-06-24 15:06:03 +00003005 }
Jing Huangca619062012-07-24 13:58:02 +00003006
3007out:
bellard3532fa72006-06-24 15:06:03 +00003008 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003009out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003010 return ret;
3011}
3012
3013static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3014 int flags, int send)
3015{
3016 abi_long ret;
3017 struct target_msghdr *msgp;
3018
3019 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3020 msgp,
3021 target_msg,
3022 send ? 1 : 0)) {
3023 return -TARGET_EFAULT;
3024 }
3025 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003026 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003027 return ret;
3028}
3029
Alexander Graff19e00d2014-03-02 19:36:42 +00003030/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3031 * so it might not have this *mmsg-specific flag either.
3032 */
3033#ifndef MSG_WAITFORONE
3034#define MSG_WAITFORONE 0x10000
3035#endif
3036
3037static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3038 unsigned int vlen, unsigned int flags,
3039 int send)
3040{
3041 struct target_mmsghdr *mmsgp;
3042 abi_long ret = 0;
3043 int i;
3044
3045 if (vlen > UIO_MAXIOV) {
3046 vlen = UIO_MAXIOV;
3047 }
3048
3049 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3050 if (!mmsgp) {
3051 return -TARGET_EFAULT;
3052 }
3053
3054 for (i = 0; i < vlen; i++) {
3055 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3056 if (is_error(ret)) {
3057 break;
3058 }
3059 mmsgp[i].msg_len = tswap32(ret);
3060 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3061 if (flags & MSG_WAITFORONE) {
3062 flags |= MSG_DONTWAIT;
3063 }
3064 }
3065
3066 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3067
3068 /* Return number of datagrams sent if we sent any at all;
3069 * otherwise return the error.
3070 */
3071 if (i) {
3072 return i;
3073 }
3074 return ret;
3075}
Alexander Graff19e00d2014-03-02 19:36:42 +00003076
Peter Maydella94b4982013-02-08 04:35:04 +00003077/* do_accept4() Must return target values and target errnos. */
3078static abi_long do_accept4(int fd, abi_ulong target_addr,
3079 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003080{
bellard2f619692007-11-16 10:46:05 +00003081 socklen_t addrlen;
3082 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003083 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003084 int host_flags;
3085
3086 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003087
Peter Maydella94b4982013-02-08 04:35:04 +00003088 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003089 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003090 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003091
3092 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003093 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003094 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003095
Blue Swirl38724252010-09-18 05:53:14 +00003096 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003097 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003098 }
aurel328f7aeaf2009-01-30 19:47:57 +00003099
Arnaud Patard917507b2009-06-19 10:44:45 +03003100 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3101 return -TARGET_EINVAL;
3102
bellard2f619692007-11-16 10:46:05 +00003103 addr = alloca(addrlen);
3104
Peter Maydellff6dc132016-06-06 19:58:13 +01003105 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003106 if (!is_error(ret)) {
3107 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003108 if (put_user_u32(addrlen, target_addrlen_addr))
3109 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003110 }
3111 return ret;
3112}
3113
ths0da46a62007-10-20 20:23:07 +00003114/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003115static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003116 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003117{
bellard2f619692007-11-16 10:46:05 +00003118 socklen_t addrlen;
3119 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003120 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003121
bellard2f619692007-11-16 10:46:05 +00003122 if (get_user_u32(addrlen, target_addrlen_addr))
3123 return -TARGET_EFAULT;
3124
Blue Swirl38724252010-09-18 05:53:14 +00003125 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003126 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003127 }
aurel328f7aeaf2009-01-30 19:47:57 +00003128
Arnaud Patard917507b2009-06-19 10:44:45 +03003129 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3130 return -TARGET_EFAULT;
3131
bellard2f619692007-11-16 10:46:05 +00003132 addr = alloca(addrlen);
3133
pbrook1be9e1d2006-11-19 15:26:04 +00003134 ret = get_errno(getpeername(fd, addr, &addrlen));
3135 if (!is_error(ret)) {
3136 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003137 if (put_user_u32(addrlen, target_addrlen_addr))
3138 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003139 }
3140 return ret;
3141}
3142
ths0da46a62007-10-20 20:23:07 +00003143/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003144static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003145 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003146{
bellard2f619692007-11-16 10:46:05 +00003147 socklen_t addrlen;
3148 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003149 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003150
bellard2f619692007-11-16 10:46:05 +00003151 if (get_user_u32(addrlen, target_addrlen_addr))
3152 return -TARGET_EFAULT;
3153
Blue Swirl38724252010-09-18 05:53:14 +00003154 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003155 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003156 }
aurel328f7aeaf2009-01-30 19:47:57 +00003157
Arnaud Patard917507b2009-06-19 10:44:45 +03003158 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3159 return -TARGET_EFAULT;
3160
bellard2f619692007-11-16 10:46:05 +00003161 addr = alloca(addrlen);
3162
pbrook1be9e1d2006-11-19 15:26:04 +00003163 ret = get_errno(getsockname(fd, addr, &addrlen));
3164 if (!is_error(ret)) {
3165 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003166 if (put_user_u32(addrlen, target_addrlen_addr))
3167 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003168 }
3169 return ret;
3170}
3171
ths0da46a62007-10-20 20:23:07 +00003172/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003173static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003174 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003175{
3176 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003177 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003178
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003179 target_to_host_sock_type(&type);
3180
pbrook1be9e1d2006-11-19 15:26:04 +00003181 ret = get_errno(socketpair(domain, type, protocol, tab));
3182 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003183 if (put_user_s32(tab[0], target_tab_addr)
3184 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3185 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003186 }
3187 return ret;
3188}
3189
ths0da46a62007-10-20 20:23:07 +00003190/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003191static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3192 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003193{
3194 void *addr;
3195 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003196 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003197
Blue Swirl38724252010-09-18 05:53:14 +00003198 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003199 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003200 }
aurel328f7aeaf2009-01-30 19:47:57 +00003201
bellard579a97f2007-11-11 14:26:47 +00003202 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3203 if (!host_msg)
3204 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003205 if (fd_trans_target_to_host_data(fd)) {
3206 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3207 if (ret < 0) {
3208 unlock_user(host_msg, msg, 0);
3209 return ret;
3210 }
3211 }
pbrook1be9e1d2006-11-19 15:26:04 +00003212 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003213 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003214 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003215 if (ret) {
3216 unlock_user(host_msg, msg, 0);
3217 return ret;
3218 }
Peter Maydell66687532016-06-06 19:58:04 +01003219 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003220 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003221 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003222 }
3223 unlock_user(host_msg, msg, 0);
3224 return ret;
3225}
3226
ths0da46a62007-10-20 20:23:07 +00003227/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003228static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3229 abi_ulong target_addr,
3230 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003231{
3232 socklen_t addrlen;
3233 void *addr;
3234 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003235 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003236
bellard579a97f2007-11-11 14:26:47 +00003237 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3238 if (!host_msg)
3239 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003240 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003241 if (get_user_u32(addrlen, target_addrlen)) {
3242 ret = -TARGET_EFAULT;
3243 goto fail;
3244 }
Blue Swirl38724252010-09-18 05:53:14 +00003245 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003246 ret = -TARGET_EINVAL;
3247 goto fail;
3248 }
pbrook1be9e1d2006-11-19 15:26:04 +00003249 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003250 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3251 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003252 } else {
3253 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003254 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003255 }
3256 if (!is_error(ret)) {
3257 if (target_addr) {
3258 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003259 if (put_user_u32(addrlen, target_addrlen)) {
3260 ret = -TARGET_EFAULT;
3261 goto fail;
3262 }
pbrook1be9e1d2006-11-19 15:26:04 +00003263 }
3264 unlock_user(host_msg, msg, len);
3265 } else {
bellard2f619692007-11-16 10:46:05 +00003266fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003267 unlock_user(host_msg, msg, 0);
3268 }
3269 return ret;
3270}
3271
j_mayer32407102007-09-26 23:01:49 +00003272#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003273/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003274static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003275{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003276 static const unsigned ac[] = { /* number of arguments per call */
3277 [SOCKOP_socket] = 3, /* domain, type, protocol */
3278 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3279 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3280 [SOCKOP_listen] = 2, /* sockfd, backlog */
3281 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3282 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3283 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3284 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3285 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3286 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3287 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3288 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3289 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3290 [SOCKOP_shutdown] = 2, /* sockfd, how */
3291 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3292 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003293 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3294 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003295 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3296 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3297 };
3298 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003299
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003300 /* first, collect the arguments in a[] according to ac[] */
3301 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3302 unsigned i;
3303 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3304 for (i = 0; i < ac[num]; ++i) {
3305 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003306 return -TARGET_EFAULT;
3307 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003308 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003309 }
bellard2f619692007-11-16 10:46:05 +00003310
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003311 /* now when we have the args, actually handle the call */
3312 switch (num) {
3313 case SOCKOP_socket: /* domain, type, protocol */
3314 return do_socket(a[0], a[1], a[2]);
3315 case SOCKOP_bind: /* sockfd, addr, addrlen */
3316 return do_bind(a[0], a[1], a[2]);
3317 case SOCKOP_connect: /* sockfd, addr, addrlen */
3318 return do_connect(a[0], a[1], a[2]);
3319 case SOCKOP_listen: /* sockfd, backlog */
3320 return get_errno(listen(a[0], a[1]));
3321 case SOCKOP_accept: /* sockfd, addr, addrlen */
3322 return do_accept4(a[0], a[1], a[2], 0);
3323 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3324 return do_accept4(a[0], a[1], a[2], a[3]);
3325 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3326 return do_getsockname(a[0], a[1], a[2]);
3327 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3328 return do_getpeername(a[0], a[1], a[2]);
3329 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3330 return do_socketpair(a[0], a[1], a[2], a[3]);
3331 case SOCKOP_send: /* sockfd, msg, len, flags */
3332 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3333 case SOCKOP_recv: /* sockfd, msg, len, flags */
3334 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3335 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3336 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3337 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3338 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3339 case SOCKOP_shutdown: /* sockfd, how */
3340 return get_errno(shutdown(a[0], a[1]));
3341 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3342 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3343 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3344 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003345 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3346 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3347 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3348 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003349 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3350 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3351 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3352 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003353 default:
3354 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003355 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003356 }
bellard31e31b82003-02-18 22:55:36 +00003357}
j_mayer32407102007-09-26 23:01:49 +00003358#endif
bellard31e31b82003-02-18 22:55:36 +00003359
bellard8853f862004-02-22 14:57:26 +00003360#define N_SHM_REGIONS 32
3361
3362static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003363 abi_ulong start;
3364 abi_ulong size;
3365 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003366} shm_regions[N_SHM_REGIONS];
3367
ths3eb6b042007-06-03 14:26:27 +00003368struct target_semid_ds
3369{
3370 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003371 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003372#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003373 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003374#endif
blueswir1992f48a2007-10-14 16:27:31 +00003375 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003376#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003377 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003378#endif
blueswir1992f48a2007-10-14 16:27:31 +00003379 abi_ulong sem_nsems;
3380 abi_ulong __unused3;
3381 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003382};
3383
bellard579a97f2007-11-11 14:26:47 +00003384static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3385 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003386{
3387 struct target_ipc_perm *target_ip;
3388 struct target_semid_ds *target_sd;
3389
bellard579a97f2007-11-11 14:26:47 +00003390 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3391 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003392 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003393 host_ip->__key = tswap32(target_ip->__key);
3394 host_ip->uid = tswap32(target_ip->uid);
3395 host_ip->gid = tswap32(target_ip->gid);
3396 host_ip->cuid = tswap32(target_ip->cuid);
3397 host_ip->cgid = tswap32(target_ip->cgid);
3398#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3399 host_ip->mode = tswap32(target_ip->mode);
3400#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003401 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003402#endif
3403#if defined(TARGET_PPC)
3404 host_ip->__seq = tswap32(target_ip->__seq);
3405#else
3406 host_ip->__seq = tswap16(target_ip->__seq);
3407#endif
ths3eb6b042007-06-03 14:26:27 +00003408 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003409 return 0;
ths3eb6b042007-06-03 14:26:27 +00003410}
3411
bellard579a97f2007-11-11 14:26:47 +00003412static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3413 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003414{
3415 struct target_ipc_perm *target_ip;
3416 struct target_semid_ds *target_sd;
3417
bellard579a97f2007-11-11 14:26:47 +00003418 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3419 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003420 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003421 target_ip->__key = tswap32(host_ip->__key);
3422 target_ip->uid = tswap32(host_ip->uid);
3423 target_ip->gid = tswap32(host_ip->gid);
3424 target_ip->cuid = tswap32(host_ip->cuid);
3425 target_ip->cgid = tswap32(host_ip->cgid);
3426#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3427 target_ip->mode = tswap32(host_ip->mode);
3428#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003429 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003430#endif
3431#if defined(TARGET_PPC)
3432 target_ip->__seq = tswap32(host_ip->__seq);
3433#else
3434 target_ip->__seq = tswap16(host_ip->__seq);
3435#endif
ths3eb6b042007-06-03 14:26:27 +00003436 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003437 return 0;
ths3eb6b042007-06-03 14:26:27 +00003438}
3439
bellard579a97f2007-11-11 14:26:47 +00003440static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3441 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003442{
3443 struct target_semid_ds *target_sd;
3444
bellard579a97f2007-11-11 14:26:47 +00003445 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3446 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003447 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3448 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003449 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3450 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3451 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003452 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003453 return 0;
ths3eb6b042007-06-03 14:26:27 +00003454}
3455
bellard579a97f2007-11-11 14:26:47 +00003456static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3457 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003458{
3459 struct target_semid_ds *target_sd;
3460
bellard579a97f2007-11-11 14:26:47 +00003461 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3462 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003463 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003464 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003465 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3466 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3467 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003468 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003469 return 0;
ths3eb6b042007-06-03 14:26:27 +00003470}
3471
aurel32e5289082009-04-18 16:16:12 +00003472struct target_seminfo {
3473 int semmap;
3474 int semmni;
3475 int semmns;
3476 int semmnu;
3477 int semmsl;
3478 int semopm;
3479 int semume;
3480 int semusz;
3481 int semvmx;
3482 int semaem;
3483};
3484
3485static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3486 struct seminfo *host_seminfo)
3487{
3488 struct target_seminfo *target_seminfo;
3489 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3490 return -TARGET_EFAULT;
3491 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3492 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3493 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3494 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3495 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3496 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3497 __put_user(host_seminfo->semume, &target_seminfo->semume);
3498 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3499 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3500 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3501 unlock_user_struct(target_seminfo, target_addr, 1);
3502 return 0;
3503}
3504
thsfa294812007-02-02 22:05:00 +00003505union semun {
3506 int val;
ths3eb6b042007-06-03 14:26:27 +00003507 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003508 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003509 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003510};
3511
ths3eb6b042007-06-03 14:26:27 +00003512union target_semun {
3513 int val;
aurel32e5289082009-04-18 16:16:12 +00003514 abi_ulong buf;
3515 abi_ulong array;
3516 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003517};
3518
aurel32e5289082009-04-18 16:16:12 +00003519static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3520 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003521{
aurel32e5289082009-04-18 16:16:12 +00003522 int nsems;
3523 unsigned short *array;
3524 union semun semun;
3525 struct semid_ds semid_ds;
3526 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003527
aurel32e5289082009-04-18 16:16:12 +00003528 semun.buf = &semid_ds;
3529
3530 ret = semctl(semid, 0, IPC_STAT, semun);
3531 if (ret == -1)
3532 return get_errno(ret);
3533
3534 nsems = semid_ds.sem_nsems;
3535
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303536 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003537 if (!*host_array) {
3538 return -TARGET_ENOMEM;
3539 }
aurel32e5289082009-04-18 16:16:12 +00003540 array = lock_user(VERIFY_READ, target_addr,
3541 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003542 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303543 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003544 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003545 }
aurel32e5289082009-04-18 16:16:12 +00003546
3547 for(i=0; i<nsems; i++) {
3548 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003549 }
aurel32e5289082009-04-18 16:16:12 +00003550 unlock_user(array, target_addr, 0);
3551
bellard579a97f2007-11-11 14:26:47 +00003552 return 0;
ths3eb6b042007-06-03 14:26:27 +00003553}
3554
aurel32e5289082009-04-18 16:16:12 +00003555static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3556 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003557{
aurel32e5289082009-04-18 16:16:12 +00003558 int nsems;
3559 unsigned short *array;
3560 union semun semun;
3561 struct semid_ds semid_ds;
3562 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003563
aurel32e5289082009-04-18 16:16:12 +00003564 semun.buf = &semid_ds;
3565
3566 ret = semctl(semid, 0, IPC_STAT, semun);
3567 if (ret == -1)
3568 return get_errno(ret);
3569
3570 nsems = semid_ds.sem_nsems;
3571
3572 array = lock_user(VERIFY_WRITE, target_addr,
3573 nsems*sizeof(unsigned short), 0);
3574 if (!array)
3575 return -TARGET_EFAULT;
3576
3577 for(i=0; i<nsems; i++) {
3578 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003579 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303580 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003581 unlock_user(array, target_addr, 1);
3582
bellard579a97f2007-11-11 14:26:47 +00003583 return 0;
ths3eb6b042007-06-03 14:26:27 +00003584}
3585
aurel32e5289082009-04-18 16:16:12 +00003586static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003587 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003588{
Stefan Weild1c002b2015-02-08 15:40:58 +01003589 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003590 union semun arg;
3591 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303592 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003593 struct seminfo seminfo;
3594 abi_long ret = -TARGET_EINVAL;
3595 abi_long err;
3596 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003597
3598 switch( cmd ) {
3599 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003600 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003601 /* In 64 bit cross-endian situations, we will erroneously pick up
3602 * the wrong half of the union for the "val" element. To rectify
3603 * this, the entire 8-byte structure is byteswapped, followed by
3604 * a swap of the 4 byte val field. In other cases, the data is
3605 * already in proper host byte order. */
3606 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3607 target_su.buf = tswapal(target_su.buf);
3608 arg.val = tswap32(target_su.val);
3609 } else {
3610 arg.val = target_su.val;
3611 }
aurel32e5289082009-04-18 16:16:12 +00003612 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003613 break;
3614 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003615 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003616 err = target_to_host_semarray(semid, &array, target_su.array);
3617 if (err)
3618 return err;
3619 arg.array = array;
3620 ret = get_errno(semctl(semid, semnum, cmd, arg));
3621 err = host_to_target_semarray(semid, target_su.array, &array);
3622 if (err)
3623 return err;
ths3eb6b042007-06-03 14:26:27 +00003624 break;
3625 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003626 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003627 case SEM_STAT:
3628 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3629 if (err)
3630 return err;
3631 arg.buf = &dsarg;
3632 ret = get_errno(semctl(semid, semnum, cmd, arg));
3633 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3634 if (err)
3635 return err;
ths3eb6b042007-06-03 14:26:27 +00003636 break;
aurel32e5289082009-04-18 16:16:12 +00003637 case IPC_INFO:
3638 case SEM_INFO:
3639 arg.__buf = &seminfo;
3640 ret = get_errno(semctl(semid, semnum, cmd, arg));
3641 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3642 if (err)
3643 return err;
3644 break;
3645 case IPC_RMID:
3646 case GETPID:
3647 case GETNCNT:
3648 case GETZCNT:
3649 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3650 break;
ths3eb6b042007-06-03 14:26:27 +00003651 }
3652
3653 return ret;
3654}
3655
aurel32e5289082009-04-18 16:16:12 +00003656struct target_sembuf {
3657 unsigned short sem_num;
3658 short sem_op;
3659 short sem_flg;
3660};
3661
3662static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3663 abi_ulong target_addr,
3664 unsigned nsops)
3665{
3666 struct target_sembuf *target_sembuf;
3667 int i;
3668
3669 target_sembuf = lock_user(VERIFY_READ, target_addr,
3670 nsops*sizeof(struct target_sembuf), 1);
3671 if (!target_sembuf)
3672 return -TARGET_EFAULT;
3673
3674 for(i=0; i<nsops; i++) {
3675 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3676 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3677 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3678 }
3679
3680 unlock_user(target_sembuf, target_addr, 0);
3681
3682 return 0;
3683}
3684
3685static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3686{
3687 struct sembuf sops[nsops];
3688
3689 if (target_to_host_sembuf(sops, ptr, nsops))
3690 return -TARGET_EFAULT;
3691
Peter Maydellffb7ee72016-06-06 19:58:12 +01003692 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00003693}
3694
ths1bc012f2007-06-03 14:27:49 +00003695struct target_msqid_ds
3696{
aurel321c54ff92008-10-13 21:08:44 +00003697 struct target_ipc_perm msg_perm;
3698 abi_ulong msg_stime;
3699#if TARGET_ABI_BITS == 32
3700 abi_ulong __unused1;
3701#endif
3702 abi_ulong msg_rtime;
3703#if TARGET_ABI_BITS == 32
3704 abi_ulong __unused2;
3705#endif
3706 abi_ulong msg_ctime;
3707#if TARGET_ABI_BITS == 32
3708 abi_ulong __unused3;
3709#endif
3710 abi_ulong __msg_cbytes;
3711 abi_ulong msg_qnum;
3712 abi_ulong msg_qbytes;
3713 abi_ulong msg_lspid;
3714 abi_ulong msg_lrpid;
3715 abi_ulong __unused4;
3716 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003717};
3718
bellard579a97f2007-11-11 14:26:47 +00003719static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3720 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003721{
3722 struct target_msqid_ds *target_md;
3723
bellard579a97f2007-11-11 14:26:47 +00003724 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3725 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003726 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3727 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003728 host_md->msg_stime = tswapal(target_md->msg_stime);
3729 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3730 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3731 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3732 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3733 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3734 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3735 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003736 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003737 return 0;
ths1bc012f2007-06-03 14:27:49 +00003738}
3739
bellard579a97f2007-11-11 14:26:47 +00003740static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3741 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003742{
3743 struct target_msqid_ds *target_md;
3744
bellard579a97f2007-11-11 14:26:47 +00003745 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3746 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003747 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3748 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003749 target_md->msg_stime = tswapal(host_md->msg_stime);
3750 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3751 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3752 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3753 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3754 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3755 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3756 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003757 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003758 return 0;
ths1bc012f2007-06-03 14:27:49 +00003759}
3760
aurel321c54ff92008-10-13 21:08:44 +00003761struct target_msginfo {
3762 int msgpool;
3763 int msgmap;
3764 int msgmax;
3765 int msgmnb;
3766 int msgmni;
3767 int msgssz;
3768 int msgtql;
3769 unsigned short int msgseg;
3770};
3771
3772static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3773 struct msginfo *host_msginfo)
3774{
3775 struct target_msginfo *target_msginfo;
3776 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3777 return -TARGET_EFAULT;
3778 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3779 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3780 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3781 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3782 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3783 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3784 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3785 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3786 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003787 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003788}
3789
3790static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003791{
3792 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003793 struct msginfo msginfo;
3794 abi_long ret = -TARGET_EINVAL;
3795
3796 cmd &= 0xff;
3797
3798 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003799 case IPC_STAT:
3800 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003801 case MSG_STAT:
3802 if (target_to_host_msqid_ds(&dsarg,ptr))
3803 return -TARGET_EFAULT;
3804 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3805 if (host_to_target_msqid_ds(ptr,&dsarg))
3806 return -TARGET_EFAULT;
3807 break;
3808 case IPC_RMID:
3809 ret = get_errno(msgctl(msgid, cmd, NULL));
3810 break;
3811 case IPC_INFO:
3812 case MSG_INFO:
3813 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3814 if (host_to_target_msginfo(ptr, &msginfo))
3815 return -TARGET_EFAULT;
3816 break;
ths1bc012f2007-06-03 14:27:49 +00003817 }
aurel321c54ff92008-10-13 21:08:44 +00003818
ths1bc012f2007-06-03 14:27:49 +00003819 return ret;
3820}
3821
3822struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003823 abi_long mtype;
3824 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003825};
3826
blueswir1992f48a2007-10-14 16:27:31 +00003827static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003828 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003829{
3830 struct target_msgbuf *target_mb;
3831 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003832 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003833
Tom Mustaedcc5f92014-08-12 13:53:37 -05003834 if (msgsz < 0) {
3835 return -TARGET_EINVAL;
3836 }
3837
bellard579a97f2007-11-11 14:26:47 +00003838 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3839 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303840 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003841 if (!host_mb) {
3842 unlock_user_struct(target_mb, msgp, 0);
3843 return -TARGET_ENOMEM;
3844 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003845 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003846 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01003847 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303848 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003849 unlock_user_struct(target_mb, msgp, 0);
3850
3851 return ret;
3852}
3853
blueswir1992f48a2007-10-14 16:27:31 +00003854static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003855 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003856 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003857{
3858 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003859 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003860 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003861 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003862
Peter Maydell99874f62016-05-20 19:00:56 +01003863 if (msgsz < 0) {
3864 return -TARGET_EINVAL;
3865 }
3866
bellard579a97f2007-11-11 14:26:47 +00003867 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3868 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003869
Peter Maydell415d8472016-05-20 19:00:57 +01003870 host_mb = g_try_malloc(msgsz + sizeof(long));
3871 if (!host_mb) {
3872 ret = -TARGET_ENOMEM;
3873 goto end;
3874 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01003875 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003876
bellard579a97f2007-11-11 14:26:47 +00003877 if (ret > 0) {
3878 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3879 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3880 if (!target_mtext) {
3881 ret = -TARGET_EFAULT;
3882 goto end;
3883 }
aurel321c54ff92008-10-13 21:08:44 +00003884 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003885 unlock_user(target_mtext, target_mtext_addr, ret);
3886 }
aurel321c54ff92008-10-13 21:08:44 +00003887
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003888 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003889
bellard579a97f2007-11-11 14:26:47 +00003890end:
3891 if (target_mb)
3892 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003893 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003894 return ret;
3895}
3896
Riku Voipio88a8c982009-04-03 10:42:00 +03003897static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3898 abi_ulong target_addr)
3899{
3900 struct target_shmid_ds *target_sd;
3901
3902 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3903 return -TARGET_EFAULT;
3904 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3905 return -TARGET_EFAULT;
3906 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3907 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3908 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3909 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3910 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3911 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3912 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3913 unlock_user_struct(target_sd, target_addr, 0);
3914 return 0;
3915}
3916
3917static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3918 struct shmid_ds *host_sd)
3919{
3920 struct target_shmid_ds *target_sd;
3921
3922 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3923 return -TARGET_EFAULT;
3924 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3925 return -TARGET_EFAULT;
3926 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3927 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3928 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3929 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3930 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3931 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3932 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3933 unlock_user_struct(target_sd, target_addr, 1);
3934 return 0;
3935}
3936
3937struct target_shminfo {
3938 abi_ulong shmmax;
3939 abi_ulong shmmin;
3940 abi_ulong shmmni;
3941 abi_ulong shmseg;
3942 abi_ulong shmall;
3943};
3944
3945static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3946 struct shminfo *host_shminfo)
3947{
3948 struct target_shminfo *target_shminfo;
3949 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3950 return -TARGET_EFAULT;
3951 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3952 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3953 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3954 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3955 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3956 unlock_user_struct(target_shminfo, target_addr, 1);
3957 return 0;
3958}
3959
3960struct target_shm_info {
3961 int used_ids;
3962 abi_ulong shm_tot;
3963 abi_ulong shm_rss;
3964 abi_ulong shm_swp;
3965 abi_ulong swap_attempts;
3966 abi_ulong swap_successes;
3967};
3968
3969static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3970 struct shm_info *host_shm_info)
3971{
3972 struct target_shm_info *target_shm_info;
3973 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3974 return -TARGET_EFAULT;
3975 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3976 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3977 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3978 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3979 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3980 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3981 unlock_user_struct(target_shm_info, target_addr, 1);
3982 return 0;
3983}
3984
3985static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3986{
3987 struct shmid_ds dsarg;
3988 struct shminfo shminfo;
3989 struct shm_info shm_info;
3990 abi_long ret = -TARGET_EINVAL;
3991
3992 cmd &= 0xff;
3993
3994 switch(cmd) {
3995 case IPC_STAT:
3996 case IPC_SET:
3997 case SHM_STAT:
3998 if (target_to_host_shmid_ds(&dsarg, buf))
3999 return -TARGET_EFAULT;
4000 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4001 if (host_to_target_shmid_ds(buf, &dsarg))
4002 return -TARGET_EFAULT;
4003 break;
4004 case IPC_INFO:
4005 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4006 if (host_to_target_shminfo(buf, &shminfo))
4007 return -TARGET_EFAULT;
4008 break;
4009 case SHM_INFO:
4010 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4011 if (host_to_target_shm_info(buf, &shm_info))
4012 return -TARGET_EFAULT;
4013 break;
4014 case IPC_RMID:
4015 case SHM_LOCK:
4016 case SHM_UNLOCK:
4017 ret = get_errno(shmctl(shmid, cmd, NULL));
4018 break;
4019 }
4020
4021 return ret;
4022}
4023
4024static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4025{
4026 abi_long raddr;
4027 void *host_raddr;
4028 struct shmid_ds shm_info;
4029 int i,ret;
4030
4031 /* find out the length of the shared memory segment */
4032 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4033 if (is_error(ret)) {
4034 /* can't get length, bail out */
4035 return ret;
4036 }
4037
4038 mmap_lock();
4039
4040 if (shmaddr)
4041 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4042 else {
4043 abi_ulong mmap_start;
4044
4045 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4046
4047 if (mmap_start == -1) {
4048 errno = ENOMEM;
4049 host_raddr = (void *)-1;
4050 } else
4051 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4052 }
4053
4054 if (host_raddr == (void *)-1) {
4055 mmap_unlock();
4056 return get_errno((long)host_raddr);
4057 }
4058 raddr=h2g((unsigned long)host_raddr);
4059
4060 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4061 PAGE_VALID | PAGE_READ |
4062 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4063
4064 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004065 if (!shm_regions[i].in_use) {
4066 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004067 shm_regions[i].start = raddr;
4068 shm_regions[i].size = shm_info.shm_segsz;
4069 break;
4070 }
4071 }
4072
4073 mmap_unlock();
4074 return raddr;
4075
4076}
4077
4078static inline abi_long do_shmdt(abi_ulong shmaddr)
4079{
4080 int i;
4081
4082 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004083 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4084 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004085 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004086 break;
4087 }
4088 }
4089
4090 return get_errno(shmdt(g2h(shmaddr)));
4091}
4092
aurel321c54ff92008-10-13 21:08:44 +00004093#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004094/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004095/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004096static abi_long do_ipc(unsigned int call, abi_long first,
4097 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004098 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004099{
4100 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004101 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004102
4103 version = call >> 16;
4104 call &= 0xffff;
4105
4106 switch (call) {
thsfa294812007-02-02 22:05:00 +00004107 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004108 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004109 break;
4110
4111 case IPCOP_semget:
4112 ret = get_errno(semget(first, second, third));
4113 break;
4114
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004115 case IPCOP_semctl: {
4116 /* The semun argument to semctl is passed by value, so dereference the
4117 * ptr argument. */
4118 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004119 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004120 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004121 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004122 }
thsd96372e2007-02-02 22:05:44 +00004123
aurel321c54ff92008-10-13 21:08:44 +00004124 case IPCOP_msgget:
4125 ret = get_errno(msgget(first, second));
4126 break;
thsd96372e2007-02-02 22:05:44 +00004127
aurel321c54ff92008-10-13 21:08:44 +00004128 case IPCOP_msgsnd:
4129 ret = do_msgsnd(first, ptr, second, third);
4130 break;
thsd96372e2007-02-02 22:05:44 +00004131
aurel321c54ff92008-10-13 21:08:44 +00004132 case IPCOP_msgctl:
4133 ret = do_msgctl(first, second, ptr);
4134 break;
thsd96372e2007-02-02 22:05:44 +00004135
aurel321c54ff92008-10-13 21:08:44 +00004136 case IPCOP_msgrcv:
4137 switch (version) {
4138 case 0:
4139 {
4140 struct target_ipc_kludge {
4141 abi_long msgp;
4142 abi_long msgtyp;
4143 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004144
aurel321c54ff92008-10-13 21:08:44 +00004145 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4146 ret = -TARGET_EFAULT;
4147 break;
ths1bc012f2007-06-03 14:27:49 +00004148 }
aurel321c54ff92008-10-13 21:08:44 +00004149
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004150 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004151
4152 unlock_user_struct(tmp, ptr, 0);
4153 break;
4154 }
4155 default:
4156 ret = do_msgrcv(first, ptr, second, fifth, third);
4157 }
4158 break;
thsd96372e2007-02-02 22:05:44 +00004159
bellard8853f862004-02-22 14:57:26 +00004160 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004161 switch (version) {
4162 default:
bellard5a4a8982007-11-11 17:39:18 +00004163 {
4164 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004165 raddr = do_shmat(first, ptr, second);
4166 if (is_error(raddr))
4167 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004168 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004169 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004170 break;
4171 }
4172 case 1:
4173 ret = -TARGET_EINVAL;
4174 break;
bellard5a4a8982007-11-11 17:39:18 +00004175 }
bellard8853f862004-02-22 14:57:26 +00004176 break;
4177 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004178 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004179 break;
4180
4181 case IPCOP_shmget:
4182 /* IPC_* flag values are the same on all linux platforms */
4183 ret = get_errno(shmget(first, second, third));
4184 break;
4185
4186 /* IPC_* and SHM_* command values are the same on all linux platforms */
4187 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004188 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004189 break;
4190 default:
j_mayer32407102007-09-26 23:01:49 +00004191 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004192 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004193 break;
4194 }
4195 return ret;
4196}
j_mayer32407102007-09-26 23:01:49 +00004197#endif
bellard8853f862004-02-22 14:57:26 +00004198
bellard31e31b82003-02-18 22:55:36 +00004199/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004200
Blue Swirl001faf32009-05-13 17:53:17 +00004201#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004202#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4203enum {
4204#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004205STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004206};
4207#undef STRUCT
4208#undef STRUCT_SPECIAL
4209
Blue Swirl001faf32009-05-13 17:53:17 +00004210#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004211#define STRUCT_SPECIAL(name)
4212#include "syscall_types.h"
4213#undef STRUCT
4214#undef STRUCT_SPECIAL
4215
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004216typedef struct IOCTLEntry IOCTLEntry;
4217
4218typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004219 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004220
4221struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004222 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004223 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004224 const char *name;
4225 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004226 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004227 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004228};
bellard31e31b82003-02-18 22:55:36 +00004229
4230#define IOC_R 0x0001
4231#define IOC_W 0x0002
4232#define IOC_RW (IOC_R | IOC_W)
4233
4234#define MAX_STRUCT_SIZE 4096
4235
Peter Maydelldace20d2011-01-10 13:11:24 +00004236#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004237/* So fiemap access checks don't overflow on 32 bit systems.
4238 * This is very slightly smaller than the limit imposed by
4239 * the underlying kernel.
4240 */
4241#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4242 / sizeof(struct fiemap_extent))
4243
4244static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004245 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004246{
4247 /* The parameter for this ioctl is a struct fiemap followed
4248 * by an array of struct fiemap_extent whose size is set
4249 * in fiemap->fm_extent_count. The array is filled in by the
4250 * ioctl.
4251 */
4252 int target_size_in, target_size_out;
4253 struct fiemap *fm;
4254 const argtype *arg_type = ie->arg_type;
4255 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4256 void *argptr, *p;
4257 abi_long ret;
4258 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4259 uint32_t outbufsz;
4260 int free_fm = 0;
4261
4262 assert(arg_type[0] == TYPE_PTR);
4263 assert(ie->access == IOC_RW);
4264 arg_type++;
4265 target_size_in = thunk_type_size(arg_type, 0);
4266 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4267 if (!argptr) {
4268 return -TARGET_EFAULT;
4269 }
4270 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4271 unlock_user(argptr, arg, 0);
4272 fm = (struct fiemap *)buf_temp;
4273 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4274 return -TARGET_EINVAL;
4275 }
4276
4277 outbufsz = sizeof (*fm) +
4278 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4279
4280 if (outbufsz > MAX_STRUCT_SIZE) {
4281 /* We can't fit all the extents into the fixed size buffer.
4282 * Allocate one that is large enough and use it instead.
4283 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304284 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004285 if (!fm) {
4286 return -TARGET_ENOMEM;
4287 }
4288 memcpy(fm, buf_temp, sizeof(struct fiemap));
4289 free_fm = 1;
4290 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004291 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004292 if (!is_error(ret)) {
4293 target_size_out = target_size_in;
4294 /* An extent_count of 0 means we were only counting the extents
4295 * so there are no structs to copy
4296 */
4297 if (fm->fm_extent_count != 0) {
4298 target_size_out += fm->fm_mapped_extents * extent_size;
4299 }
4300 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4301 if (!argptr) {
4302 ret = -TARGET_EFAULT;
4303 } else {
4304 /* Convert the struct fiemap */
4305 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4306 if (fm->fm_extent_count != 0) {
4307 p = argptr + target_size_in;
4308 /* ...and then all the struct fiemap_extents */
4309 for (i = 0; i < fm->fm_mapped_extents; i++) {
4310 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4311 THUNK_TARGET);
4312 p += extent_size;
4313 }
4314 }
4315 unlock_user(argptr, arg, target_size_out);
4316 }
4317 }
4318 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304319 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004320 }
4321 return ret;
4322}
Peter Maydelldace20d2011-01-10 13:11:24 +00004323#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004324
Laurent Vivier059c2f22011-03-30 00:12:12 +02004325static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004326 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004327{
4328 const argtype *arg_type = ie->arg_type;
4329 int target_size;
4330 void *argptr;
4331 int ret;
4332 struct ifconf *host_ifconf;
4333 uint32_t outbufsz;
4334 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4335 int target_ifreq_size;
4336 int nb_ifreq;
4337 int free_buf = 0;
4338 int i;
4339 int target_ifc_len;
4340 abi_long target_ifc_buf;
4341 int host_ifc_len;
4342 char *host_ifc_buf;
4343
4344 assert(arg_type[0] == TYPE_PTR);
4345 assert(ie->access == IOC_RW);
4346
4347 arg_type++;
4348 target_size = thunk_type_size(arg_type, 0);
4349
4350 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4351 if (!argptr)
4352 return -TARGET_EFAULT;
4353 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4354 unlock_user(argptr, arg, 0);
4355
4356 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4357 target_ifc_len = host_ifconf->ifc_len;
4358 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4359
4360 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4361 nb_ifreq = target_ifc_len / target_ifreq_size;
4362 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4363
4364 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4365 if (outbufsz > MAX_STRUCT_SIZE) {
4366 /* We can't fit all the extents into the fixed size buffer.
4367 * Allocate one that is large enough and use it instead.
4368 */
4369 host_ifconf = malloc(outbufsz);
4370 if (!host_ifconf) {
4371 return -TARGET_ENOMEM;
4372 }
4373 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4374 free_buf = 1;
4375 }
4376 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4377
4378 host_ifconf->ifc_len = host_ifc_len;
4379 host_ifconf->ifc_buf = host_ifc_buf;
4380
Peter Maydell49ca6f32016-06-06 19:58:14 +01004381 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004382 if (!is_error(ret)) {
4383 /* convert host ifc_len to target ifc_len */
4384
4385 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4386 target_ifc_len = nb_ifreq * target_ifreq_size;
4387 host_ifconf->ifc_len = target_ifc_len;
4388
4389 /* restore target ifc_buf */
4390
4391 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4392
4393 /* copy struct ifconf to target user */
4394
4395 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4396 if (!argptr)
4397 return -TARGET_EFAULT;
4398 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4399 unlock_user(argptr, arg, target_size);
4400
4401 /* copy ifreq[] to target user */
4402
4403 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4404 for (i = 0; i < nb_ifreq ; i++) {
4405 thunk_convert(argptr + i * target_ifreq_size,
4406 host_ifc_buf + i * sizeof(struct ifreq),
4407 ifreq_arg_type, THUNK_TARGET);
4408 }
4409 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4410 }
4411
4412 if (free_buf) {
4413 free(host_ifconf);
4414 }
4415
4416 return ret;
4417}
4418
Alexander Graf56e904e2012-01-31 18:42:06 +01004419static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004420 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004421{
4422 void *argptr;
4423 struct dm_ioctl *host_dm;
4424 abi_long guest_data;
4425 uint32_t guest_data_size;
4426 int target_size;
4427 const argtype *arg_type = ie->arg_type;
4428 abi_long ret;
4429 void *big_buf = NULL;
4430 char *host_data;
4431
4432 arg_type++;
4433 target_size = thunk_type_size(arg_type, 0);
4434 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4435 if (!argptr) {
4436 ret = -TARGET_EFAULT;
4437 goto out;
4438 }
4439 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4440 unlock_user(argptr, arg, 0);
4441
4442 /* buf_temp is too small, so fetch things into a bigger buffer */
4443 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4444 memcpy(big_buf, buf_temp, target_size);
4445 buf_temp = big_buf;
4446 host_dm = big_buf;
4447
4448 guest_data = arg + host_dm->data_start;
4449 if ((guest_data - arg) < 0) {
4450 ret = -EINVAL;
4451 goto out;
4452 }
4453 guest_data_size = host_dm->data_size - host_dm->data_start;
4454 host_data = (char*)host_dm + host_dm->data_start;
4455
4456 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4457 switch (ie->host_cmd) {
4458 case DM_REMOVE_ALL:
4459 case DM_LIST_DEVICES:
4460 case DM_DEV_CREATE:
4461 case DM_DEV_REMOVE:
4462 case DM_DEV_SUSPEND:
4463 case DM_DEV_STATUS:
4464 case DM_DEV_WAIT:
4465 case DM_TABLE_STATUS:
4466 case DM_TABLE_CLEAR:
4467 case DM_TABLE_DEPS:
4468 case DM_LIST_VERSIONS:
4469 /* no input data */
4470 break;
4471 case DM_DEV_RENAME:
4472 case DM_DEV_SET_GEOMETRY:
4473 /* data contains only strings */
4474 memcpy(host_data, argptr, guest_data_size);
4475 break;
4476 case DM_TARGET_MSG:
4477 memcpy(host_data, argptr, guest_data_size);
4478 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4479 break;
4480 case DM_TABLE_LOAD:
4481 {
4482 void *gspec = argptr;
4483 void *cur_data = host_data;
4484 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4485 int spec_size = thunk_type_size(arg_type, 0);
4486 int i;
4487
4488 for (i = 0; i < host_dm->target_count; i++) {
4489 struct dm_target_spec *spec = cur_data;
4490 uint32_t next;
4491 int slen;
4492
4493 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4494 slen = strlen((char*)gspec + spec_size) + 1;
4495 next = spec->next;
4496 spec->next = sizeof(*spec) + slen;
4497 strcpy((char*)&spec[1], gspec + spec_size);
4498 gspec += next;
4499 cur_data += spec->next;
4500 }
4501 break;
4502 }
4503 default:
4504 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004505 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004506 goto out;
4507 }
4508 unlock_user(argptr, guest_data, 0);
4509
Peter Maydell49ca6f32016-06-06 19:58:14 +01004510 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01004511 if (!is_error(ret)) {
4512 guest_data = arg + host_dm->data_start;
4513 guest_data_size = host_dm->data_size - host_dm->data_start;
4514 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4515 switch (ie->host_cmd) {
4516 case DM_REMOVE_ALL:
4517 case DM_DEV_CREATE:
4518 case DM_DEV_REMOVE:
4519 case DM_DEV_RENAME:
4520 case DM_DEV_SUSPEND:
4521 case DM_DEV_STATUS:
4522 case DM_TABLE_LOAD:
4523 case DM_TABLE_CLEAR:
4524 case DM_TARGET_MSG:
4525 case DM_DEV_SET_GEOMETRY:
4526 /* no return data */
4527 break;
4528 case DM_LIST_DEVICES:
4529 {
4530 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4531 uint32_t remaining_data = guest_data_size;
4532 void *cur_data = argptr;
4533 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4534 int nl_size = 12; /* can't use thunk_size due to alignment */
4535
4536 while (1) {
4537 uint32_t next = nl->next;
4538 if (next) {
4539 nl->next = nl_size + (strlen(nl->name) + 1);
4540 }
4541 if (remaining_data < nl->next) {
4542 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4543 break;
4544 }
4545 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4546 strcpy(cur_data + nl_size, nl->name);
4547 cur_data += nl->next;
4548 remaining_data -= nl->next;
4549 if (!next) {
4550 break;
4551 }
4552 nl = (void*)nl + next;
4553 }
4554 break;
4555 }
4556 case DM_DEV_WAIT:
4557 case DM_TABLE_STATUS:
4558 {
4559 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4560 void *cur_data = argptr;
4561 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4562 int spec_size = thunk_type_size(arg_type, 0);
4563 int i;
4564
4565 for (i = 0; i < host_dm->target_count; i++) {
4566 uint32_t next = spec->next;
4567 int slen = strlen((char*)&spec[1]) + 1;
4568 spec->next = (cur_data - argptr) + spec_size + slen;
4569 if (guest_data_size < spec->next) {
4570 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4571 break;
4572 }
4573 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4574 strcpy(cur_data + spec_size, (char*)&spec[1]);
4575 cur_data = argptr + spec->next;
4576 spec = (void*)host_dm + host_dm->data_start + next;
4577 }
4578 break;
4579 }
4580 case DM_TABLE_DEPS:
4581 {
4582 void *hdata = (void*)host_dm + host_dm->data_start;
4583 int count = *(uint32_t*)hdata;
4584 uint64_t *hdev = hdata + 8;
4585 uint64_t *gdev = argptr + 8;
4586 int i;
4587
4588 *(uint32_t*)argptr = tswap32(count);
4589 for (i = 0; i < count; i++) {
4590 *gdev = tswap64(*hdev);
4591 gdev++;
4592 hdev++;
4593 }
4594 break;
4595 }
4596 case DM_LIST_VERSIONS:
4597 {
4598 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4599 uint32_t remaining_data = guest_data_size;
4600 void *cur_data = argptr;
4601 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4602 int vers_size = thunk_type_size(arg_type, 0);
4603
4604 while (1) {
4605 uint32_t next = vers->next;
4606 if (next) {
4607 vers->next = vers_size + (strlen(vers->name) + 1);
4608 }
4609 if (remaining_data < vers->next) {
4610 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4611 break;
4612 }
4613 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4614 strcpy(cur_data + vers_size, vers->name);
4615 cur_data += vers->next;
4616 remaining_data -= vers->next;
4617 if (!next) {
4618 break;
4619 }
4620 vers = (void*)vers + next;
4621 }
4622 break;
4623 }
4624 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004625 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004626 ret = -TARGET_EINVAL;
4627 goto out;
4628 }
4629 unlock_user(argptr, guest_data, guest_data_size);
4630
4631 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4632 if (!argptr) {
4633 ret = -TARGET_EFAULT;
4634 goto out;
4635 }
4636 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4637 unlock_user(argptr, arg, target_size);
4638 }
4639out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004640 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004641 return ret;
4642}
4643
Alexander Grafa59b5e32014-08-22 13:15:50 +02004644static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004645 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004646{
4647 void *argptr;
4648 int target_size;
4649 const argtype *arg_type = ie->arg_type;
4650 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4651 abi_long ret;
4652
4653 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4654 struct blkpg_partition host_part;
4655
4656 /* Read and convert blkpg */
4657 arg_type++;
4658 target_size = thunk_type_size(arg_type, 0);
4659 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4660 if (!argptr) {
4661 ret = -TARGET_EFAULT;
4662 goto out;
4663 }
4664 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4665 unlock_user(argptr, arg, 0);
4666
4667 switch (host_blkpg->op) {
4668 case BLKPG_ADD_PARTITION:
4669 case BLKPG_DEL_PARTITION:
4670 /* payload is struct blkpg_partition */
4671 break;
4672 default:
4673 /* Unknown opcode */
4674 ret = -TARGET_EINVAL;
4675 goto out;
4676 }
4677
4678 /* Read and convert blkpg->data */
4679 arg = (abi_long)(uintptr_t)host_blkpg->data;
4680 target_size = thunk_type_size(part_arg_type, 0);
4681 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4682 if (!argptr) {
4683 ret = -TARGET_EFAULT;
4684 goto out;
4685 }
4686 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4687 unlock_user(argptr, arg, 0);
4688
4689 /* Swizzle the data pointer to our local copy and call! */
4690 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01004691 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02004692
4693out:
4694 return ret;
4695}
4696
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004697static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004698 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004699{
4700 const argtype *arg_type = ie->arg_type;
4701 const StructEntry *se;
4702 const argtype *field_types;
4703 const int *dst_offsets, *src_offsets;
4704 int target_size;
4705 void *argptr;
4706 abi_ulong *target_rt_dev_ptr;
4707 unsigned long *host_rt_dev_ptr;
4708 abi_long ret;
4709 int i;
4710
4711 assert(ie->access == IOC_W);
4712 assert(*arg_type == TYPE_PTR);
4713 arg_type++;
4714 assert(*arg_type == TYPE_STRUCT);
4715 target_size = thunk_type_size(arg_type, 0);
4716 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4717 if (!argptr) {
4718 return -TARGET_EFAULT;
4719 }
4720 arg_type++;
4721 assert(*arg_type == (int)STRUCT_rtentry);
4722 se = struct_entries + *arg_type++;
4723 assert(se->convert[0] == NULL);
4724 /* convert struct here to be able to catch rt_dev string */
4725 field_types = se->field_types;
4726 dst_offsets = se->field_offsets[THUNK_HOST];
4727 src_offsets = se->field_offsets[THUNK_TARGET];
4728 for (i = 0; i < se->nb_fields; i++) {
4729 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4730 assert(*field_types == TYPE_PTRVOID);
4731 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4732 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4733 if (*target_rt_dev_ptr != 0) {
4734 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4735 tswapal(*target_rt_dev_ptr));
4736 if (!*host_rt_dev_ptr) {
4737 unlock_user(argptr, arg, 0);
4738 return -TARGET_EFAULT;
4739 }
4740 } else {
4741 *host_rt_dev_ptr = 0;
4742 }
4743 field_types++;
4744 continue;
4745 }
4746 field_types = thunk_convert(buf_temp + dst_offsets[i],
4747 argptr + src_offsets[i],
4748 field_types, THUNK_HOST);
4749 }
4750 unlock_user(argptr, arg, 0);
4751
Peter Maydell49ca6f32016-06-06 19:58:14 +01004752 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004753 if (*host_rt_dev_ptr != 0) {
4754 unlock_user((void *)*host_rt_dev_ptr,
4755 *target_rt_dev_ptr, 0);
4756 }
4757 return ret;
4758}
4759
Paul Burtonca56f5b2014-06-22 11:25:47 +01004760static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004761 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004762{
4763 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004764 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01004765}
4766
blueswir19f106a72008-10-05 10:52:52 +00004767static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004768#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004769 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4770#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4771 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004772#include "ioctls.h"
4773 { 0, 0, },
4774};
4775
pbrook53a59602006-03-25 19:31:22 +00004776/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004777/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004778static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004779{
4780 const IOCTLEntry *ie;
4781 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004782 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004783 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004784 int target_size;
4785 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004786
4787 ie = ioctl_entries;
4788 for(;;) {
4789 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004790 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004791 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004792 }
4793 if (ie->target_cmd == cmd)
4794 break;
4795 ie++;
4796 }
4797 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004798#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004799 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004800#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004801 if (ie->do_ioctl) {
4802 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4803 }
4804
bellard31e31b82003-02-18 22:55:36 +00004805 switch(arg_type[0]) {
4806 case TYPE_NULL:
4807 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01004808 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00004809 break;
4810 case TYPE_PTRVOID:
4811 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004812 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00004813 break;
4814 case TYPE_PTR:
4815 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004816 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004817 switch(ie->access) {
4818 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004819 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004820 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004821 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4822 if (!argptr)
4823 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004824 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4825 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004826 }
4827 break;
4828 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004829 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4830 if (!argptr)
4831 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004832 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4833 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004834 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004835 break;
4836 default:
4837 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004838 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4839 if (!argptr)
4840 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004841 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4842 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004843 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004844 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004845 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4846 if (!argptr)
4847 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004848 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4849 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004850 }
4851 break;
4852 }
4853 break;
4854 default:
j_mayer32407102007-09-26 23:01:49 +00004855 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4856 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004857 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004858 break;
4859 }
4860 return ret;
4861}
4862
blueswir1b39bc502008-10-05 10:51:10 +00004863static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004864 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4865 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4866 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4867 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4868 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4869 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4870 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4871 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4872 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4873 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4874 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4875 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4876 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4877 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4878 { 0, 0, 0, 0 }
4879};
4880
blueswir1b39bc502008-10-05 10:51:10 +00004881static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004882 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4883 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4884 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4885 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4886 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4887 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4888 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4889 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4890 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4891 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4892 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4893 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4894 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4895 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4896 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4897 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4898 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4899 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4900 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4901 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4902 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4903 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4904 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4905 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4906 { 0, 0, 0, 0 }
4907};
4908
blueswir1b39bc502008-10-05 10:51:10 +00004909static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004910 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4911 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4912 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4913 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4914 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4915 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4916 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4917 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4918 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4919 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4920 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4921 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4922 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4923 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4924 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4925 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4926 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4927 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4928 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4929 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4930 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4931 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4932 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4933 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4934 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4935 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4936 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4937 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4938 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4939 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4940 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4941 { 0, 0, 0, 0 }
4942};
4943
blueswir1b39bc502008-10-05 10:51:10 +00004944static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004945 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4946 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4947 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4948 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4949 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4950 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4951 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4952 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4953 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4954 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4955 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4956 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4957 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4958 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4959 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4960 { 0, 0, 0, 0 }
4961};
4962
4963static void target_to_host_termios (void *dst, const void *src)
4964{
4965 struct host_termios *host = dst;
4966 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004967
ths5fafdf22007-09-16 21:08:06 +00004968 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004969 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004970 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004971 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004972 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004973 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004974 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004975 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4976 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004977
Arnaud Patard44607122009-04-21 17:39:08 +03004978 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004979 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4980 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004981 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004982 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004983 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004984 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004985 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004986 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004987 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004988 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4989 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004990 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4991 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4992 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4993 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4994 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004995 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004996}
ths3b46e622007-09-17 08:09:54 +00004997
bellard31e31b82003-02-18 22:55:36 +00004998static void host_to_target_termios (void *dst, const void *src)
4999{
5000 struct target_termios *target = dst;
5001 const struct host_termios *host = src;
5002
ths5fafdf22007-09-16 21:08:06 +00005003 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005004 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005005 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005006 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005007 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005008 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005009 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005010 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5011 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005012
Arnaud Patard44607122009-04-21 17:39:08 +03005013 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005014 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5015 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5016 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5017 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5018 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5019 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5020 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5021 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5022 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5023 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5024 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5025 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5026 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5027 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5028 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5029 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5030 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5031}
5032
blueswir18e853dc2008-10-05 10:49:32 +00005033static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005034 .convert = { host_to_target_termios, target_to_host_termios },
5035 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5036 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5037};
5038
bellard5286db72003-06-05 00:57:30 +00005039static bitmask_transtbl mmap_flags_tbl[] = {
5040 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5041 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5042 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5043 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5044 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5045 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5046 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5047 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005048 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5049 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005050 { 0, 0, 0, 0 }
5051};
5052
bellard2ab83ea2003-06-15 19:56:46 +00005053#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005054
5055/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005056static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005057
bellard03acab62007-11-11 14:57:14 +00005058static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005059{
5060 int size;
pbrook53a59602006-03-25 19:31:22 +00005061 void *p;
bellard6dbad632003-03-16 18:05:05 +00005062
5063 if (!ldt_table)
5064 return 0;
5065 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5066 if (size > bytecount)
5067 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005068 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5069 if (!p)
bellard03acab62007-11-11 14:57:14 +00005070 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005071 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005072 memcpy(p, ldt_table, size);
5073 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005074 return size;
5075}
5076
5077/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005078static abi_long write_ldt(CPUX86State *env,
5079 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005080{
5081 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005082 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005083 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005084 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005085 uint32_t *lp, entry_1, entry_2;
5086
5087 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005088 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005089 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005090 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005091 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005092 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005093 ldt_info.limit = tswap32(target_ldt_info->limit);
5094 ldt_info.flags = tswap32(target_ldt_info->flags);
5095 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005096
bellard6dbad632003-03-16 18:05:05 +00005097 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005098 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005099 seg_32bit = ldt_info.flags & 1;
5100 contents = (ldt_info.flags >> 1) & 3;
5101 read_exec_only = (ldt_info.flags >> 3) & 1;
5102 limit_in_pages = (ldt_info.flags >> 4) & 1;
5103 seg_not_present = (ldt_info.flags >> 5) & 1;
5104 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005105#ifdef TARGET_ABI32
5106 lm = 0;
5107#else
5108 lm = (ldt_info.flags >> 7) & 1;
5109#endif
bellard6dbad632003-03-16 18:05:05 +00005110 if (contents == 3) {
5111 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005112 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005113 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005114 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005115 }
5116 /* allocate the LDT */
5117 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005118 env->ldt.base = target_mmap(0,
5119 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5120 PROT_READ|PROT_WRITE,
5121 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5122 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005123 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005124 memset(g2h(env->ldt.base), 0,
5125 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005126 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005127 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005128 }
5129
5130 /* NOTE: same code as Linux kernel */
5131 /* Allow LDTs to be cleared by the user. */
5132 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5133 if (oldmode ||
5134 (contents == 0 &&
5135 read_exec_only == 1 &&
5136 seg_32bit == 0 &&
5137 limit_in_pages == 0 &&
5138 seg_not_present == 1 &&
5139 useable == 0 )) {
5140 entry_1 = 0;
5141 entry_2 = 0;
5142 goto install;
5143 }
5144 }
ths3b46e622007-09-17 08:09:54 +00005145
bellard6dbad632003-03-16 18:05:05 +00005146 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5147 (ldt_info.limit & 0x0ffff);
5148 entry_2 = (ldt_info.base_addr & 0xff000000) |
5149 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5150 (ldt_info.limit & 0xf0000) |
5151 ((read_exec_only ^ 1) << 9) |
5152 (contents << 10) |
5153 ((seg_not_present ^ 1) << 15) |
5154 (seg_32bit << 22) |
5155 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005156 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005157 0x7000;
5158 if (!oldmode)
5159 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005160
bellard6dbad632003-03-16 18:05:05 +00005161 /* Install the new entry ... */
5162install:
5163 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5164 lp[0] = tswap32(entry_1);
5165 lp[1] = tswap32(entry_2);
5166 return 0;
5167}
5168
5169/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005170static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5171 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005172{
bellard03acab62007-11-11 14:57:14 +00005173 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005174
bellard6dbad632003-03-16 18:05:05 +00005175 switch (func) {
5176 case 0:
5177 ret = read_ldt(ptr, bytecount);
5178 break;
5179 case 1:
5180 ret = write_ldt(env, ptr, bytecount, 1);
5181 break;
5182 case 0x11:
5183 ret = write_ldt(env, ptr, bytecount, 0);
5184 break;
bellard03acab62007-11-11 14:57:14 +00005185 default:
5186 ret = -TARGET_ENOSYS;
5187 break;
bellard6dbad632003-03-16 18:05:05 +00005188 }
5189 return ret;
5190}
bellard1b6b0292003-03-22 17:31:38 +00005191
blueswir14583f582008-08-24 10:35:55 +00005192#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005193abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005194{
5195 uint64_t *gdt_table = g2h(env->gdt.base);
5196 struct target_modify_ldt_ldt_s ldt_info;
5197 struct target_modify_ldt_ldt_s *target_ldt_info;
5198 int seg_32bit, contents, read_exec_only, limit_in_pages;
5199 int seg_not_present, useable, lm;
5200 uint32_t *lp, entry_1, entry_2;
5201 int i;
5202
5203 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5204 if (!target_ldt_info)
5205 return -TARGET_EFAULT;
5206 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005207 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005208 ldt_info.limit = tswap32(target_ldt_info->limit);
5209 ldt_info.flags = tswap32(target_ldt_info->flags);
5210 if (ldt_info.entry_number == -1) {
5211 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5212 if (gdt_table[i] == 0) {
5213 ldt_info.entry_number = i;
5214 target_ldt_info->entry_number = tswap32(i);
5215 break;
5216 }
5217 }
5218 }
5219 unlock_user_struct(target_ldt_info, ptr, 1);
5220
5221 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5222 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5223 return -TARGET_EINVAL;
5224 seg_32bit = ldt_info.flags & 1;
5225 contents = (ldt_info.flags >> 1) & 3;
5226 read_exec_only = (ldt_info.flags >> 3) & 1;
5227 limit_in_pages = (ldt_info.flags >> 4) & 1;
5228 seg_not_present = (ldt_info.flags >> 5) & 1;
5229 useable = (ldt_info.flags >> 6) & 1;
5230#ifdef TARGET_ABI32
5231 lm = 0;
5232#else
5233 lm = (ldt_info.flags >> 7) & 1;
5234#endif
5235
5236 if (contents == 3) {
5237 if (seg_not_present == 0)
5238 return -TARGET_EINVAL;
5239 }
5240
5241 /* NOTE: same code as Linux kernel */
5242 /* Allow LDTs to be cleared by the user. */
5243 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5244 if ((contents == 0 &&
5245 read_exec_only == 1 &&
5246 seg_32bit == 0 &&
5247 limit_in_pages == 0 &&
5248 seg_not_present == 1 &&
5249 useable == 0 )) {
5250 entry_1 = 0;
5251 entry_2 = 0;
5252 goto install;
5253 }
5254 }
5255
5256 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5257 (ldt_info.limit & 0x0ffff);
5258 entry_2 = (ldt_info.base_addr & 0xff000000) |
5259 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5260 (ldt_info.limit & 0xf0000) |
5261 ((read_exec_only ^ 1) << 9) |
5262 (contents << 10) |
5263 ((seg_not_present ^ 1) << 15) |
5264 (seg_32bit << 22) |
5265 (limit_in_pages << 23) |
5266 (useable << 20) |
5267 (lm << 21) |
5268 0x7000;
5269
5270 /* Install the new entry ... */
5271install:
5272 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5273 lp[0] = tswap32(entry_1);
5274 lp[1] = tswap32(entry_2);
5275 return 0;
5276}
5277
blueswir18fcd3692008-08-17 20:26:25 +00005278static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005279{
5280 struct target_modify_ldt_ldt_s *target_ldt_info;
5281 uint64_t *gdt_table = g2h(env->gdt.base);
5282 uint32_t base_addr, limit, flags;
5283 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5284 int seg_not_present, useable, lm;
5285 uint32_t *lp, entry_1, entry_2;
5286
5287 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5288 if (!target_ldt_info)
5289 return -TARGET_EFAULT;
5290 idx = tswap32(target_ldt_info->entry_number);
5291 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5292 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5293 unlock_user_struct(target_ldt_info, ptr, 1);
5294 return -TARGET_EINVAL;
5295 }
5296 lp = (uint32_t *)(gdt_table + idx);
5297 entry_1 = tswap32(lp[0]);
5298 entry_2 = tswap32(lp[1]);
5299
5300 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5301 contents = (entry_2 >> 10) & 3;
5302 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5303 seg_32bit = (entry_2 >> 22) & 1;
5304 limit_in_pages = (entry_2 >> 23) & 1;
5305 useable = (entry_2 >> 20) & 1;
5306#ifdef TARGET_ABI32
5307 lm = 0;
5308#else
5309 lm = (entry_2 >> 21) & 1;
5310#endif
5311 flags = (seg_32bit << 0) | (contents << 1) |
5312 (read_exec_only << 3) | (limit_in_pages << 4) |
5313 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5314 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5315 base_addr = (entry_1 >> 16) |
5316 (entry_2 & 0xff000000) |
5317 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005318 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005319 target_ldt_info->limit = tswap32(limit);
5320 target_ldt_info->flags = tswap32(flags);
5321 unlock_user_struct(target_ldt_info, ptr, 1);
5322 return 0;
5323}
blueswir14583f582008-08-24 10:35:55 +00005324#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005325
bellardd2fd1af2007-11-14 18:08:56 +00005326#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005327abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005328{
Juan Quintela1add8692011-06-16 17:37:09 +01005329 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005330 abi_ulong val;
5331 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005332
bellardd2fd1af2007-11-14 18:08:56 +00005333 switch(code) {
5334 case TARGET_ARCH_SET_GS:
5335 case TARGET_ARCH_SET_FS:
5336 if (code == TARGET_ARCH_SET_GS)
5337 idx = R_GS;
5338 else
5339 idx = R_FS;
5340 cpu_x86_load_seg(env, idx, 0);
5341 env->segs[idx].base = addr;
5342 break;
5343 case TARGET_ARCH_GET_GS:
5344 case TARGET_ARCH_GET_FS:
5345 if (code == TARGET_ARCH_GET_GS)
5346 idx = R_GS;
5347 else
5348 idx = R_FS;
5349 val = env->segs[idx].base;
5350 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005351 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005352 break;
5353 default:
5354 ret = -TARGET_EINVAL;
5355 break;
5356 }
Juan Quintela1add8692011-06-16 17:37:09 +01005357 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005358}
5359#endif
5360
bellard2ab83ea2003-06-15 19:56:46 +00005361#endif /* defined(TARGET_I386) */
5362
Riku Voipio05098a92011-03-04 15:27:29 +02005363#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005364
pbrookd865bab2008-06-07 22:12:17 +00005365
5366static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5367typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005368 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005369 pthread_mutex_t mutex;
5370 pthread_cond_t cond;
5371 pthread_t thread;
5372 uint32_t tid;
5373 abi_ulong child_tidptr;
5374 abi_ulong parent_tidptr;
5375 sigset_t sigmask;
5376} new_thread_info;
5377
5378static void *clone_func(void *arg)
5379{
5380 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005381 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005382 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005383 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005384
Emilio G. Cota70903762015-08-23 20:23:41 -04005385 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005386 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005387 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005388 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005389 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005390 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005391 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005392 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005393 if (info->child_tidptr)
5394 put_user_u32(info->tid, info->child_tidptr);
5395 if (info->parent_tidptr)
5396 put_user_u32(info->tid, info->parent_tidptr);
5397 /* Enable signals. */
5398 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5399 /* Signal to the parent that we're ready. */
5400 pthread_mutex_lock(&info->mutex);
5401 pthread_cond_broadcast(&info->cond);
5402 pthread_mutex_unlock(&info->mutex);
5403 /* Wait until the parent has finshed initializing the tls state. */
5404 pthread_mutex_lock(&clone_lock);
5405 pthread_mutex_unlock(&clone_lock);
5406 cpu_loop(env);
5407 /* never exits */
5408 return NULL;
5409}
bellard1b6b0292003-03-22 17:31:38 +00005410
ths0da46a62007-10-20 20:23:07 +00005411/* do_fork() Must return host values and target errnos (unlike most
5412 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005413static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005414 abi_ulong parent_tidptr, target_ulong newtls,
5415 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005416{
Andreas Färber0429a972013-08-26 18:14:44 +02005417 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005418 int ret;
bellard5cd43932003-03-29 16:54:36 +00005419 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005420 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005421 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005422 unsigned int nptl_flags;
5423 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005424
balrog436d1242008-09-21 02:39:45 +00005425 /* Emulate vfork() with fork() */
5426 if (flags & CLONE_VFORK)
5427 flags &= ~(CLONE_VFORK | CLONE_VM);
5428
bellard1b6b0292003-03-22 17:31:38 +00005429 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005430 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005431 new_thread_info info;
5432 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005433
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005434 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005435 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005436 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005437 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005438 /* Init regs that differ from the parent. */
5439 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005440 new_cpu = ENV_GET_CPU(new_env);
5441 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005442 ts->bprm = parent_ts->bprm;
5443 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005444 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005445 nptl_flags = flags;
5446 flags &= ~CLONE_NPTL_FLAGS2;
5447
pbrookc2764712009-03-07 15:24:59 +00005448 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5449 ts->child_tidptr = child_tidptr;
5450 }
5451
pbrookd865bab2008-06-07 22:12:17 +00005452 if (nptl_flags & CLONE_SETTLS)
5453 cpu_set_tls (new_env, newtls);
5454
5455 /* Grab a mutex so that thread setup appears atomic. */
5456 pthread_mutex_lock(&clone_lock);
5457
5458 memset(&info, 0, sizeof(info));
5459 pthread_mutex_init(&info.mutex, NULL);
5460 pthread_mutex_lock(&info.mutex);
5461 pthread_cond_init(&info.cond, NULL);
5462 info.env = new_env;
5463 if (nptl_flags & CLONE_CHILD_SETTID)
5464 info.child_tidptr = child_tidptr;
5465 if (nptl_flags & CLONE_PARENT_SETTID)
5466 info.parent_tidptr = parent_tidptr;
5467
5468 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005469 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5470 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005471 /* It is not safe to deliver signals until the child has finished
5472 initializing, so temporarily block all signals. */
5473 sigfillset(&sigmask);
5474 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5475
5476 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005477 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005478
5479 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5480 pthread_attr_destroy(&attr);
5481 if (ret == 0) {
5482 /* Wait for the child to initialize. */
5483 pthread_cond_wait(&info.cond, &info.mutex);
5484 ret = info.tid;
5485 if (flags & CLONE_PARENT_SETTID)
5486 put_user_u32(ret, parent_tidptr);
5487 } else {
5488 ret = -1;
5489 }
5490 pthread_mutex_unlock(&info.mutex);
5491 pthread_cond_destroy(&info.cond);
5492 pthread_mutex_destroy(&info.mutex);
5493 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005494 } else {
5495 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005496 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5497 return -TARGET_EINVAL;
5498 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005499
5500 if (block_signals()) {
5501 return -TARGET_ERESTARTSYS;
5502 }
5503
pbrookd865bab2008-06-07 22:12:17 +00005504 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005505 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005506 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005507 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005508 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005509 cpu_clone_regs(env, newsp);
5510 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005511 /* There is a race condition here. The parent process could
5512 theoretically read the TID in the child process before the child
5513 tid is set. This would require using either ptrace
5514 (not implemented) or having *_tidptr to point at a shared memory
5515 mapping. We can't repeat the spinlock hack used above because
5516 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005517 if (flags & CLONE_CHILD_SETTID)
5518 put_user_u32(gettid(), child_tidptr);
5519 if (flags & CLONE_PARENT_SETTID)
5520 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005521 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005522 if (flags & CLONE_SETTLS)
5523 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005524 if (flags & CLONE_CHILD_CLEARTID)
5525 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005526 } else {
5527 fork_end(0);
5528 }
bellard1b6b0292003-03-22 17:31:38 +00005529 }
5530 return ret;
5531}
5532
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005533/* warning : doesn't handle linux specific flags... */
5534static int target_to_host_fcntl_cmd(int cmd)
5535{
5536 switch(cmd) {
5537 case TARGET_F_DUPFD:
5538 case TARGET_F_GETFD:
5539 case TARGET_F_SETFD:
5540 case TARGET_F_GETFL:
5541 case TARGET_F_SETFL:
5542 return cmd;
5543 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005544 return F_GETLK64;
5545 case TARGET_F_SETLK:
5546 return F_SETLK64;
5547 case TARGET_F_SETLKW:
5548 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005549 case TARGET_F_GETOWN:
5550 return F_GETOWN;
5551 case TARGET_F_SETOWN:
5552 return F_SETOWN;
5553 case TARGET_F_GETSIG:
5554 return F_GETSIG;
5555 case TARGET_F_SETSIG:
5556 return F_SETSIG;
5557#if TARGET_ABI_BITS == 32
5558 case TARGET_F_GETLK64:
5559 return F_GETLK64;
5560 case TARGET_F_SETLK64:
5561 return F_SETLK64;
5562 case TARGET_F_SETLKW64:
5563 return F_SETLKW64;
5564#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005565 case TARGET_F_SETLEASE:
5566 return F_SETLEASE;
5567 case TARGET_F_GETLEASE:
5568 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005569#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005570 case TARGET_F_DUPFD_CLOEXEC:
5571 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005572#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005573 case TARGET_F_NOTIFY:
5574 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005575#ifdef F_GETOWN_EX
5576 case TARGET_F_GETOWN_EX:
5577 return F_GETOWN_EX;
5578#endif
5579#ifdef F_SETOWN_EX
5580 case TARGET_F_SETOWN_EX:
5581 return F_SETOWN_EX;
5582#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005583 default:
5584 return -TARGET_EINVAL;
5585 }
5586 return -TARGET_EINVAL;
5587}
5588
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005589#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5590static const bitmask_transtbl flock_tbl[] = {
5591 TRANSTBL_CONVERT(F_RDLCK),
5592 TRANSTBL_CONVERT(F_WRLCK),
5593 TRANSTBL_CONVERT(F_UNLCK),
5594 TRANSTBL_CONVERT(F_EXLCK),
5595 TRANSTBL_CONVERT(F_SHLCK),
5596 { 0, 0, 0, 0 }
5597};
5598
Peter Maydell213d3e92016-06-13 11:22:05 +01005599static inline abi_long copy_from_user_flock(struct flock64 *fl,
5600 abi_ulong target_flock_addr)
5601{
5602 struct target_flock *target_fl;
5603 short l_type;
5604
5605 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5606 return -TARGET_EFAULT;
5607 }
5608
5609 __get_user(l_type, &target_fl->l_type);
5610 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5611 __get_user(fl->l_whence, &target_fl->l_whence);
5612 __get_user(fl->l_start, &target_fl->l_start);
5613 __get_user(fl->l_len, &target_fl->l_len);
5614 __get_user(fl->l_pid, &target_fl->l_pid);
5615 unlock_user_struct(target_fl, target_flock_addr, 0);
5616 return 0;
5617}
5618
5619static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
5620 const struct flock64 *fl)
5621{
5622 struct target_flock *target_fl;
5623 short l_type;
5624
5625 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5626 return -TARGET_EFAULT;
5627 }
5628
5629 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5630 __put_user(l_type, &target_fl->l_type);
5631 __put_user(fl->l_whence, &target_fl->l_whence);
5632 __put_user(fl->l_start, &target_fl->l_start);
5633 __put_user(fl->l_len, &target_fl->l_len);
5634 __put_user(fl->l_pid, &target_fl->l_pid);
5635 unlock_user_struct(target_fl, target_flock_addr, 1);
5636 return 0;
5637}
5638
5639typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
5640typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
5641
5642#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
5643static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
5644 abi_ulong target_flock_addr)
5645{
5646 struct target_eabi_flock64 *target_fl;
5647 short l_type;
5648
5649 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5650 return -TARGET_EFAULT;
5651 }
5652
5653 __get_user(l_type, &target_fl->l_type);
5654 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5655 __get_user(fl->l_whence, &target_fl->l_whence);
5656 __get_user(fl->l_start, &target_fl->l_start);
5657 __get_user(fl->l_len, &target_fl->l_len);
5658 __get_user(fl->l_pid, &target_fl->l_pid);
5659 unlock_user_struct(target_fl, target_flock_addr, 0);
5660 return 0;
5661}
5662
5663static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
5664 const struct flock64 *fl)
5665{
5666 struct target_eabi_flock64 *target_fl;
5667 short l_type;
5668
5669 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5670 return -TARGET_EFAULT;
5671 }
5672
5673 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5674 __put_user(l_type, &target_fl->l_type);
5675 __put_user(fl->l_whence, &target_fl->l_whence);
5676 __put_user(fl->l_start, &target_fl->l_start);
5677 __put_user(fl->l_len, &target_fl->l_len);
5678 __put_user(fl->l_pid, &target_fl->l_pid);
5679 unlock_user_struct(target_fl, target_flock_addr, 1);
5680 return 0;
5681}
5682#endif
5683
5684static inline abi_long copy_from_user_flock64(struct flock64 *fl,
5685 abi_ulong target_flock_addr)
5686{
5687 struct target_flock64 *target_fl;
5688 short l_type;
5689
5690 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5691 return -TARGET_EFAULT;
5692 }
5693
5694 __get_user(l_type, &target_fl->l_type);
5695 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5696 __get_user(fl->l_whence, &target_fl->l_whence);
5697 __get_user(fl->l_start, &target_fl->l_start);
5698 __get_user(fl->l_len, &target_fl->l_len);
5699 __get_user(fl->l_pid, &target_fl->l_pid);
5700 unlock_user_struct(target_fl, target_flock_addr, 0);
5701 return 0;
5702}
5703
5704static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
5705 const struct flock64 *fl)
5706{
5707 struct target_flock64 *target_fl;
5708 short l_type;
5709
5710 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5711 return -TARGET_EFAULT;
5712 }
5713
5714 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5715 __put_user(l_type, &target_fl->l_type);
5716 __put_user(fl->l_whence, &target_fl->l_whence);
5717 __put_user(fl->l_start, &target_fl->l_start);
5718 __put_user(fl->l_len, &target_fl->l_len);
5719 __put_user(fl->l_pid, &target_fl->l_pid);
5720 unlock_user_struct(target_fl, target_flock_addr, 1);
5721 return 0;
5722}
5723
blueswir1992f48a2007-10-14 16:27:31 +00005724static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005725{
ths43f238d2007-01-05 20:55:49 +00005726 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005727#ifdef F_GETOWN_EX
5728 struct f_owner_ex fox;
5729 struct target_f_owner_ex *target_fox;
5730#endif
blueswir1992f48a2007-10-14 16:27:31 +00005731 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005732 int host_cmd = target_to_host_fcntl_cmd(cmd);
5733
5734 if (host_cmd == -TARGET_EINVAL)
5735 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005736
bellard7775e9e2003-05-14 22:46:48 +00005737 switch(cmd) {
5738 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005739 ret = copy_from_user_flock(&fl64, arg);
5740 if (ret) {
5741 return ret;
5742 }
5743 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005744 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005745 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00005746 }
5747 break;
ths3b46e622007-09-17 08:09:54 +00005748
bellard7775e9e2003-05-14 22:46:48 +00005749 case TARGET_F_SETLK:
5750 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01005751 ret = copy_from_user_flock(&fl64, arg);
5752 if (ret) {
5753 return ret;
5754 }
5755 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005756 break;
ths3b46e622007-09-17 08:09:54 +00005757
bellard7775e9e2003-05-14 22:46:48 +00005758 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005759 ret = copy_from_user_flock64(&fl64, arg);
5760 if (ret) {
5761 return ret;
5762 }
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005763 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005764 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005765 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00005766 }
bellard9ee1fa22007-11-11 15:11:19 +00005767 break;
bellard7775e9e2003-05-14 22:46:48 +00005768 case TARGET_F_SETLK64:
5769 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005770 ret = copy_from_user_flock64(&fl64, arg);
5771 if (ret) {
5772 return ret;
5773 }
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005774 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005775 break;
5776
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005777 case TARGET_F_GETFL:
5778 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005779 if (ret >= 0) {
5780 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5781 }
bellardffa65c32004-01-04 23:57:22 +00005782 break;
5783
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005784 case TARGET_F_SETFL:
5785 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
5786 break;
5787
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005788#ifdef F_GETOWN_EX
5789 case TARGET_F_GETOWN_EX:
5790 ret = get_errno(fcntl(fd, host_cmd, &fox));
5791 if (ret >= 0) {
5792 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5793 return -TARGET_EFAULT;
5794 target_fox->type = tswap32(fox.type);
5795 target_fox->pid = tswap32(fox.pid);
5796 unlock_user_struct(target_fox, arg, 1);
5797 }
5798 break;
5799#endif
5800
5801#ifdef F_SETOWN_EX
5802 case TARGET_F_SETOWN_EX:
5803 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5804 return -TARGET_EFAULT;
5805 fox.type = tswap32(target_fox->type);
5806 fox.pid = tswap32(target_fox->pid);
5807 unlock_user_struct(target_fox, arg, 0);
5808 ret = get_errno(fcntl(fd, host_cmd, &fox));
5809 break;
5810#endif
5811
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005812 case TARGET_F_SETOWN:
5813 case TARGET_F_GETOWN:
5814 case TARGET_F_SETSIG:
5815 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005816 case TARGET_F_SETLEASE:
5817 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005818 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005819 break;
5820
bellard7775e9e2003-05-14 22:46:48 +00005821 default:
bellard9ee1fa22007-11-11 15:11:19 +00005822 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005823 break;
5824 }
5825 return ret;
5826}
5827
bellard67867302003-11-23 17:05:30 +00005828#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005829
bellard67867302003-11-23 17:05:30 +00005830static inline int high2lowuid(int uid)
5831{
5832 if (uid > 65535)
5833 return 65534;
5834 else
5835 return uid;
5836}
5837
5838static inline int high2lowgid(int gid)
5839{
5840 if (gid > 65535)
5841 return 65534;
5842 else
5843 return gid;
5844}
5845
5846static inline int low2highuid(int uid)
5847{
5848 if ((int16_t)uid == -1)
5849 return -1;
5850 else
5851 return uid;
5852}
5853
5854static inline int low2highgid(int gid)
5855{
5856 if ((int16_t)gid == -1)
5857 return -1;
5858 else
5859 return gid;
5860}
Riku Voipio0c866a72011-04-18 15:23:06 +03005861static inline int tswapid(int id)
5862{
5863 return tswap16(id);
5864}
Peter Maydell76ca3102014-03-02 19:36:41 +00005865
5866#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5867
Riku Voipio0c866a72011-04-18 15:23:06 +03005868#else /* !USE_UID16 */
5869static inline int high2lowuid(int uid)
5870{
5871 return uid;
5872}
5873static inline int high2lowgid(int gid)
5874{
5875 return gid;
5876}
5877static inline int low2highuid(int uid)
5878{
5879 return uid;
5880}
5881static inline int low2highgid(int gid)
5882{
5883 return gid;
5884}
5885static inline int tswapid(int id)
5886{
5887 return tswap32(id);
5888}
Peter Maydell76ca3102014-03-02 19:36:41 +00005889
5890#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5891
bellard67867302003-11-23 17:05:30 +00005892#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005893
Peter Maydellfd6f7792016-03-01 16:33:02 +00005894/* We must do direct syscalls for setting UID/GID, because we want to
5895 * implement the Linux system call semantics of "change only for this thread",
5896 * not the libc/POSIX semantics of "change for all threads in process".
5897 * (See http://ewontfix.com/17/ for more details.)
5898 * We use the 32-bit version of the syscalls if present; if it is not
5899 * then either the host architecture supports 32-bit UIDs natively with
5900 * the standard syscall, or the 16-bit UID is the best we can do.
5901 */
5902#ifdef __NR_setuid32
5903#define __NR_sys_setuid __NR_setuid32
5904#else
5905#define __NR_sys_setuid __NR_setuid
5906#endif
5907#ifdef __NR_setgid32
5908#define __NR_sys_setgid __NR_setgid32
5909#else
5910#define __NR_sys_setgid __NR_setgid
5911#endif
5912#ifdef __NR_setresuid32
5913#define __NR_sys_setresuid __NR_setresuid32
5914#else
5915#define __NR_sys_setresuid __NR_setresuid
5916#endif
5917#ifdef __NR_setresgid32
5918#define __NR_sys_setresgid __NR_setresgid32
5919#else
5920#define __NR_sys_setresgid __NR_setresgid
5921#endif
5922
5923_syscall1(int, sys_setuid, uid_t, uid)
5924_syscall1(int, sys_setgid, gid_t, gid)
5925_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
5926_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
5927
bellard31e31b82003-02-18 22:55:36 +00005928void syscall_init(void)
5929{
bellard2ab83ea2003-06-15 19:56:46 +00005930 IOCTLEntry *ie;
5931 const argtype *arg_type;
5932 int size;
thsb92c47c2007-11-01 00:07:38 +00005933 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005934
Alexander Graf8be656b2015-05-06 23:47:32 +02005935 thunk_init(STRUCT_MAX);
5936
Blue Swirl001faf32009-05-13 17:53:17 +00005937#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005938#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005939#include "syscall_types.h"
5940#undef STRUCT
5941#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005942
Peter Maydelldd6e9572012-07-23 08:07:22 +00005943 /* Build target_to_host_errno_table[] table from
5944 * host_to_target_errno_table[]. */
5945 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5946 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5947 }
5948
bellard2ab83ea2003-06-15 19:56:46 +00005949 /* we patch the ioctl size if necessary. We rely on the fact that
5950 no ioctl has all the bits at '1' in the size field */
5951 ie = ioctl_entries;
5952 while (ie->target_cmd != 0) {
5953 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5954 TARGET_IOC_SIZEMASK) {
5955 arg_type = ie->arg_type;
5956 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005957 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005958 ie->target_cmd);
5959 exit(1);
5960 }
5961 arg_type++;
5962 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005963 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005964 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5965 (size << TARGET_IOC_SIZESHIFT);
5966 }
thsb92c47c2007-11-01 00:07:38 +00005967
bellard2ab83ea2003-06-15 19:56:46 +00005968 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005969#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5970 (defined(__x86_64__) && defined(TARGET_X86_64))
5971 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5972 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5973 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005974 }
5975#endif
5976 ie++;
5977 }
bellard31e31b82003-02-18 22:55:36 +00005978}
bellardc573ff62004-01-04 15:51:36 +00005979
blueswir1992f48a2007-10-14 16:27:31 +00005980#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005981static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5982{
thsaf325d32008-06-10 15:29:15 +00005983#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005984 return ((uint64_t)word0 << 32) | word1;
5985#else
5986 return ((uint64_t)word1 << 32) | word0;
5987#endif
5988}
blueswir1992f48a2007-10-14 16:27:31 +00005989#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005990static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5991{
5992 return word0;
5993}
blueswir1992f48a2007-10-14 16:27:31 +00005994#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005995
5996#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005997static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5998 abi_long arg2,
5999 abi_long arg3,
6000 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006001{
Riku Voipio48e515d2011-07-12 15:40:51 +03006002 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006003 arg2 = arg3;
6004 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006005 }
pbrookce4defa2006-02-09 16:49:55 +00006006 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6007}
6008#endif
6009
6010#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006011static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6012 abi_long arg2,
6013 abi_long arg3,
6014 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006015{
Riku Voipio48e515d2011-07-12 15:40:51 +03006016 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006017 arg2 = arg3;
6018 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006019 }
pbrookce4defa2006-02-09 16:49:55 +00006020 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6021}
6022#endif
6023
bellard579a97f2007-11-11 14:26:47 +00006024static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6025 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006026{
6027 struct target_timespec *target_ts;
6028
bellard579a97f2007-11-11 14:26:47 +00006029 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6030 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006031 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6032 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006033 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006034 return 0;
pbrook53a59602006-03-25 19:31:22 +00006035}
6036
bellard579a97f2007-11-11 14:26:47 +00006037static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6038 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006039{
6040 struct target_timespec *target_ts;
6041
bellard579a97f2007-11-11 14:26:47 +00006042 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6043 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006044 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6045 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006046 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006047 return 0;
pbrook53a59602006-03-25 19:31:22 +00006048}
6049
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006050static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6051 abi_ulong target_addr)
6052{
6053 struct target_itimerspec *target_itspec;
6054
6055 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6056 return -TARGET_EFAULT;
6057 }
6058
6059 host_itspec->it_interval.tv_sec =
6060 tswapal(target_itspec->it_interval.tv_sec);
6061 host_itspec->it_interval.tv_nsec =
6062 tswapal(target_itspec->it_interval.tv_nsec);
6063 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6064 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6065
6066 unlock_user_struct(target_itspec, target_addr, 1);
6067 return 0;
6068}
6069
6070static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6071 struct itimerspec *host_its)
6072{
6073 struct target_itimerspec *target_itspec;
6074
6075 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6076 return -TARGET_EFAULT;
6077 }
6078
6079 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6080 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6081
6082 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6083 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6084
6085 unlock_user_struct(target_itspec, target_addr, 0);
6086 return 0;
6087}
6088
Peter Maydellc0659762014-08-09 15:42:32 +01006089static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6090 abi_ulong target_addr)
6091{
6092 struct target_sigevent *target_sevp;
6093
6094 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6095 return -TARGET_EFAULT;
6096 }
6097
6098 /* This union is awkward on 64 bit systems because it has a 32 bit
6099 * integer and a pointer in it; we follow the conversion approach
6100 * used for handling sigval types in signal.c so the guest should get
6101 * the correct value back even if we did a 64 bit byteswap and it's
6102 * using the 32 bit integer.
6103 */
6104 host_sevp->sigev_value.sival_ptr =
6105 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6106 host_sevp->sigev_signo =
6107 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6108 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6109 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6110
6111 unlock_user_struct(target_sevp, target_addr, 1);
6112 return 0;
6113}
6114
Tom Musta6f6a4032014-08-12 13:53:42 -05006115#if defined(TARGET_NR_mlockall)
6116static inline int target_to_host_mlockall_arg(int arg)
6117{
6118 int result = 0;
6119
6120 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6121 result |= MCL_CURRENT;
6122 }
6123 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6124 result |= MCL_FUTURE;
6125 }
6126 return result;
6127}
6128#endif
6129
balrog6a24a772008-09-20 02:23:36 +00006130static inline abi_long host_to_target_stat64(void *cpu_env,
6131 abi_ulong target_addr,
6132 struct stat *host_st)
6133{
Alexander Graf09701192013-09-03 20:12:15 +01006134#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006135 if (((CPUARMState *)cpu_env)->eabi) {
6136 struct target_eabi_stat64 *target_st;
6137
6138 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6139 return -TARGET_EFAULT;
6140 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6141 __put_user(host_st->st_dev, &target_st->st_dev);
6142 __put_user(host_st->st_ino, &target_st->st_ino);
6143#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6144 __put_user(host_st->st_ino, &target_st->__st_ino);
6145#endif
6146 __put_user(host_st->st_mode, &target_st->st_mode);
6147 __put_user(host_st->st_nlink, &target_st->st_nlink);
6148 __put_user(host_st->st_uid, &target_st->st_uid);
6149 __put_user(host_st->st_gid, &target_st->st_gid);
6150 __put_user(host_st->st_rdev, &target_st->st_rdev);
6151 __put_user(host_st->st_size, &target_st->st_size);
6152 __put_user(host_st->st_blksize, &target_st->st_blksize);
6153 __put_user(host_st->st_blocks, &target_st->st_blocks);
6154 __put_user(host_st->st_atime, &target_st->target_st_atime);
6155 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6156 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6157 unlock_user_struct(target_st, target_addr, 1);
6158 } else
6159#endif
6160 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006161#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006162 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006163#else
6164 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006165#endif
balrog6a24a772008-09-20 02:23:36 +00006166
6167 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6168 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006169 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006170 __put_user(host_st->st_dev, &target_st->st_dev);
6171 __put_user(host_st->st_ino, &target_st->st_ino);
6172#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6173 __put_user(host_st->st_ino, &target_st->__st_ino);
6174#endif
6175 __put_user(host_st->st_mode, &target_st->st_mode);
6176 __put_user(host_st->st_nlink, &target_st->st_nlink);
6177 __put_user(host_st->st_uid, &target_st->st_uid);
6178 __put_user(host_st->st_gid, &target_st->st_gid);
6179 __put_user(host_st->st_rdev, &target_st->st_rdev);
6180 /* XXX: better use of kernel struct */
6181 __put_user(host_st->st_size, &target_st->st_size);
6182 __put_user(host_st->st_blksize, &target_st->st_blksize);
6183 __put_user(host_st->st_blocks, &target_st->st_blocks);
6184 __put_user(host_st->st_atime, &target_st->target_st_atime);
6185 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6186 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6187 unlock_user_struct(target_st, target_addr, 1);
6188 }
6189
6190 return 0;
6191}
balrog6a24a772008-09-20 02:23:36 +00006192
pbrookbd0c5662008-05-29 14:34:11 +00006193/* ??? Using host futex calls even when target atomic operations
6194 are not really atomic probably breaks things. However implementing
6195 futexes locally would make futexes shared between multiple processes
6196 tricky. However they're probably useless because guest atomic
6197 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006198static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6199 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006200{
6201 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006202 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006203
6204 /* ??? We assume FUTEX_* constants are the same on both host
6205 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006206#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006207 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006208#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006209 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006210#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006211 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006212 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006213 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006214 if (timeout) {
6215 pts = &ts;
6216 target_to_host_timespec(pts, timeout);
6217 } else {
6218 pts = NULL;
6219 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006220 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006221 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006222 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006223 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006224 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006225 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006226 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006227 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006228 case FUTEX_WAKE_OP:
6229 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6230 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6231 But the prototype takes a `struct timespec *'; insert casts
6232 to satisfy the compiler. We do not need to tswap TIMEOUT
6233 since it's not compared to guest memory. */
6234 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006235 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6236 g2h(uaddr2),
6237 (base_op == FUTEX_CMP_REQUEUE
6238 ? tswap32(val3)
6239 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006240 default:
6241 return -TARGET_ENOSYS;
6242 }
6243}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006244#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6245static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6246 abi_long handle, abi_long mount_id,
6247 abi_long flags)
6248{
6249 struct file_handle *target_fh;
6250 struct file_handle *fh;
6251 int mid = 0;
6252 abi_long ret;
6253 char *name;
6254 unsigned int size, total_size;
6255
6256 if (get_user_s32(size, handle)) {
6257 return -TARGET_EFAULT;
6258 }
6259
6260 name = lock_user_string(pathname);
6261 if (!name) {
6262 return -TARGET_EFAULT;
6263 }
6264
6265 total_size = sizeof(struct file_handle) + size;
6266 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6267 if (!target_fh) {
6268 unlock_user(name, pathname, 0);
6269 return -TARGET_EFAULT;
6270 }
6271
6272 fh = g_malloc0(total_size);
6273 fh->handle_bytes = size;
6274
6275 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6276 unlock_user(name, pathname, 0);
6277
6278 /* man name_to_handle_at(2):
6279 * Other than the use of the handle_bytes field, the caller should treat
6280 * the file_handle structure as an opaque data type
6281 */
6282
6283 memcpy(target_fh, fh, total_size);
6284 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6285 target_fh->handle_type = tswap32(fh->handle_type);
6286 g_free(fh);
6287 unlock_user(target_fh, handle, total_size);
6288
6289 if (put_user_s32(mid, mount_id)) {
6290 return -TARGET_EFAULT;
6291 }
6292
6293 return ret;
6294
6295}
6296#endif
6297
6298#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6299static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6300 abi_long flags)
6301{
6302 struct file_handle *target_fh;
6303 struct file_handle *fh;
6304 unsigned int size, total_size;
6305 abi_long ret;
6306
6307 if (get_user_s32(size, handle)) {
6308 return -TARGET_EFAULT;
6309 }
6310
6311 total_size = sizeof(struct file_handle) + size;
6312 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6313 if (!target_fh) {
6314 return -TARGET_EFAULT;
6315 }
6316
Thomas Huthe9d49d52015-10-09 17:56:38 +02006317 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006318 fh->handle_bytes = size;
6319 fh->handle_type = tswap32(target_fh->handle_type);
6320
6321 ret = get_errno(open_by_handle_at(mount_fd, fh,
6322 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6323
6324 g_free(fh);
6325
6326 unlock_user(target_fh, handle, total_size);
6327
6328 return ret;
6329}
6330#endif
pbrookbd0c5662008-05-29 14:34:11 +00006331
Laurent Viviere36800c2015-10-02 14:48:09 +02006332#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6333
6334/* signalfd siginfo conversion */
6335
6336static void
6337host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6338 const struct signalfd_siginfo *info)
6339{
6340 int sig = host_to_target_signal(info->ssi_signo);
6341
6342 /* linux/signalfd.h defines a ssi_addr_lsb
6343 * not defined in sys/signalfd.h but used by some kernels
6344 */
6345
6346#ifdef BUS_MCEERR_AO
6347 if (tinfo->ssi_signo == SIGBUS &&
6348 (tinfo->ssi_code == BUS_MCEERR_AR ||
6349 tinfo->ssi_code == BUS_MCEERR_AO)) {
6350 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6351 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6352 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6353 }
6354#endif
6355
6356 tinfo->ssi_signo = tswap32(sig);
6357 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6358 tinfo->ssi_code = tswap32(info->ssi_code);
6359 tinfo->ssi_pid = tswap32(info->ssi_pid);
6360 tinfo->ssi_uid = tswap32(info->ssi_uid);
6361 tinfo->ssi_fd = tswap32(info->ssi_fd);
6362 tinfo->ssi_tid = tswap32(info->ssi_tid);
6363 tinfo->ssi_band = tswap32(info->ssi_band);
6364 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6365 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6366 tinfo->ssi_status = tswap32(info->ssi_status);
6367 tinfo->ssi_int = tswap32(info->ssi_int);
6368 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6369 tinfo->ssi_utime = tswap64(info->ssi_utime);
6370 tinfo->ssi_stime = tswap64(info->ssi_stime);
6371 tinfo->ssi_addr = tswap64(info->ssi_addr);
6372}
6373
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006374static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006375{
6376 int i;
6377
6378 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6379 host_to_target_signalfd_siginfo(buf + i, buf + i);
6380 }
6381
6382 return len;
6383}
6384
6385static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006386 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006387};
6388
6389static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6390{
6391 int host_flags;
6392 target_sigset_t *target_mask;
6393 sigset_t host_mask;
6394 abi_long ret;
6395
6396 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6397 return -TARGET_EINVAL;
6398 }
6399 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6400 return -TARGET_EFAULT;
6401 }
6402
6403 target_to_host_sigset(&host_mask, target_mask);
6404
6405 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6406
6407 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6408 if (ret >= 0) {
6409 fd_trans_register(ret, &target_signalfd_trans);
6410 }
6411
6412 unlock_user_struct(target_mask, mask, 0);
6413
6414 return ret;
6415}
6416#endif
6417
pbrook1d9d8b52009-04-16 15:17:02 +00006418/* Map host to target signal numbers for the wait family of syscalls.
6419 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006420int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006421{
6422 if (WIFSIGNALED(status)) {
6423 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6424 }
6425 if (WIFSTOPPED(status)) {
6426 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6427 | (status & 0xff);
6428 }
6429 return status;
6430}
6431
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006432static int open_self_cmdline(void *cpu_env, int fd)
6433{
6434 int fd_orig = -1;
6435 bool word_skipped = false;
6436
6437 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6438 if (fd_orig < 0) {
6439 return fd_orig;
6440 }
6441
6442 while (true) {
6443 ssize_t nb_read;
6444 char buf[128];
6445 char *cp_buf = buf;
6446
6447 nb_read = read(fd_orig, buf, sizeof(buf));
6448 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006449 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006450 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006451 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006452 return -1;
6453 } else if (nb_read == 0) {
6454 break;
6455 }
6456
6457 if (!word_skipped) {
6458 /* Skip the first string, which is the path to qemu-*-static
6459 instead of the actual command. */
6460 cp_buf = memchr(buf, 0, sizeof(buf));
6461 if (cp_buf) {
6462 /* Null byte found, skip one string */
6463 cp_buf++;
6464 nb_read -= cp_buf - buf;
6465 word_skipped = true;
6466 }
6467 }
6468
6469 if (word_skipped) {
6470 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006471 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006472 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006473 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006474 return -1;
6475 }
6476 }
6477 }
6478
6479 return close(fd_orig);
6480}
6481
Alexander Graf36c08d42011-11-02 20:23:24 +01006482static int open_self_maps(void *cpu_env, int fd)
6483{
Andreas Färber0429a972013-08-26 18:14:44 +02006484 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6485 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006486 FILE *fp;
6487 char *line = NULL;
6488 size_t len = 0;
6489 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006490
Alexander Graf1a49ef22012-05-01 16:30:28 +01006491 fp = fopen("/proc/self/maps", "r");
6492 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006493 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006494 }
6495
6496 while ((read = getline(&line, &len, fp)) != -1) {
6497 int fields, dev_maj, dev_min, inode;
6498 uint64_t min, max, offset;
6499 char flag_r, flag_w, flag_x, flag_p;
6500 char path[512] = "";
6501 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6502 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6503 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6504
6505 if ((fields < 10) || (fields > 11)) {
6506 continue;
6507 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006508 if (h2g_valid(min)) {
6509 int flags = page_get_flags(h2g(min));
6510 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6511 if (page_check_range(h2g(min), max - min, flags) == -1) {
6512 continue;
6513 }
6514 if (h2g(min) == ts->info->stack_limit) {
6515 pstrcpy(path, sizeof(path), " [stack]");
6516 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006517 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006518 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006519 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006520 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006521 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006522 }
6523 }
6524
6525 free(line);
6526 fclose(fp);
6527
Alexander Graf36c08d42011-11-02 20:23:24 +01006528 return 0;
6529}
6530
Alexander Graf480b8e72011-11-02 20:23:25 +01006531static int open_self_stat(void *cpu_env, int fd)
6532{
Andreas Färber0429a972013-08-26 18:14:44 +02006533 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6534 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006535 abi_ulong start_stack = ts->info->start_stack;
6536 int i;
6537
6538 for (i = 0; i < 44; i++) {
6539 char buf[128];
6540 int len;
6541 uint64_t val = 0;
6542
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006543 if (i == 0) {
6544 /* pid */
6545 val = getpid();
6546 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6547 } else if (i == 1) {
6548 /* app name */
6549 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6550 } else if (i == 27) {
6551 /* stack bottom */
6552 val = start_stack;
6553 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6554 } else {
6555 /* for the rest, there is MasterCard */
6556 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006557 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006558
Alexander Graf480b8e72011-11-02 20:23:25 +01006559 len = strlen(buf);
6560 if (write(fd, buf, len) != len) {
6561 return -1;
6562 }
6563 }
6564
6565 return 0;
6566}
6567
Alexander Graf257450e2011-11-02 20:23:26 +01006568static int open_self_auxv(void *cpu_env, int fd)
6569{
Andreas Färber0429a972013-08-26 18:14:44 +02006570 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6571 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006572 abi_ulong auxv = ts->info->saved_auxv;
6573 abi_ulong len = ts->info->auxv_len;
6574 char *ptr;
6575
6576 /*
6577 * Auxiliary vector is stored in target process stack.
6578 * read in whole auxv vector and copy it to file
6579 */
6580 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6581 if (ptr != NULL) {
6582 while (len > 0) {
6583 ssize_t r;
6584 r = write(fd, ptr, len);
6585 if (r <= 0) {
6586 break;
6587 }
6588 len -= r;
6589 ptr += r;
6590 }
6591 lseek(fd, 0, SEEK_SET);
6592 unlock_user(ptr, auxv, len);
6593 }
6594
6595 return 0;
6596}
6597
Andreas Schwab463d8e72013-07-02 14:04:12 +01006598static int is_proc_myself(const char *filename, const char *entry)
6599{
6600 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6601 filename += strlen("/proc/");
6602 if (!strncmp(filename, "self/", strlen("self/"))) {
6603 filename += strlen("self/");
6604 } else if (*filename >= '1' && *filename <= '9') {
6605 char myself[80];
6606 snprintf(myself, sizeof(myself), "%d/", getpid());
6607 if (!strncmp(filename, myself, strlen(myself))) {
6608 filename += strlen(myself);
6609 } else {
6610 return 0;
6611 }
6612 } else {
6613 return 0;
6614 }
6615 if (!strcmp(filename, entry)) {
6616 return 1;
6617 }
6618 }
6619 return 0;
6620}
6621
Laurent Vivierde6b9932013-08-30 01:46:40 +02006622#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6623static int is_proc(const char *filename, const char *entry)
6624{
6625 return strcmp(filename, entry) == 0;
6626}
6627
6628static int open_net_route(void *cpu_env, int fd)
6629{
6630 FILE *fp;
6631 char *line = NULL;
6632 size_t len = 0;
6633 ssize_t read;
6634
6635 fp = fopen("/proc/net/route", "r");
6636 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006637 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006638 }
6639
6640 /* read header */
6641
6642 read = getline(&line, &len, fp);
6643 dprintf(fd, "%s", line);
6644
6645 /* read routes */
6646
6647 while ((read = getline(&line, &len, fp)) != -1) {
6648 char iface[16];
6649 uint32_t dest, gw, mask;
6650 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6651 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6652 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6653 &mask, &mtu, &window, &irtt);
6654 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6655 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6656 metric, tswap32(mask), mtu, window, irtt);
6657 }
6658
6659 free(line);
6660 fclose(fp);
6661
6662 return 0;
6663}
6664#endif
6665
Riku Voipio0b2effd2014-08-06 10:36:37 +03006666static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006667{
6668 struct fake_open {
6669 const char *filename;
6670 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006671 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006672 };
6673 const struct fake_open *fake_open;
6674 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006675 { "maps", open_self_maps, is_proc_myself },
6676 { "stat", open_self_stat, is_proc_myself },
6677 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006678 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006679#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6680 { "/proc/net/route", open_net_route, is_proc },
6681#endif
6682 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006683 };
6684
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006685 if (is_proc_myself(pathname, "exe")) {
6686 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006687 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006688 }
6689
Alexander Graf3be14d02011-11-02 20:23:23 +01006690 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006691 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006692 break;
6693 }
6694 }
6695
6696 if (fake_open->filename) {
6697 const char *tmpdir;
6698 char filename[PATH_MAX];
6699 int fd, r;
6700
6701 /* create temporary file to map stat to */
6702 tmpdir = getenv("TMPDIR");
6703 if (!tmpdir)
6704 tmpdir = "/tmp";
6705 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6706 fd = mkstemp(filename);
6707 if (fd < 0) {
6708 return fd;
6709 }
6710 unlink(filename);
6711
6712 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006713 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006714 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006715 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006716 return r;
6717 }
6718 lseek(fd, 0, SEEK_SET);
6719
6720 return fd;
6721 }
6722
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006723 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006724}
6725
Alexander Grafaecc8862014-11-10 21:33:03 +01006726#define TIMER_MAGIC 0x0caf0000
6727#define TIMER_MAGIC_MASK 0xffff0000
6728
6729/* Convert QEMU provided timer ID back to internal 16bit index format */
6730static target_timer_t get_timer_id(abi_long arg)
6731{
6732 target_timer_t timerid = arg;
6733
6734 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6735 return -TARGET_EINVAL;
6736 }
6737
6738 timerid &= 0xffff;
6739
6740 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6741 return -TARGET_EINVAL;
6742 }
6743
6744 return timerid;
6745}
6746
ths0da46a62007-10-20 20:23:07 +00006747/* do_syscall() should always have a single exit point at the end so
6748 that actions, such as logging of syscall results, can be performed.
6749 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006750abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6751 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006752 abi_long arg5, abi_long arg6, abi_long arg7,
6753 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006754{
Andreas Färber182735e2013-05-29 22:29:20 +02006755 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006756 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006757 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006758 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006759 void *p;
ths3b46e622007-09-17 08:09:54 +00006760
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006761#if defined(DEBUG_ERESTARTSYS)
6762 /* Debug-only code for exercising the syscall-restart code paths
6763 * in the per-architecture cpu main loops: restart every syscall
6764 * the guest makes once before letting it through.
6765 */
6766 {
6767 static int flag;
6768
6769 flag = !flag;
6770 if (flag) {
6771 return -TARGET_ERESTARTSYS;
6772 }
6773 }
6774#endif
6775
bellard72f03902003-02-18 23:33:18 +00006776#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006777 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006778#endif
thsb92c47c2007-11-01 00:07:38 +00006779 if(do_strace)
6780 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6781
bellard31e31b82003-02-18 22:55:36 +00006782 switch(num) {
6783 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006784 /* In old applications this may be used to implement _exit(2).
6785 However in threaded applictions it is used for thread termination,
6786 and _exit_group is used for application termination.
6787 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01006788
6789 if (block_signals()) {
6790 ret = -TARGET_ERESTARTSYS;
6791 break;
6792 }
6793
Andreas Färberbdc44642013-06-24 23:50:24 +02006794 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006795 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006796
Andreas Färber9b056fc2013-06-24 23:53:10 +02006797 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006798 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006799 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006800 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006801 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006802 if (ts->child_tidptr) {
6803 put_user_u32(0, ts->child_tidptr);
6804 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6805 NULL, NULL, 0);
6806 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006807 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006808 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006809 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006810 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006811 pthread_exit(NULL);
6812 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006813#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006814 _mcleanup();
6815#endif
bellarde9009672005-04-26 20:42:36 +00006816 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006817 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006818 ret = 0; /* avoid warning */
6819 break;
6820 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006821 if (arg3 == 0)
6822 ret = 0;
6823 else {
6824 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6825 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006826 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006827 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006828 fd_trans_host_to_target_data(arg1)) {
6829 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006830 }
aurel3238d840e2009-01-30 19:48:17 +00006831 unlock_user(p, arg2, ret);
6832 }
bellard31e31b82003-02-18 22:55:36 +00006833 break;
6834 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006835 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6836 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006837 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006838 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006839 break;
Chen Gang704eff62015-08-21 05:37:33 +08006840#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006841 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006842 if (!(p = lock_user_string(arg1)))
6843 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006844 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6845 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6846 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006847 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006848 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006849 break;
Chen Gang704eff62015-08-21 05:37:33 +08006850#endif
ths82424832007-09-24 09:21:55 +00006851 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006852 if (!(p = lock_user_string(arg2)))
6853 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006854 ret = get_errno(do_openat(cpu_env, arg1, p,
6855 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6856 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006857 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006858 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006859 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006860#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6861 case TARGET_NR_name_to_handle_at:
6862 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6863 break;
6864#endif
6865#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6866 case TARGET_NR_open_by_handle_at:
6867 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006868 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006869 break;
6870#endif
bellard31e31b82003-02-18 22:55:36 +00006871 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006872 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006873 ret = get_errno(close(arg1));
6874 break;
6875 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006876 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006877 break;
Chen Gang704eff62015-08-21 05:37:33 +08006878#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006879 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006880 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006881 break;
Chen Gang704eff62015-08-21 05:37:33 +08006882#endif
thse5febef2007-04-01 18:31:35 +00006883#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006884 case TARGET_NR_waitpid:
6885 {
pbrook53a59602006-03-25 19:31:22 +00006886 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006887 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006888 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006889 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006890 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006891 }
6892 break;
thse5febef2007-04-01 18:31:35 +00006893#endif
pbrookf0cbb612008-05-30 18:20:05 +00006894#ifdef TARGET_NR_waitid
6895 case TARGET_NR_waitid:
6896 {
6897 siginfo_t info;
6898 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006899 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006900 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006901 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006902 goto efault;
6903 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006904 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006905 }
6906 }
6907 break;
6908#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006909#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006910 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006911 if (!(p = lock_user_string(arg1)))
6912 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006913 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006914 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006915 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006916 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006917#endif
Chen Gang704eff62015-08-21 05:37:33 +08006918#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006919 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006920 {
6921 void * p2;
6922 p = lock_user_string(arg1);
6923 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006924 if (!p || !p2)
6925 ret = -TARGET_EFAULT;
6926 else
6927 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006928 unlock_user(p2, arg2, 0);
6929 unlock_user(p, arg1, 0);
6930 }
bellard31e31b82003-02-18 22:55:36 +00006931 break;
Chen Gang704eff62015-08-21 05:37:33 +08006932#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006933#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006934 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006935 {
6936 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006937 if (!arg2 || !arg4)
6938 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006939 p = lock_user_string(arg2);
6940 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006941 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006942 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006943 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006944 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006945 unlock_user(p, arg2, 0);
6946 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006947 }
6948 break;
6949#endif
Chen Gang704eff62015-08-21 05:37:33 +08006950#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006951 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006952 if (!(p = lock_user_string(arg1)))
6953 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006954 ret = get_errno(unlink(p));
6955 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006956 break;
Chen Gang704eff62015-08-21 05:37:33 +08006957#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006958#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006959 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006960 if (!(p = lock_user_string(arg2)))
6961 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006962 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006963 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006964 break;
balrogb7d35e62007-12-12 00:40:24 +00006965#endif
bellard31e31b82003-02-18 22:55:36 +00006966 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006967 {
6968 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006969 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006970 abi_ulong gp;
6971 abi_ulong guest_argp;
6972 abi_ulong guest_envp;
6973 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006974 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006975 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006976
bellardf7341ff2003-03-30 21:00:25 +00006977 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006978 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006979 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006980 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006981 goto efault;
ths03aa1972007-12-02 06:28:08 +00006982 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006983 break;
bellard7854b052003-03-29 17:22:23 +00006984 argc++;
bellard2f619692007-11-16 10:46:05 +00006985 }
bellardf7341ff2003-03-30 21:00:25 +00006986 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006987 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006988 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006989 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006990 goto efault;
ths03aa1972007-12-02 06:28:08 +00006991 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006992 break;
bellard7854b052003-03-29 17:22:23 +00006993 envc++;
bellard2f619692007-11-16 10:46:05 +00006994 }
bellard7854b052003-03-29 17:22:23 +00006995
bellardf7341ff2003-03-30 21:00:25 +00006996 argp = alloca((argc + 1) * sizeof(void *));
6997 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006998
pbrookda94d262008-05-30 18:24:00 +00006999 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007000 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007001 if (get_user_ual(addr, gp))
7002 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007003 if (!addr)
7004 break;
bellard2f619692007-11-16 10:46:05 +00007005 if (!(*q = lock_user_string(addr)))
7006 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007007 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007008 }
bellardf7341ff2003-03-30 21:00:25 +00007009 *q = NULL;
7010
pbrookda94d262008-05-30 18:24:00 +00007011 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007012 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007013 if (get_user_ual(addr, gp))
7014 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007015 if (!addr)
7016 break;
bellard2f619692007-11-16 10:46:05 +00007017 if (!(*q = lock_user_string(addr)))
7018 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007019 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007020 }
bellardf7341ff2003-03-30 21:00:25 +00007021 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007022
bellard2f619692007-11-16 10:46:05 +00007023 if (!(p = lock_user_string(arg1)))
7024 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007025 /* Although execve() is not an interruptible syscall it is
7026 * a special case where we must use the safe_syscall wrapper:
7027 * if we allow a signal to happen before we make the host
7028 * syscall then we will 'lose' it, because at the point of
7029 * execve the process leaves QEMU's control. So we use the
7030 * safe syscall wrapper to ensure that we either take the
7031 * signal as a guest signal, or else it does not happen
7032 * before the execve completes and makes it the other
7033 * program's problem.
7034 */
7035 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007036 unlock_user(p, arg1, 0);
7037
bellard2f619692007-11-16 10:46:05 +00007038 goto execve_end;
7039
7040 execve_efault:
7041 ret = -TARGET_EFAULT;
7042
7043 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007044 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007045 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007046 if (get_user_ual(addr, gp)
7047 || !addr)
7048 break;
pbrook53a59602006-03-25 19:31:22 +00007049 unlock_user(*q, addr, 0);
7050 }
7051 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007052 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007053 if (get_user_ual(addr, gp)
7054 || !addr)
7055 break;
pbrook53a59602006-03-25 19:31:22 +00007056 unlock_user(*q, addr, 0);
7057 }
bellard7854b052003-03-29 17:22:23 +00007058 }
bellard31e31b82003-02-18 22:55:36 +00007059 break;
7060 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007061 if (!(p = lock_user_string(arg1)))
7062 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007063 ret = get_errno(chdir(p));
7064 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007065 break;
bellarda315a142005-01-30 22:59:18 +00007066#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007067 case TARGET_NR_time:
7068 {
pbrook53a59602006-03-25 19:31:22 +00007069 time_t host_time;
7070 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007071 if (!is_error(ret)
7072 && arg1
7073 && put_user_sal(host_time, arg1))
7074 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007075 }
7076 break;
bellarda315a142005-01-30 22:59:18 +00007077#endif
Chen Gang704eff62015-08-21 05:37:33 +08007078#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007079 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007080 if (!(p = lock_user_string(arg1)))
7081 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007082 ret = get_errno(mknod(p, arg2, arg3));
7083 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007084 break;
Chen Gang704eff62015-08-21 05:37:33 +08007085#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007086#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007087 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007088 if (!(p = lock_user_string(arg2)))
7089 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007090 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007091 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007092 break;
7093#endif
Chen Gang704eff62015-08-21 05:37:33 +08007094#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007095 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007096 if (!(p = lock_user_string(arg1)))
7097 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007098 ret = get_errno(chmod(p, arg2));
7099 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007100 break;
Chen Gang704eff62015-08-21 05:37:33 +08007101#endif
bellardebc05482003-09-30 21:08:41 +00007102#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007103 case TARGET_NR_break:
7104 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007105#endif
7106#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007107 case TARGET_NR_oldstat:
7108 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007109#endif
bellard31e31b82003-02-18 22:55:36 +00007110 case TARGET_NR_lseek:
7111 ret = get_errno(lseek(arg1, arg2, arg3));
7112 break;
Richard Henderson92317332010-05-03 10:07:53 -07007113#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7114 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007115 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007116 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007117 ret = get_errno(getpid());
7118 break;
Richard Henderson92317332010-05-03 10:07:53 -07007119#endif
7120#ifdef TARGET_NR_getpid
7121 case TARGET_NR_getpid:
7122 ret = get_errno(getpid());
7123 break;
7124#endif
bellard31e31b82003-02-18 22:55:36 +00007125 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007126 {
7127 /* need to look at the data field */
7128 void *p2, *p3;
7129
7130 if (arg1) {
7131 p = lock_user_string(arg1);
7132 if (!p) {
7133 goto efault;
7134 }
7135 } else {
7136 p = NULL;
7137 }
7138
7139 p2 = lock_user_string(arg2);
7140 if (!p2) {
7141 if (arg1) {
7142 unlock_user(p, arg1, 0);
7143 }
7144 goto efault;
7145 }
7146
7147 if (arg3) {
7148 p3 = lock_user_string(arg3);
7149 if (!p3) {
7150 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007151 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007152 }
7153 unlock_user(p2, arg2, 0);
7154 goto efault;
7155 }
7156 } else {
7157 p3 = NULL;
7158 }
7159
7160 /* FIXME - arg5 should be locked, but it isn't clear how to
7161 * do that since it's not guaranteed to be a NULL-terminated
7162 * string.
7163 */
7164 if (!arg5) {
7165 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7166 } else {
7167 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7168 }
7169 ret = get_errno(ret);
7170
7171 if (arg1) {
7172 unlock_user(p, arg1, 0);
7173 }
7174 unlock_user(p2, arg2, 0);
7175 if (arg3) {
7176 unlock_user(p3, arg3, 0);
7177 }
7178 }
7179 break;
thse5febef2007-04-01 18:31:35 +00007180#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007181 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007182 if (!(p = lock_user_string(arg1)))
7183 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007184 ret = get_errno(umount(p));
7185 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007186 break;
thse5febef2007-04-01 18:31:35 +00007187#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007188#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007189 case TARGET_NR_stime:
7190 {
pbrook53a59602006-03-25 19:31:22 +00007191 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007192 if (get_user_sal(host_time, arg1))
7193 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007194 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007195 }
7196 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007197#endif
bellard31e31b82003-02-18 22:55:36 +00007198 case TARGET_NR_ptrace:
7199 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007200#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007201 case TARGET_NR_alarm:
7202 ret = alarm(arg1);
7203 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007204#endif
bellardebc05482003-09-30 21:08:41 +00007205#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007206 case TARGET_NR_oldfstat:
7207 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007208#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007209#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007210 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007211 if (!block_signals()) {
7212 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7213 }
7214 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007215 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007216#endif
thse5febef2007-04-01 18:31:35 +00007217#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007219 {
pbrook53a59602006-03-25 19:31:22 +00007220 struct utimbuf tbuf, *host_tbuf;
7221 struct target_utimbuf *target_tbuf;
7222 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007223 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7224 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007225 tbuf.actime = tswapal(target_tbuf->actime);
7226 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007227 unlock_user_struct(target_tbuf, arg2, 0);
7228 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007229 } else {
pbrook53a59602006-03-25 19:31:22 +00007230 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007231 }
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(utime(p, host_tbuf));
7235 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007236 }
7237 break;
thse5febef2007-04-01 18:31:35 +00007238#endif
Chen Gang704eff62015-08-21 05:37:33 +08007239#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007240 case TARGET_NR_utimes:
7241 {
bellard978a66f2004-12-06 22:58:05 +00007242 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007243 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007244 if (copy_from_user_timeval(&tv[0], arg2)
7245 || copy_from_user_timeval(&tv[1],
7246 arg2 + sizeof(struct target_timeval)))
7247 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007248 tvp = tv;
7249 } else {
7250 tvp = NULL;
7251 }
bellard579a97f2007-11-11 14:26:47 +00007252 if (!(p = lock_user_string(arg1)))
7253 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007254 ret = get_errno(utimes(p, tvp));
7255 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007256 }
7257 break;
Chen Gang704eff62015-08-21 05:37:33 +08007258#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007259#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007260 case TARGET_NR_futimesat:
7261 {
7262 struct timeval *tvp, tv[2];
7263 if (arg3) {
7264 if (copy_from_user_timeval(&tv[0], arg3)
7265 || copy_from_user_timeval(&tv[1],
7266 arg3 + sizeof(struct target_timeval)))
7267 goto efault;
7268 tvp = tv;
7269 } else {
7270 tvp = NULL;
7271 }
7272 if (!(p = lock_user_string(arg2)))
7273 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007274 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007275 unlock_user(p, arg2, 0);
7276 }
7277 break;
7278#endif
bellardebc05482003-09-30 21:08:41 +00007279#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007280 case TARGET_NR_stty:
7281 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007282#endif
7283#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007284 case TARGET_NR_gtty:
7285 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007286#endif
Chen Gang704eff62015-08-21 05:37:33 +08007287#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007288 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007289 if (!(p = lock_user_string(arg1)))
7290 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007291 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007292 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007293 break;
Chen Gang704eff62015-08-21 05:37:33 +08007294#endif
ths92a34c12007-09-24 09:27:49 +00007295#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7296 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007297 if (!(p = lock_user_string(arg2)))
7298 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007299 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007300 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007301 break;
7302#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007303#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007304 case TARGET_NR_nice:
7305 ret = get_errno(nice(arg1));
7306 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007307#endif
bellardebc05482003-09-30 21:08:41 +00007308#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007309 case TARGET_NR_ftime:
7310 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007311#endif
bellard31e31b82003-02-18 22:55:36 +00007312 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007313 sync();
7314 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007315 break;
7316 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007317 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007318 break;
Chen Gang704eff62015-08-21 05:37:33 +08007319#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007320 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007321 {
7322 void *p2;
7323 p = lock_user_string(arg1);
7324 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007325 if (!p || !p2)
7326 ret = -TARGET_EFAULT;
7327 else
7328 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007329 unlock_user(p2, arg2, 0);
7330 unlock_user(p, arg1, 0);
7331 }
bellard31e31b82003-02-18 22:55:36 +00007332 break;
Chen Gang704eff62015-08-21 05:37:33 +08007333#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007334#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007335 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007336 {
bellard579a97f2007-11-11 14:26:47 +00007337 void *p2;
ths722183f2007-09-24 09:24:37 +00007338 p = lock_user_string(arg2);
7339 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007340 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007341 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007342 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007343 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007344 unlock_user(p2, arg4, 0);
7345 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007346 }
7347 break;
7348#endif
Chen Gang704eff62015-08-21 05:37:33 +08007349#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007350 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007351 if (!(p = lock_user_string(arg1)))
7352 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007353 ret = get_errno(mkdir(p, arg2));
7354 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007355 break;
Chen Gang704eff62015-08-21 05:37:33 +08007356#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007357#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007358 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007359 if (!(p = lock_user_string(arg2)))
7360 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007361 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007362 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007363 break;
7364#endif
Chen Gang704eff62015-08-21 05:37:33 +08007365#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007366 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007367 if (!(p = lock_user_string(arg1)))
7368 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007369 ret = get_errno(rmdir(p));
7370 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007371 break;
Chen Gang704eff62015-08-21 05:37:33 +08007372#endif
bellard31e31b82003-02-18 22:55:36 +00007373 case TARGET_NR_dup:
7374 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007375 if (ret >= 0) {
7376 fd_trans_dup(arg1, ret);
7377 }
bellard31e31b82003-02-18 22:55:36 +00007378 break;
Chen Gang704eff62015-08-21 05:37:33 +08007379#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007380 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007381 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007382 break;
Chen Gang704eff62015-08-21 05:37:33 +08007383#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007384#ifdef TARGET_NR_pipe2
7385 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007386 ret = do_pipe(cpu_env, arg1,
7387 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007388 break;
7389#endif
bellard31e31b82003-02-18 22:55:36 +00007390 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007391 {
pbrook53a59602006-03-25 19:31:22 +00007392 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007393 struct tms tms;
7394 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007395 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007396 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7397 if (!tmsp)
7398 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007399 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7400 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7401 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7402 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007403 }
bellardc596ed12003-07-13 17:32:31 +00007404 if (!is_error(ret))
7405 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007406 }
7407 break;
bellardebc05482003-09-30 21:08:41 +00007408#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007409 case TARGET_NR_prof:
7410 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007411#endif
thse5febef2007-04-01 18:31:35 +00007412#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007413 case TARGET_NR_signal:
7414 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007415#endif
bellard31e31b82003-02-18 22:55:36 +00007416 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007417 if (arg1 == 0) {
7418 ret = get_errno(acct(NULL));
7419 } else {
7420 if (!(p = lock_user_string(arg1)))
7421 goto efault;
7422 ret = get_errno(acct(path(p)));
7423 unlock_user(p, arg1, 0);
7424 }
pbrook24836682006-04-16 14:14:53 +00007425 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007426#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007427 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007428 if (!(p = lock_user_string(arg1)))
7429 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007430 ret = get_errno(umount2(p, arg2));
7431 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007432 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007433#endif
bellardebc05482003-09-30 21:08:41 +00007434#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007435 case TARGET_NR_lock:
7436 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007437#endif
bellard31e31b82003-02-18 22:55:36 +00007438 case TARGET_NR_ioctl:
7439 ret = do_ioctl(arg1, arg2, arg3);
7440 break;
7441 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007442 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007443 break;
bellardebc05482003-09-30 21:08:41 +00007444#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007445 case TARGET_NR_mpx:
7446 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007447#endif
bellard31e31b82003-02-18 22:55:36 +00007448 case TARGET_NR_setpgid:
7449 ret = get_errno(setpgid(arg1, arg2));
7450 break;
bellardebc05482003-09-30 21:08:41 +00007451#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007452 case TARGET_NR_ulimit:
7453 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007454#endif
7455#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007456 case TARGET_NR_oldolduname:
7457 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007458#endif
bellard31e31b82003-02-18 22:55:36 +00007459 case TARGET_NR_umask:
7460 ret = get_errno(umask(arg1));
7461 break;
7462 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007463 if (!(p = lock_user_string(arg1)))
7464 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007465 ret = get_errno(chroot(p));
7466 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007467 break;
Chen Gang704eff62015-08-21 05:37:33 +08007468#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007469 case TARGET_NR_ustat:
7470 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007471#endif
7472#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007473 case TARGET_NR_dup2:
7474 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007475 if (ret >= 0) {
7476 fd_trans_dup(arg1, arg2);
7477 }
bellard31e31b82003-02-18 22:55:36 +00007478 break;
Chen Gang704eff62015-08-21 05:37:33 +08007479#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007480#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7481 case TARGET_NR_dup3:
7482 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007483 if (ret >= 0) {
7484 fd_trans_dup(arg1, arg2);
7485 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007486 break;
7487#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007488#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007489 case TARGET_NR_getppid:
7490 ret = get_errno(getppid());
7491 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007492#endif
Chen Gang704eff62015-08-21 05:37:33 +08007493#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007494 case TARGET_NR_getpgrp:
7495 ret = get_errno(getpgrp());
7496 break;
Chen Gang704eff62015-08-21 05:37:33 +08007497#endif
bellard31e31b82003-02-18 22:55:36 +00007498 case TARGET_NR_setsid:
7499 ret = get_errno(setsid());
7500 break;
thse5febef2007-04-01 18:31:35 +00007501#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007502 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007503 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007504#if defined(TARGET_ALPHA)
7505 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007506 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007507 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007508 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7509 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007510 act._sa_handler = old_act->_sa_handler;
7511 target_siginitset(&act.sa_mask, old_act->sa_mask);
7512 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007513 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007514 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007515 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007516 }
7517 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007518 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007519 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7520 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007521 old_act->_sa_handler = oact._sa_handler;
7522 old_act->sa_mask = oact.sa_mask.sig[0];
7523 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007524 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007525 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007526#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007527 struct target_sigaction act, oact, *pact, *old_act;
7528
7529 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007530 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7531 goto efault;
bellard106ec872006-06-27 21:08:10 +00007532 act._sa_handler = old_act->_sa_handler;
7533 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7534 act.sa_flags = old_act->sa_flags;
7535 unlock_user_struct(old_act, arg2, 0);
7536 pact = &act;
7537 } else {
7538 pact = NULL;
7539 }
7540
7541 ret = get_errno(do_sigaction(arg1, pact, &oact));
7542
7543 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007544 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7545 goto efault;
bellard106ec872006-06-27 21:08:10 +00007546 old_act->_sa_handler = oact._sa_handler;
7547 old_act->sa_flags = oact.sa_flags;
7548 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7549 old_act->sa_mask.sig[1] = 0;
7550 old_act->sa_mask.sig[2] = 0;
7551 old_act->sa_mask.sig[3] = 0;
7552 unlock_user_struct(old_act, arg3, 1);
7553 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007554#else
7555 struct target_old_sigaction *old_act;
7556 struct target_sigaction act, oact, *pact;
7557 if (arg2) {
7558 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7559 goto efault;
7560 act._sa_handler = old_act->_sa_handler;
7561 target_siginitset(&act.sa_mask, old_act->sa_mask);
7562 act.sa_flags = old_act->sa_flags;
7563 act.sa_restorer = old_act->sa_restorer;
7564 unlock_user_struct(old_act, arg2, 0);
7565 pact = &act;
7566 } else {
7567 pact = NULL;
7568 }
7569 ret = get_errno(do_sigaction(arg1, pact, &oact));
7570 if (!is_error(ret) && arg3) {
7571 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7572 goto efault;
7573 old_act->_sa_handler = oact._sa_handler;
7574 old_act->sa_mask = oact.sa_mask.sig[0];
7575 old_act->sa_flags = oact.sa_flags;
7576 old_act->sa_restorer = oact.sa_restorer;
7577 unlock_user_struct(old_act, arg3, 1);
7578 }
ths388bb212007-05-13 13:58:00 +00007579#endif
bellard31e31b82003-02-18 22:55:36 +00007580 }
7581 break;
thse5febef2007-04-01 18:31:35 +00007582#endif
bellard66fb9762003-03-23 01:06:05 +00007583 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007584 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007585#if defined(TARGET_ALPHA)
7586 struct target_sigaction act, oact, *pact = 0;
7587 struct target_rt_sigaction *rt_act;
7588 /* ??? arg4 == sizeof(sigset_t). */
7589 if (arg2) {
7590 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7591 goto efault;
7592 act._sa_handler = rt_act->_sa_handler;
7593 act.sa_mask = rt_act->sa_mask;
7594 act.sa_flags = rt_act->sa_flags;
7595 act.sa_restorer = arg5;
7596 unlock_user_struct(rt_act, arg2, 0);
7597 pact = &act;
7598 }
7599 ret = get_errno(do_sigaction(arg1, pact, &oact));
7600 if (!is_error(ret) && arg3) {
7601 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7602 goto efault;
7603 rt_act->_sa_handler = oact._sa_handler;
7604 rt_act->sa_mask = oact.sa_mask;
7605 rt_act->sa_flags = oact.sa_flags;
7606 unlock_user_struct(rt_act, arg3, 1);
7607 }
7608#else
pbrook53a59602006-03-25 19:31:22 +00007609 struct target_sigaction *act;
7610 struct target_sigaction *oact;
7611
bellard579a97f2007-11-11 14:26:47 +00007612 if (arg2) {
7613 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7614 goto efault;
7615 } else
pbrook53a59602006-03-25 19:31:22 +00007616 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007617 if (arg3) {
7618 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7619 ret = -TARGET_EFAULT;
7620 goto rt_sigaction_fail;
7621 }
7622 } else
pbrook53a59602006-03-25 19:31:22 +00007623 oact = NULL;
7624 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007625 rt_sigaction_fail:
7626 if (act)
pbrook53a59602006-03-25 19:31:22 +00007627 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007628 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007629 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007630#endif
pbrook53a59602006-03-25 19:31:22 +00007631 }
bellard66fb9762003-03-23 01:06:05 +00007632 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007633#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007634 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007635 {
7636 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007637 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007638 ret = do_sigprocmask(0, NULL, &cur_set);
7639 if (!ret) {
7640 host_to_target_old_sigset(&target_set, &cur_set);
7641 ret = target_set;
7642 }
bellard66fb9762003-03-23 01:06:05 +00007643 }
7644 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007645#endif
7646#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007647 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007648 {
7649 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007650 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007651 /* We only have one word of the new mask so we must read
7652 * the rest of it with do_sigprocmask() and OR in this word.
7653 * We are guaranteed that a do_sigprocmask() that only queries
7654 * the signal mask will not fail.
7655 */
7656 ret = do_sigprocmask(0, NULL, &cur_set);
7657 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00007658 target_to_host_old_sigset(&set, &target_set);
7659 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007660 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7661 if (!ret) {
7662 host_to_target_old_sigset(&target_set, &oset);
7663 ret = target_set;
7664 }
bellard66fb9762003-03-23 01:06:05 +00007665 }
7666 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007667#endif
thse5febef2007-04-01 18:31:35 +00007668#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007669 case TARGET_NR_sigprocmask:
7670 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007671#if defined(TARGET_ALPHA)
7672 sigset_t set, oldset;
7673 abi_ulong mask;
7674 int how;
7675
7676 switch (arg1) {
7677 case TARGET_SIG_BLOCK:
7678 how = SIG_BLOCK;
7679 break;
7680 case TARGET_SIG_UNBLOCK:
7681 how = SIG_UNBLOCK;
7682 break;
7683 case TARGET_SIG_SETMASK:
7684 how = SIG_SETMASK;
7685 break;
7686 default:
7687 ret = -TARGET_EINVAL;
7688 goto fail;
7689 }
7690 mask = arg2;
7691 target_to_host_old_sigset(&set, &mask);
7692
Peter Maydell3d3efba2016-05-27 15:51:49 +01007693 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007694 if (!is_error(ret)) {
7695 host_to_target_old_sigset(&mask, &oldset);
7696 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007697 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007698 }
7699#else
bellard66fb9762003-03-23 01:06:05 +00007700 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007701 int how;
ths3b46e622007-09-17 08:09:54 +00007702
pbrook53a59602006-03-25 19:31:22 +00007703 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007704 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007705 case TARGET_SIG_BLOCK:
7706 how = SIG_BLOCK;
7707 break;
7708 case TARGET_SIG_UNBLOCK:
7709 how = SIG_UNBLOCK;
7710 break;
7711 case TARGET_SIG_SETMASK:
7712 how = SIG_SETMASK;
7713 break;
7714 default:
ths0da46a62007-10-20 20:23:07 +00007715 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007716 goto fail;
7717 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007718 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007719 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007720 target_to_host_old_sigset(&set, p);
7721 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007722 set_ptr = &set;
7723 } else {
7724 how = 0;
7725 set_ptr = NULL;
7726 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007727 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007728 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007729 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007730 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007731 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007732 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007733 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007734#endif
bellard66fb9762003-03-23 01:06:05 +00007735 }
7736 break;
thse5febef2007-04-01 18:31:35 +00007737#endif
bellard66fb9762003-03-23 01:06:05 +00007738 case TARGET_NR_rt_sigprocmask:
7739 {
7740 int how = arg1;
7741 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007742
pbrook53a59602006-03-25 19:31:22 +00007743 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007744 switch(how) {
7745 case TARGET_SIG_BLOCK:
7746 how = SIG_BLOCK;
7747 break;
7748 case TARGET_SIG_UNBLOCK:
7749 how = SIG_UNBLOCK;
7750 break;
7751 case TARGET_SIG_SETMASK:
7752 how = SIG_SETMASK;
7753 break;
7754 default:
ths0da46a62007-10-20 20:23:07 +00007755 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007756 goto fail;
7757 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007758 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007759 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007760 target_to_host_sigset(&set, p);
7761 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007762 set_ptr = &set;
7763 } else {
7764 how = 0;
7765 set_ptr = NULL;
7766 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007767 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007768 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007769 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007770 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007771 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007772 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007773 }
7774 }
7775 break;
thse5febef2007-04-01 18:31:35 +00007776#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007777 case TARGET_NR_sigpending:
7778 {
7779 sigset_t set;
7780 ret = get_errno(sigpending(&set));
7781 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007782 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007783 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007784 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007785 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007786 }
7787 }
7788 break;
thse5febef2007-04-01 18:31:35 +00007789#endif
bellard66fb9762003-03-23 01:06:05 +00007790 case TARGET_NR_rt_sigpending:
7791 {
7792 sigset_t set;
7793 ret = get_errno(sigpending(&set));
7794 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007795 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007796 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007797 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007798 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007799 }
7800 }
7801 break;
thse5febef2007-04-01 18:31:35 +00007802#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007803 case TARGET_NR_sigsuspend:
7804 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007805 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007806#if defined(TARGET_ALPHA)
7807 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007808 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007809#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007810 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007811 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007812 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007813 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007814#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01007815 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7816 SIGSET_T_SIZE));
7817 if (ret != -TARGET_ERESTARTSYS) {
7818 ts->in_sigsuspend = 1;
7819 }
bellard66fb9762003-03-23 01:06:05 +00007820 }
7821 break;
thse5febef2007-04-01 18:31:35 +00007822#endif
bellard66fb9762003-03-23 01:06:05 +00007823 case TARGET_NR_rt_sigsuspend:
7824 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007825 TaskState *ts = cpu->opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05007826 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007827 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007828 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007829 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007830 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7831 SIGSET_T_SIZE));
7832 if (ret != -TARGET_ERESTARTSYS) {
7833 ts->in_sigsuspend = 1;
7834 }
bellard66fb9762003-03-23 01:06:05 +00007835 }
7836 break;
7837 case TARGET_NR_rt_sigtimedwait:
7838 {
bellard66fb9762003-03-23 01:06:05 +00007839 sigset_t set;
7840 struct timespec uts, *puts;
7841 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007842
Anthony Liguoric227f092009-10-01 16:12:16 -05007843 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007844 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007845 target_to_host_sigset(&set, p);
7846 unlock_user(p, arg1, 0);
7847 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007848 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007849 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007850 } else {
7851 puts = NULL;
7852 }
Peter Maydellb3f82332016-06-06 19:58:08 +01007853 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
7854 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007855 if (!is_error(ret)) {
7856 if (arg2) {
7857 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7858 0);
7859 if (!p) {
7860 goto efault;
7861 }
7862 host_to_target_siginfo(p, &uinfo);
7863 unlock_user(p, arg2, sizeof(target_siginfo_t));
7864 }
7865 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007866 }
7867 }
7868 break;
7869 case TARGET_NR_rt_sigqueueinfo:
7870 {
7871 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05007872 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007873 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007874 target_to_host_siginfo(&uinfo, p);
7875 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007876 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7877 }
7878 break;
thse5febef2007-04-01 18:31:35 +00007879#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007880 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007881 if (block_signals()) {
7882 ret = -TARGET_ERESTARTSYS;
7883 } else {
7884 ret = do_sigreturn(cpu_env);
7885 }
bellard66fb9762003-03-23 01:06:05 +00007886 break;
thse5febef2007-04-01 18:31:35 +00007887#endif
bellard66fb9762003-03-23 01:06:05 +00007888 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007889 if (block_signals()) {
7890 ret = -TARGET_ERESTARTSYS;
7891 } else {
7892 ret = do_rt_sigreturn(cpu_env);
7893 }
bellard66fb9762003-03-23 01:06:05 +00007894 break;
bellard31e31b82003-02-18 22:55:36 +00007895 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007896 if (!(p = lock_user_string(arg1)))
7897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007898 ret = get_errno(sethostname(p, arg2));
7899 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007900 break;
7901 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007902 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007903 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007904 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007905 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007906 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7907 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007908 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7909 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007910 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007911 ret = get_errno(setrlimit(resource, &rlim));
7912 }
7913 break;
bellard31e31b82003-02-18 22:55:36 +00007914 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007915 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007916 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007917 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007918 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007919
bellard9de5e442003-03-23 16:49:39 +00007920 ret = get_errno(getrlimit(resource, &rlim));
7921 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007922 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7923 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007924 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7925 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007926 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007927 }
7928 }
7929 break;
bellard31e31b82003-02-18 22:55:36 +00007930 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007931 {
7932 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007933 ret = get_errno(getrusage(arg1, &rusage));
7934 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007935 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007936 }
7937 }
7938 break;
bellard31e31b82003-02-18 22:55:36 +00007939 case TARGET_NR_gettimeofday:
7940 {
bellard31e31b82003-02-18 22:55:36 +00007941 struct timeval tv;
7942 ret = get_errno(gettimeofday(&tv, NULL));
7943 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007944 if (copy_to_user_timeval(arg1, &tv))
7945 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007946 }
7947 }
7948 break;
7949 case TARGET_NR_settimeofday:
7950 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007951 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007952 struct timezone tz, *ptz = NULL;
7953
Paul Burtonb67d8032014-06-22 11:25:41 +01007954 if (arg1) {
7955 if (copy_from_user_timeval(&tv, arg1)) {
7956 goto efault;
7957 }
7958 ptv = &tv;
7959 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007960
7961 if (arg2) {
7962 if (copy_from_user_timezone(&tz, arg2)) {
7963 goto efault;
7964 }
7965 ptz = &tz;
7966 }
7967
Paul Burtonb67d8032014-06-22 11:25:41 +01007968 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007969 }
7970 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007971#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007972 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007973#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7974 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7975#else
bellardf2674e32003-07-09 12:26:09 +00007976 {
pbrook53a59602006-03-25 19:31:22 +00007977 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007978 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007979 long nsel;
7980
bellard579a97f2007-11-11 14:26:47 +00007981 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7982 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007983 nsel = tswapal(sel->n);
7984 inp = tswapal(sel->inp);
7985 outp = tswapal(sel->outp);
7986 exp = tswapal(sel->exp);
7987 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007988 unlock_user_struct(sel, arg1, 0);
7989 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007990 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007991#endif
bellardf2674e32003-07-09 12:26:09 +00007992 break;
bellard048f6b42005-11-26 18:47:20 +00007993#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007994#ifdef TARGET_NR_pselect6
7995 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007996 {
7997 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7998 fd_set rfds, wfds, efds;
7999 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8000 struct timespec ts, *ts_ptr;
8001
8002 /*
8003 * The 6th arg is actually two args smashed together,
8004 * so we cannot use the C library.
8005 */
8006 sigset_t set;
8007 struct {
8008 sigset_t *set;
8009 size_t size;
8010 } sig, *sig_ptr;
8011
8012 abi_ulong arg_sigset, arg_sigsize, *arg7;
8013 target_sigset_t *target_sigset;
8014
8015 n = arg1;
8016 rfd_addr = arg2;
8017 wfd_addr = arg3;
8018 efd_addr = arg4;
8019 ts_addr = arg5;
8020
8021 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8022 if (ret) {
8023 goto fail;
8024 }
8025 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8026 if (ret) {
8027 goto fail;
8028 }
8029 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8030 if (ret) {
8031 goto fail;
8032 }
8033
8034 /*
8035 * This takes a timespec, and not a timeval, so we cannot
8036 * use the do_select() helper ...
8037 */
8038 if (ts_addr) {
8039 if (target_to_host_timespec(&ts, ts_addr)) {
8040 goto efault;
8041 }
8042 ts_ptr = &ts;
8043 } else {
8044 ts_ptr = NULL;
8045 }
8046
8047 /* Extract the two packed args for the sigset */
8048 if (arg6) {
8049 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008050 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008051
8052 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8053 if (!arg7) {
8054 goto efault;
8055 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008056 arg_sigset = tswapal(arg7[0]);
8057 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008058 unlock_user(arg7, arg6, 0);
8059
8060 if (arg_sigset) {
8061 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008062 if (arg_sigsize != sizeof(*target_sigset)) {
8063 /* Like the kernel, we enforce correct size sigsets */
8064 ret = -TARGET_EINVAL;
8065 goto fail;
8066 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008067 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8068 sizeof(*target_sigset), 1);
8069 if (!target_sigset) {
8070 goto efault;
8071 }
8072 target_to_host_sigset(&set, target_sigset);
8073 unlock_user(target_sigset, arg_sigset, 0);
8074 } else {
8075 sig.set = NULL;
8076 }
8077 } else {
8078 sig_ptr = NULL;
8079 }
8080
Peter Maydell6df9d382016-05-12 18:47:51 +01008081 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8082 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008083
8084 if (!is_error(ret)) {
8085 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8086 goto efault;
8087 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8088 goto efault;
8089 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8090 goto efault;
8091
8092 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8093 goto efault;
8094 }
8095 }
8096 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008097#endif
Chen Gang704eff62015-08-21 05:37:33 +08008098#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008099 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008100 {
8101 void *p2;
8102 p = lock_user_string(arg1);
8103 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008104 if (!p || !p2)
8105 ret = -TARGET_EFAULT;
8106 else
8107 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008108 unlock_user(p2, arg2, 0);
8109 unlock_user(p, arg1, 0);
8110 }
bellard31e31b82003-02-18 22:55:36 +00008111 break;
Chen Gang704eff62015-08-21 05:37:33 +08008112#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008113#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008114 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008115 {
bellard579a97f2007-11-11 14:26:47 +00008116 void *p2;
thsf0b62432007-09-24 09:25:40 +00008117 p = lock_user_string(arg1);
8118 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008119 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008120 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008121 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008122 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008123 unlock_user(p2, arg3, 0);
8124 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008125 }
8126 break;
8127#endif
bellardebc05482003-09-30 21:08:41 +00008128#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008129 case TARGET_NR_oldlstat:
8130 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008131#endif
Chen Gang704eff62015-08-21 05:37:33 +08008132#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008133 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008134 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008135 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008136 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008137 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008138 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008139 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008140 } else if (!arg3) {
8141 /* Short circuit this for the magic exe check. */
8142 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008143 } else if (is_proc_myself((const char *)p, "exe")) {
8144 char real[PATH_MAX], *temp;
8145 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008146 /* Return value is # of bytes that we wrote to the buffer. */
8147 if (temp == NULL) {
8148 ret = get_errno(-1);
8149 } else {
8150 /* Don't worry about sign mismatch as earlier mapping
8151 * logic would have thrown a bad address error. */
8152 ret = MIN(strlen(real), arg3);
8153 /* We cannot NUL terminate the string. */
8154 memcpy(p2, real, ret);
8155 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008156 } else {
8157 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008158 }
pbrook53a59602006-03-25 19:31:22 +00008159 unlock_user(p2, arg2, ret);
8160 unlock_user(p, arg1, 0);
8161 }
bellard31e31b82003-02-18 22:55:36 +00008162 break;
Chen Gang704eff62015-08-21 05:37:33 +08008163#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008164#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008165 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008166 {
bellard579a97f2007-11-11 14:26:47 +00008167 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008168 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008169 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008170 if (!p || !p2) {
8171 ret = -TARGET_EFAULT;
8172 } else if (is_proc_myself((const char *)p, "exe")) {
8173 char real[PATH_MAX], *temp;
8174 temp = realpath(exec_path, real);
8175 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8176 snprintf((char *)p2, arg4, "%s", real);
8177 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008178 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008179 }
bellard579a97f2007-11-11 14:26:47 +00008180 unlock_user(p2, arg3, ret);
8181 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008182 }
8183 break;
8184#endif
thse5febef2007-04-01 18:31:35 +00008185#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008186 case TARGET_NR_uselib:
8187 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008188#endif
8189#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008190 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008191 if (!(p = lock_user_string(arg1)))
8192 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008193 ret = get_errno(swapon(p, arg2));
8194 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008195 break;
thse5febef2007-04-01 18:31:35 +00008196#endif
bellard31e31b82003-02-18 22:55:36 +00008197 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008198 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8199 /* arg4 must be ignored in all other cases */
8200 p = lock_user_string(arg4);
8201 if (!p) {
8202 goto efault;
8203 }
8204 ret = get_errno(reboot(arg1, arg2, arg3, p));
8205 unlock_user(p, arg4, 0);
8206 } else {
8207 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8208 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008209 break;
thse5febef2007-04-01 18:31:35 +00008210#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008211 case TARGET_NR_readdir:
8212 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008213#endif
8214#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008215 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008216#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8217 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008218 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8219 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008220 {
blueswir1992f48a2007-10-14 16:27:31 +00008221 abi_ulong *v;
8222 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008223 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8224 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008225 v1 = tswapal(v[0]);
8226 v2 = tswapal(v[1]);
8227 v3 = tswapal(v[2]);
8228 v4 = tswapal(v[3]);
8229 v5 = tswapal(v[4]);
8230 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008231 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008232 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008233 target_to_host_bitmask(v4, mmap_flags_tbl),
8234 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008235 }
bellard31e31b82003-02-18 22:55:36 +00008236#else
ths5fafdf22007-09-16 21:08:06 +00008237 ret = get_errno(target_mmap(arg1, arg2, arg3,
8238 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008239 arg5,
8240 arg6));
bellard31e31b82003-02-18 22:55:36 +00008241#endif
bellard6fb883e2003-07-09 17:12:39 +00008242 break;
thse5febef2007-04-01 18:31:35 +00008243#endif
bellarda315a142005-01-30 22:59:18 +00008244#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008245 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008246#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008247#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008248#endif
ths5fafdf22007-09-16 21:08:06 +00008249 ret = get_errno(target_mmap(arg1, arg2, arg3,
8250 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008251 arg5,
bellardc573ff62004-01-04 15:51:36 +00008252 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008253 break;
bellarda315a142005-01-30 22:59:18 +00008254#endif
bellard31e31b82003-02-18 22:55:36 +00008255 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008256 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008257 break;
bellard9de5e442003-03-23 16:49:39 +00008258 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008259 {
Andreas Färber0429a972013-08-26 18:14:44 +02008260 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008261 /* Special hack to detect libc making the stack executable. */
8262 if ((arg3 & PROT_GROWSDOWN)
8263 && arg1 >= ts->info->stack_limit
8264 && arg1 <= ts->info->start_stack) {
8265 arg3 &= ~PROT_GROWSDOWN;
8266 arg2 = arg2 + arg1 - ts->info->stack_limit;
8267 arg1 = ts->info->stack_limit;
8268 }
8269 }
bellard54936002003-05-13 00:25:15 +00008270 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008271 break;
thse5febef2007-04-01 18:31:35 +00008272#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008273 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008274 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008275 break;
thse5febef2007-04-01 18:31:35 +00008276#endif
pbrook53a59602006-03-25 19:31:22 +00008277 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008278#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008279 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008280 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008281 break;
thse5febef2007-04-01 18:31:35 +00008282#endif
8283#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008284 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008285 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008286 break;
thse5febef2007-04-01 18:31:35 +00008287#endif
8288#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008289 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008290 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008291 break;
thse5febef2007-04-01 18:31:35 +00008292#endif
8293#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008294 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008295 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008296 break;
thse5febef2007-04-01 18:31:35 +00008297#endif
8298#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008299 case TARGET_NR_munlockall:
8300 ret = get_errno(munlockall());
8301 break;
thse5febef2007-04-01 18:31:35 +00008302#endif
bellard31e31b82003-02-18 22:55:36 +00008303 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008304 if (!(p = lock_user_string(arg1)))
8305 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008306 ret = get_errno(truncate(p, arg2));
8307 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008308 break;
8309 case TARGET_NR_ftruncate:
8310 ret = get_errno(ftruncate(arg1, arg2));
8311 break;
8312 case TARGET_NR_fchmod:
8313 ret = get_errno(fchmod(arg1, arg2));
8314 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008315#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008316 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008317 if (!(p = lock_user_string(arg2)))
8318 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008319 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008320 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008321 break;
8322#endif
bellard31e31b82003-02-18 22:55:36 +00008323 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008324 /* Note that negative values are valid for getpriority, so we must
8325 differentiate based on errno settings. */
8326 errno = 0;
8327 ret = getpriority(arg1, arg2);
8328 if (ret == -1 && errno != 0) {
8329 ret = -host_to_target_errno(errno);
8330 break;
8331 }
8332#ifdef TARGET_ALPHA
8333 /* Return value is the unbiased priority. Signal no error. */
8334 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8335#else
8336 /* Return value is a biased priority to avoid negative numbers. */
8337 ret = 20 - ret;
8338#endif
bellard31e31b82003-02-18 22:55:36 +00008339 break;
8340 case TARGET_NR_setpriority:
8341 ret = get_errno(setpriority(arg1, arg2, arg3));
8342 break;
bellardebc05482003-09-30 21:08:41 +00008343#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008344 case TARGET_NR_profil:
8345 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008346#endif
bellard31e31b82003-02-18 22:55:36 +00008347 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008348 if (!(p = lock_user_string(arg1)))
8349 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008350 ret = get_errno(statfs(path(p), &stfs));
8351 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008352 convert_statfs:
8353 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008354 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008355
bellard579a97f2007-11-11 14:26:47 +00008356 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8357 goto efault;
8358 __put_user(stfs.f_type, &target_stfs->f_type);
8359 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8360 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8361 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8362 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8363 __put_user(stfs.f_files, &target_stfs->f_files);
8364 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8365 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8366 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8367 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008368 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8369 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008370 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008371 }
8372 break;
8373 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008374 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008375 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008376#ifdef TARGET_NR_statfs64
8377 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008378 if (!(p = lock_user_string(arg1)))
8379 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008380 ret = get_errno(statfs(path(p), &stfs));
8381 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008382 convert_statfs64:
8383 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008384 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008385
bellard579a97f2007-11-11 14:26:47 +00008386 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8387 goto efault;
8388 __put_user(stfs.f_type, &target_stfs->f_type);
8389 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8390 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8391 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8392 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8393 __put_user(stfs.f_files, &target_stfs->f_files);
8394 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8395 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8396 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8397 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008398 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8399 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008400 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008401 }
8402 break;
8403 case TARGET_NR_fstatfs64:
8404 ret = get_errno(fstatfs(arg1, &stfs));
8405 goto convert_statfs64;
8406#endif
bellardebc05482003-09-30 21:08:41 +00008407#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008408 case TARGET_NR_ioperm:
8409 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008410#endif
thse5febef2007-04-01 18:31:35 +00008411#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008412 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008413 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008414 break;
thse5febef2007-04-01 18:31:35 +00008415#endif
bellard3532fa72006-06-24 15:06:03 +00008416#ifdef TARGET_NR_accept
8417 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008418 ret = do_accept4(arg1, arg2, arg3, 0);
8419 break;
8420#endif
8421#ifdef TARGET_NR_accept4
8422 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00008423 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008424 break;
8425#endif
8426#ifdef TARGET_NR_bind
8427 case TARGET_NR_bind:
8428 ret = do_bind(arg1, arg2, arg3);
8429 break;
8430#endif
8431#ifdef TARGET_NR_connect
8432 case TARGET_NR_connect:
8433 ret = do_connect(arg1, arg2, arg3);
8434 break;
8435#endif
8436#ifdef TARGET_NR_getpeername
8437 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008438 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008439 break;
8440#endif
8441#ifdef TARGET_NR_getsockname
8442 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008443 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008444 break;
8445#endif
8446#ifdef TARGET_NR_getsockopt
8447 case TARGET_NR_getsockopt:
8448 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8449 break;
8450#endif
8451#ifdef TARGET_NR_listen
8452 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008453 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008454 break;
8455#endif
8456#ifdef TARGET_NR_recv
8457 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008458 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008459 break;
8460#endif
8461#ifdef TARGET_NR_recvfrom
8462 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008463 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008464 break;
8465#endif
8466#ifdef TARGET_NR_recvmsg
8467 case TARGET_NR_recvmsg:
8468 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8469 break;
8470#endif
8471#ifdef TARGET_NR_send
8472 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008473 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008474 break;
8475#endif
8476#ifdef TARGET_NR_sendmsg
8477 case TARGET_NR_sendmsg:
8478 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8479 break;
8480#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008481#ifdef TARGET_NR_sendmmsg
8482 case TARGET_NR_sendmmsg:
8483 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8484 break;
8485 case TARGET_NR_recvmmsg:
8486 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8487 break;
8488#endif
bellard3532fa72006-06-24 15:06:03 +00008489#ifdef TARGET_NR_sendto
8490 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008491 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008492 break;
8493#endif
8494#ifdef TARGET_NR_shutdown
8495 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008496 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008497 break;
8498#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008499#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8500 case TARGET_NR_getrandom:
8501 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8502 if (!p) {
8503 goto efault;
8504 }
8505 ret = get_errno(getrandom(p, arg2, arg3));
8506 unlock_user(p, arg1, ret);
8507 break;
8508#endif
bellard3532fa72006-06-24 15:06:03 +00008509#ifdef TARGET_NR_socket
8510 case TARGET_NR_socket:
8511 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008512 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008513 break;
8514#endif
8515#ifdef TARGET_NR_socketpair
8516 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008517 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008518 break;
8519#endif
8520#ifdef TARGET_NR_setsockopt
8521 case TARGET_NR_setsockopt:
8522 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8523 break;
8524#endif
ths7494b0f2007-02-11 18:26:53 +00008525
bellard31e31b82003-02-18 22:55:36 +00008526 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008527 if (!(p = lock_user_string(arg2)))
8528 goto efault;
thse5574482007-02-11 20:03:13 +00008529 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8530 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008531 break;
8532
bellard31e31b82003-02-18 22:55:36 +00008533 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008534 {
bellard66fb9762003-03-23 01:06:05 +00008535 struct itimerval value, ovalue, *pvalue;
8536
pbrook53a59602006-03-25 19:31:22 +00008537 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008538 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008539 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8540 || copy_from_user_timeval(&pvalue->it_value,
8541 arg2 + sizeof(struct target_timeval)))
8542 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008543 } else {
8544 pvalue = NULL;
8545 }
8546 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008547 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008548 if (copy_to_user_timeval(arg3,
8549 &ovalue.it_interval)
8550 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8551 &ovalue.it_value))
8552 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008553 }
8554 }
8555 break;
bellard31e31b82003-02-18 22:55:36 +00008556 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008557 {
bellard66fb9762003-03-23 01:06:05 +00008558 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008559
bellard66fb9762003-03-23 01:06:05 +00008560 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008561 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008562 if (copy_to_user_timeval(arg2,
8563 &value.it_interval)
8564 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8565 &value.it_value))
8566 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008567 }
8568 }
8569 break;
Chen Gang704eff62015-08-21 05:37:33 +08008570#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008571 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008572 if (!(p = lock_user_string(arg1)))
8573 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008574 ret = get_errno(stat(path(p), &st));
8575 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008576 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008577#endif
8578#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008579 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008580 if (!(p = lock_user_string(arg1)))
8581 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008582 ret = get_errno(lstat(path(p), &st));
8583 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008584 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008585#endif
bellard31e31b82003-02-18 22:55:36 +00008586 case TARGET_NR_fstat:
8587 {
8588 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008589#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008590 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008591#endif
bellard31e31b82003-02-18 22:55:36 +00008592 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008593 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008594
bellard579a97f2007-11-11 14:26:47 +00008595 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8596 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008597 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008598 __put_user(st.st_dev, &target_st->st_dev);
8599 __put_user(st.st_ino, &target_st->st_ino);
8600 __put_user(st.st_mode, &target_st->st_mode);
8601 __put_user(st.st_uid, &target_st->st_uid);
8602 __put_user(st.st_gid, &target_st->st_gid);
8603 __put_user(st.st_nlink, &target_st->st_nlink);
8604 __put_user(st.st_rdev, &target_st->st_rdev);
8605 __put_user(st.st_size, &target_st->st_size);
8606 __put_user(st.st_blksize, &target_st->st_blksize);
8607 __put_user(st.st_blocks, &target_st->st_blocks);
8608 __put_user(st.st_atime, &target_st->target_st_atime);
8609 __put_user(st.st_mtime, &target_st->target_st_mtime);
8610 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008611 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008612 }
8613 }
8614 break;
bellardebc05482003-09-30 21:08:41 +00008615#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008616 case TARGET_NR_olduname:
8617 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008618#endif
8619#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008620 case TARGET_NR_iopl:
8621 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008622#endif
bellard31e31b82003-02-18 22:55:36 +00008623 case TARGET_NR_vhangup:
8624 ret = get_errno(vhangup());
8625 break;
bellardebc05482003-09-30 21:08:41 +00008626#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008627 case TARGET_NR_idle:
8628 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008629#endif
bellard42ad6ae2005-01-03 22:48:11 +00008630#ifdef TARGET_NR_syscall
8631 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008632 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8633 arg6, arg7, arg8, 0);
8634 break;
bellard42ad6ae2005-01-03 22:48:11 +00008635#endif
bellard31e31b82003-02-18 22:55:36 +00008636 case TARGET_NR_wait4:
8637 {
8638 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008639 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008640 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008641 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008642 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008643 if (target_rusage)
8644 rusage_ptr = &rusage;
8645 else
8646 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008647 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008648 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008649 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008650 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008651 if (put_user_s32(status, status_ptr))
8652 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008653 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008654 if (target_rusage) {
8655 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8656 if (rusage_err) {
8657 ret = rusage_err;
8658 }
8659 }
bellard31e31b82003-02-18 22:55:36 +00008660 }
8661 }
8662 break;
thse5febef2007-04-01 18:31:35 +00008663#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008664 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008665 if (!(p = lock_user_string(arg1)))
8666 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008667 ret = get_errno(swapoff(p));
8668 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008669 break;
thse5febef2007-04-01 18:31:35 +00008670#endif
bellard31e31b82003-02-18 22:55:36 +00008671 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008672 {
pbrook53a59602006-03-25 19:31:22 +00008673 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008674 struct sysinfo value;
8675 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008676 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008677 {
bellard579a97f2007-11-11 14:26:47 +00008678 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8679 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008680 __put_user(value.uptime, &target_value->uptime);
8681 __put_user(value.loads[0], &target_value->loads[0]);
8682 __put_user(value.loads[1], &target_value->loads[1]);
8683 __put_user(value.loads[2], &target_value->loads[2]);
8684 __put_user(value.totalram, &target_value->totalram);
8685 __put_user(value.freeram, &target_value->freeram);
8686 __put_user(value.sharedram, &target_value->sharedram);
8687 __put_user(value.bufferram, &target_value->bufferram);
8688 __put_user(value.totalswap, &target_value->totalswap);
8689 __put_user(value.freeswap, &target_value->freeswap);
8690 __put_user(value.procs, &target_value->procs);
8691 __put_user(value.totalhigh, &target_value->totalhigh);
8692 __put_user(value.freehigh, &target_value->freehigh);
8693 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008694 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008695 }
8696 }
8697 break;
thse5febef2007-04-01 18:31:35 +00008698#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008699 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008700 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8701 break;
thse5febef2007-04-01 18:31:35 +00008702#endif
aurel32e5289082009-04-18 16:16:12 +00008703#ifdef TARGET_NR_semget
8704 case TARGET_NR_semget:
8705 ret = get_errno(semget(arg1, arg2, arg3));
8706 break;
8707#endif
8708#ifdef TARGET_NR_semop
8709 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008710 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008711 break;
8712#endif
8713#ifdef TARGET_NR_semctl
8714 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008715 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008716 break;
8717#endif
aurel32eeb438c2008-10-13 21:08:55 +00008718#ifdef TARGET_NR_msgctl
8719 case TARGET_NR_msgctl:
8720 ret = do_msgctl(arg1, arg2, arg3);
8721 break;
8722#endif
8723#ifdef TARGET_NR_msgget
8724 case TARGET_NR_msgget:
8725 ret = get_errno(msgget(arg1, arg2));
8726 break;
8727#endif
8728#ifdef TARGET_NR_msgrcv
8729 case TARGET_NR_msgrcv:
8730 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8731 break;
8732#endif
8733#ifdef TARGET_NR_msgsnd
8734 case TARGET_NR_msgsnd:
8735 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8736 break;
8737#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008738#ifdef TARGET_NR_shmget
8739 case TARGET_NR_shmget:
8740 ret = get_errno(shmget(arg1, arg2, arg3));
8741 break;
8742#endif
8743#ifdef TARGET_NR_shmctl
8744 case TARGET_NR_shmctl:
8745 ret = do_shmctl(arg1, arg2, arg3);
8746 break;
8747#endif
8748#ifdef TARGET_NR_shmat
8749 case TARGET_NR_shmat:
8750 ret = do_shmat(arg1, arg2, arg3);
8751 break;
8752#endif
8753#ifdef TARGET_NR_shmdt
8754 case TARGET_NR_shmdt:
8755 ret = do_shmdt(arg1);
8756 break;
8757#endif
bellard31e31b82003-02-18 22:55:36 +00008758 case TARGET_NR_fsync:
8759 ret = get_errno(fsync(arg1));
8760 break;
bellard31e31b82003-02-18 22:55:36 +00008761 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008762 /* Linux manages to have three different orderings for its
8763 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8764 * match the kernel's CONFIG_CLONE_* settings.
8765 * Microblaze is further special in that it uses a sixth
8766 * implicit argument to clone for the TLS pointer.
8767 */
8768#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008769 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008770#elif defined(TARGET_CLONE_BACKWARDS)
8771 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8772#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008773 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008774#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008775 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008776#endif
bellard1b6b0292003-03-22 17:31:38 +00008777 break;
bellardec86b0f2003-04-11 00:15:04 +00008778#ifdef __NR_exit_group
8779 /* new thread calls */
8780 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008781#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008782 _mcleanup();
8783#endif
bellarde9009672005-04-26 20:42:36 +00008784 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008785 ret = get_errno(exit_group(arg1));
8786 break;
8787#endif
bellard31e31b82003-02-18 22:55:36 +00008788 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008789 if (!(p = lock_user_string(arg1)))
8790 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008791 ret = get_errno(setdomainname(p, arg2));
8792 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008793 break;
8794 case TARGET_NR_uname:
8795 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008796 {
8797 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008798
bellard579a97f2007-11-11 14:26:47 +00008799 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8800 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008801 ret = get_errno(sys_uname(buf));
8802 if (!is_error(ret)) {
8803 /* Overrite the native machine name with whatever is being
8804 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01008805 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008806 /* Allow the user to override the reported release. */
8807 if (qemu_uname_release && *qemu_uname_release)
8808 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008809 }
pbrook53a59602006-03-25 19:31:22 +00008810 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008811 }
bellard31e31b82003-02-18 22:55:36 +00008812 break;
bellard6dbad632003-03-16 18:05:05 +00008813#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008814 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008815 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008816 break;
j_mayer84409dd2007-04-06 08:56:50 +00008817#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008818 case TARGET_NR_vm86old:
8819 goto unimplemented;
8820 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008821 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008822 break;
8823#endif
j_mayer84409dd2007-04-06 08:56:50 +00008824#endif
bellard31e31b82003-02-18 22:55:36 +00008825 case TARGET_NR_adjtimex:
8826 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008827#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008828 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008829#endif
bellard31e31b82003-02-18 22:55:36 +00008830 case TARGET_NR_init_module:
8831 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008832#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008833 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008834#endif
bellard31e31b82003-02-18 22:55:36 +00008835 goto unimplemented;
8836 case TARGET_NR_quotactl:
8837 goto unimplemented;
8838 case TARGET_NR_getpgid:
8839 ret = get_errno(getpgid(arg1));
8840 break;
8841 case TARGET_NR_fchdir:
8842 ret = get_errno(fchdir(arg1));
8843 break;
j_mayer84409dd2007-04-06 08:56:50 +00008844#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008845 case TARGET_NR_bdflush:
8846 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008847#endif
thse5febef2007-04-01 18:31:35 +00008848#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008849 case TARGET_NR_sysfs:
8850 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008851#endif
bellard31e31b82003-02-18 22:55:36 +00008852 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008853 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008854 break;
thse5febef2007-04-01 18:31:35 +00008855#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008856 case TARGET_NR_afs_syscall:
8857 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008858#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008859#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008860 case TARGET_NR__llseek:
8861 {
8862 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008863#if !defined(__NR_llseek)
8864 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8865 if (res == -1) {
8866 ret = get_errno(res);
8867 } else {
8868 ret = 0;
8869 }
8870#else
bellard31e31b82003-02-18 22:55:36 +00008871 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008872#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008873 if ((ret == 0) && put_user_s64(res, arg4)) {
8874 goto efault;
8875 }
bellard31e31b82003-02-18 22:55:36 +00008876 }
8877 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008878#endif
Chen Gang704eff62015-08-21 05:37:33 +08008879#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008880 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008881#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008882#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008883 {
pbrook53a59602006-03-25 19:31:22 +00008884 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008885 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008886 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008887
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308888 dirp = g_try_malloc(count);
8889 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008890 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008891 goto fail;
8892 }
ths3b46e622007-09-17 08:09:54 +00008893
bellard4add45b2003-06-05 01:52:59 +00008894 ret = get_errno(sys_getdents(arg1, dirp, count));
8895 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008896 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008897 struct target_dirent *tde;
8898 int len = ret;
8899 int reclen, treclen;
8900 int count1, tnamelen;
8901
8902 count1 = 0;
8903 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008904 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8905 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008906 tde = target_dirp;
8907 while (len > 0) {
8908 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008909 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8910 assert(tnamelen >= 0);
8911 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8912 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008913 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008914 tde->d_ino = tswapal(de->d_ino);
8915 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008916 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008917 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008918 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008919 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008920 count1 += treclen;
8921 }
8922 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008923 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008924 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308925 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008926 }
8927#else
bellard31e31b82003-02-18 22:55:36 +00008928 {
aurel326556a832008-10-13 21:08:17 +00008929 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008930 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008931
bellard579a97f2007-11-11 14:26:47 +00008932 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8933 goto efault;
bellard72f03902003-02-18 23:33:18 +00008934 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008935 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008936 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008937 int len = ret;
8938 int reclen;
8939 de = dirp;
8940 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008941 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008942 if (reclen > len)
8943 break;
bellard8083a3e2003-03-24 23:12:16 +00008944 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008945 tswapls(&de->d_ino);
8946 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008947 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008948 len -= reclen;
8949 }
8950 }
pbrook53a59602006-03-25 19:31:22 +00008951 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008952 }
bellard4add45b2003-06-05 01:52:59 +00008953#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008954#else
8955 /* Implement getdents in terms of getdents64 */
8956 {
8957 struct linux_dirent64 *dirp;
8958 abi_long count = arg3;
8959
8960 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8961 if (!dirp) {
8962 goto efault;
8963 }
8964 ret = get_errno(sys_getdents64(arg1, dirp, count));
8965 if (!is_error(ret)) {
8966 /* Convert the dirent64 structs to target dirent. We do this
8967 * in-place, since we can guarantee that a target_dirent is no
8968 * larger than a dirent64; however this means we have to be
8969 * careful to read everything before writing in the new format.
8970 */
8971 struct linux_dirent64 *de;
8972 struct target_dirent *tde;
8973 int len = ret;
8974 int tlen = 0;
8975
8976 de = dirp;
8977 tde = (struct target_dirent *)dirp;
8978 while (len > 0) {
8979 int namelen, treclen;
8980 int reclen = de->d_reclen;
8981 uint64_t ino = de->d_ino;
8982 int64_t off = de->d_off;
8983 uint8_t type = de->d_type;
8984
8985 namelen = strlen(de->d_name);
8986 treclen = offsetof(struct target_dirent, d_name)
8987 + namelen + 2;
8988 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8989
8990 memmove(tde->d_name, de->d_name, namelen + 1);
8991 tde->d_ino = tswapal(ino);
8992 tde->d_off = tswapal(off);
8993 tde->d_reclen = tswap16(treclen);
8994 /* The target_dirent type is in what was formerly a padding
8995 * byte at the end of the structure:
8996 */
8997 *(((char *)tde) + treclen - 1) = type;
8998
8999 de = (struct linux_dirent64 *)((char *)de + reclen);
9000 tde = (struct target_dirent *)((char *)tde + treclen);
9001 len -= reclen;
9002 tlen += treclen;
9003 }
9004 ret = tlen;
9005 }
9006 unlock_user(dirp, arg2, ret);
9007 }
9008#endif
bellard31e31b82003-02-18 22:55:36 +00009009 break;
Chen Gang704eff62015-08-21 05:37:33 +08009010#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009011#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009012 case TARGET_NR_getdents64:
9013 {
aurel326556a832008-10-13 21:08:17 +00009014 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009015 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009016 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9017 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009018 ret = get_errno(sys_getdents64(arg1, dirp, count));
9019 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009020 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009021 int len = ret;
9022 int reclen;
9023 de = dirp;
9024 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009025 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009026 if (reclen > len)
9027 break;
bellard8083a3e2003-03-24 23:12:16 +00009028 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009029 tswap64s((uint64_t *)&de->d_ino);
9030 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009031 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009032 len -= reclen;
9033 }
9034 }
pbrook53a59602006-03-25 19:31:22 +00009035 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009036 }
9037 break;
bellarda541f292004-04-12 20:39:29 +00009038#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009039#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009040 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009041 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009042 break;
thse5febef2007-04-01 18:31:35 +00009043#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009044#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9045# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009046 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009047# endif
9048# ifdef TARGET_NR_ppoll
9049 case TARGET_NR_ppoll:
9050# endif
bellard9de5e442003-03-23 16:49:39 +00009051 {
pbrook53a59602006-03-25 19:31:22 +00009052 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009053 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009054 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009055 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009056
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009057 pfd = NULL;
9058 target_pfd = NULL;
9059 if (nfds) {
9060 target_pfd = lock_user(VERIFY_WRITE, arg1,
9061 sizeof(struct target_pollfd) * nfds, 1);
9062 if (!target_pfd) {
9063 goto efault;
9064 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009065
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009066 pfd = alloca(sizeof(struct pollfd) * nfds);
9067 for (i = 0; i < nfds; i++) {
9068 pfd[i].fd = tswap32(target_pfd[i].fd);
9069 pfd[i].events = tswap16(target_pfd[i].events);
9070 }
bellard9de5e442003-03-23 16:49:39 +00009071 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009072
Peter Maydella6130232016-06-06 19:58:10 +01009073 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009074# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009075 case TARGET_NR_ppoll:
9076 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009077 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9078 target_sigset_t *target_set;
9079 sigset_t _set, *set = &_set;
9080
9081 if (arg3) {
9082 if (target_to_host_timespec(timeout_ts, arg3)) {
9083 unlock_user(target_pfd, arg1, 0);
9084 goto efault;
9085 }
9086 } else {
9087 timeout_ts = NULL;
9088 }
9089
9090 if (arg4) {
9091 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9092 if (!target_set) {
9093 unlock_user(target_pfd, arg1, 0);
9094 goto efault;
9095 }
9096 target_to_host_sigset(set, target_set);
9097 } else {
9098 set = NULL;
9099 }
9100
Peter Maydella6130232016-06-06 19:58:10 +01009101 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9102 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009103
9104 if (!is_error(ret) && arg3) {
9105 host_to_target_timespec(arg3, timeout_ts);
9106 }
9107 if (arg4) {
9108 unlock_user(target_set, arg4, 0);
9109 }
Peter Maydella6130232016-06-06 19:58:10 +01009110 break;
9111 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009112# endif
Peter Maydella6130232016-06-06 19:58:10 +01009113# ifdef TARGET_NR_poll
9114 case TARGET_NR_poll:
9115 {
9116 struct timespec ts, *pts;
9117
9118 if (arg3 >= 0) {
9119 /* Convert ms to secs, ns */
9120 ts.tv_sec = arg3 / 1000;
9121 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9122 pts = &ts;
9123 } else {
9124 /* -ve poll() timeout means "infinite" */
9125 pts = NULL;
9126 }
9127 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9128 break;
9129 }
9130# endif
9131 default:
9132 g_assert_not_reached();
9133 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009134
bellard9de5e442003-03-23 16:49:39 +00009135 if (!is_error(ret)) {
9136 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009137 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009138 }
9139 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009140 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009141 }
9142 break;
thse5febef2007-04-01 18:31:35 +00009143#endif
bellard31e31b82003-02-18 22:55:36 +00009144 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009145 /* NOTE: the flock constant seems to be the same for every
9146 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009147 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009148 break;
9149 case TARGET_NR_readv:
9150 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009151 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9152 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009153 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009154 unlock_iovec(vec, arg2, arg3, 1);
9155 } else {
9156 ret = -host_to_target_errno(errno);
9157 }
bellard31e31b82003-02-18 22:55:36 +00009158 }
9159 break;
9160 case TARGET_NR_writev:
9161 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009162 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9163 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009164 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009165 unlock_iovec(vec, arg2, arg3, 0);
9166 } else {
9167 ret = -host_to_target_errno(errno);
9168 }
bellard31e31b82003-02-18 22:55:36 +00009169 }
9170 break;
9171 case TARGET_NR_getsid:
9172 ret = get_errno(getsid(arg1));
9173 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009174#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009175 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009176 ret = get_errno(fdatasync(arg1));
9177 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009178#endif
Chen Gang704eff62015-08-21 05:37:33 +08009179#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009180 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009181 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009182 return value. */
ths0da46a62007-10-20 20:23:07 +00009183 ret = -TARGET_ENOTDIR;
9184 break;
Chen Gang704eff62015-08-21 05:37:33 +08009185#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009186 case TARGET_NR_sched_getaffinity:
9187 {
9188 unsigned int mask_size;
9189 unsigned long *mask;
9190
9191 /*
9192 * sched_getaffinity needs multiples of ulong, so need to take
9193 * care of mismatches between target ulong and host ulong sizes.
9194 */
9195 if (arg2 & (sizeof(abi_ulong) - 1)) {
9196 ret = -TARGET_EINVAL;
9197 break;
9198 }
9199 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9200
9201 mask = alloca(mask_size);
9202 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9203
9204 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009205 if (ret > arg2) {
9206 /* More data returned than the caller's buffer will fit.
9207 * This only happens if sizeof(abi_long) < sizeof(long)
9208 * and the caller passed us a buffer holding an odd number
9209 * of abi_longs. If the host kernel is actually using the
9210 * extra 4 bytes then fail EINVAL; otherwise we can just
9211 * ignore them and only copy the interesting part.
9212 */
9213 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9214 if (numcpus > arg2 * 8) {
9215 ret = -TARGET_EINVAL;
9216 break;
9217 }
9218 ret = arg2;
9219 }
9220
Mike McCormackcd18f052011-04-18 14:43:36 +09009221 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009222 goto efault;
9223 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009224 }
9225 }
9226 break;
9227 case TARGET_NR_sched_setaffinity:
9228 {
9229 unsigned int mask_size;
9230 unsigned long *mask;
9231
9232 /*
9233 * sched_setaffinity needs multiples of ulong, so need to take
9234 * care of mismatches between target ulong and host ulong sizes.
9235 */
9236 if (arg2 & (sizeof(abi_ulong) - 1)) {
9237 ret = -TARGET_EINVAL;
9238 break;
9239 }
9240 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9241
9242 mask = alloca(mask_size);
9243 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9244 goto efault;
9245 }
9246 memcpy(mask, p, arg2);
9247 unlock_user_struct(p, arg2, 0);
9248
9249 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9250 }
9251 break;
bellard31e31b82003-02-18 22:55:36 +00009252 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009253 {
pbrook53a59602006-03-25 19:31:22 +00009254 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009255 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009256
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009257 if (arg2 == 0) {
9258 return -TARGET_EINVAL;
9259 }
bellard579a97f2007-11-11 14:26:47 +00009260 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9261 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009262 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009263 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009264 ret = get_errno(sched_setparam(arg1, &schp));
9265 }
9266 break;
bellard31e31b82003-02-18 22:55:36 +00009267 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009268 {
pbrook53a59602006-03-25 19:31:22 +00009269 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009270 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009271
9272 if (arg2 == 0) {
9273 return -TARGET_EINVAL;
9274 }
bellard5cd43932003-03-29 16:54:36 +00009275 ret = get_errno(sched_getparam(arg1, &schp));
9276 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009277 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9278 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009279 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009280 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009281 }
9282 }
9283 break;
bellard31e31b82003-02-18 22:55:36 +00009284 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009285 {
pbrook53a59602006-03-25 19:31:22 +00009286 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009287 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009288 if (arg3 == 0) {
9289 return -TARGET_EINVAL;
9290 }
bellard579a97f2007-11-11 14:26:47 +00009291 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9292 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009293 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009294 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009295 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9296 }
9297 break;
bellard31e31b82003-02-18 22:55:36 +00009298 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009299 ret = get_errno(sched_getscheduler(arg1));
9300 break;
bellard31e31b82003-02-18 22:55:36 +00009301 case TARGET_NR_sched_yield:
9302 ret = get_errno(sched_yield());
9303 break;
9304 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009305 ret = get_errno(sched_get_priority_max(arg1));
9306 break;
bellard31e31b82003-02-18 22:55:36 +00009307 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009308 ret = get_errno(sched_get_priority_min(arg1));
9309 break;
bellard31e31b82003-02-18 22:55:36 +00009310 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009311 {
bellard5cd43932003-03-29 16:54:36 +00009312 struct timespec ts;
9313 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9314 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009315 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009316 }
9317 }
9318 break;
bellard31e31b82003-02-18 22:55:36 +00009319 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009320 {
bellard1b6b0292003-03-22 17:31:38 +00009321 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009322 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009323 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009324 if (is_error(ret) && arg2) {
9325 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009326 }
9327 }
9328 break;
thse5febef2007-04-01 18:31:35 +00009329#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009330 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009331 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009332#endif
9333#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009334 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009335 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009336#endif
bellard31e31b82003-02-18 22:55:36 +00009337 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009338 switch (arg1) {
9339 case PR_GET_PDEATHSIG:
9340 {
9341 int deathsig;
9342 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9343 if (!is_error(ret) && arg2
9344 && put_user_ual(deathsig, arg2)) {
9345 goto efault;
thse5574482007-02-11 20:03:13 +00009346 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009347 break;
9348 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009349#ifdef PR_GET_NAME
9350 case PR_GET_NAME:
9351 {
9352 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9353 if (!name) {
9354 goto efault;
9355 }
9356 ret = get_errno(prctl(arg1, (unsigned long)name,
9357 arg3, arg4, arg5));
9358 unlock_user(name, arg2, 16);
9359 break;
9360 }
9361 case PR_SET_NAME:
9362 {
9363 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9364 if (!name) {
9365 goto efault;
9366 }
9367 ret = get_errno(prctl(arg1, (unsigned long)name,
9368 arg3, arg4, arg5));
9369 unlock_user(name, arg2, 0);
9370 break;
9371 }
9372#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009373 default:
9374 /* Most prctl options have no pointer arguments */
9375 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9376 break;
9377 }
ths39b9aae2007-02-11 18:36:44 +00009378 break;
bellardd2fd1af2007-11-14 18:08:56 +00009379#ifdef TARGET_NR_arch_prctl
9380 case TARGET_NR_arch_prctl:
9381#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9382 ret = do_arch_prctl(cpu_env, arg1, arg2);
9383 break;
9384#else
9385 goto unimplemented;
9386#endif
9387#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009388#ifdef TARGET_NR_pread64
9389 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009390 if (regpairs_aligned(cpu_env)) {
9391 arg4 = arg5;
9392 arg5 = arg6;
9393 }
aurel32f2c7ba12008-03-28 22:32:06 +00009394 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9395 goto efault;
9396 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9397 unlock_user(p, arg2, ret);
9398 break;
9399 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009400 if (regpairs_aligned(cpu_env)) {
9401 arg4 = arg5;
9402 arg5 = arg6;
9403 }
aurel32f2c7ba12008-03-28 22:32:06 +00009404 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9405 goto efault;
9406 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9407 unlock_user(p, arg2, 0);
9408 break;
9409#endif
bellard31e31b82003-02-18 22:55:36 +00009410 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009411 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9412 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009413 ret = get_errno(sys_getcwd1(p, arg2));
9414 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009415 break;
9416 case TARGET_NR_capget:
9417 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009418 {
9419 struct target_user_cap_header *target_header;
9420 struct target_user_cap_data *target_data = NULL;
9421 struct __user_cap_header_struct header;
9422 struct __user_cap_data_struct data[2];
9423 struct __user_cap_data_struct *dataptr = NULL;
9424 int i, target_datalen;
9425 int data_items = 1;
9426
9427 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9428 goto efault;
9429 }
9430 header.version = tswap32(target_header->version);
9431 header.pid = tswap32(target_header->pid);
9432
Peter Maydellec864872014-03-19 16:07:30 +00009433 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009434 /* Version 2 and up takes pointer to two user_data structs */
9435 data_items = 2;
9436 }
9437
9438 target_datalen = sizeof(*target_data) * data_items;
9439
9440 if (arg2) {
9441 if (num == TARGET_NR_capget) {
9442 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9443 } else {
9444 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9445 }
9446 if (!target_data) {
9447 unlock_user_struct(target_header, arg1, 0);
9448 goto efault;
9449 }
9450
9451 if (num == TARGET_NR_capset) {
9452 for (i = 0; i < data_items; i++) {
9453 data[i].effective = tswap32(target_data[i].effective);
9454 data[i].permitted = tswap32(target_data[i].permitted);
9455 data[i].inheritable = tswap32(target_data[i].inheritable);
9456 }
9457 }
9458
9459 dataptr = data;
9460 }
9461
9462 if (num == TARGET_NR_capget) {
9463 ret = get_errno(capget(&header, dataptr));
9464 } else {
9465 ret = get_errno(capset(&header, dataptr));
9466 }
9467
9468 /* The kernel always updates version for both capget and capset */
9469 target_header->version = tswap32(header.version);
9470 unlock_user_struct(target_header, arg1, 1);
9471
9472 if (arg2) {
9473 if (num == TARGET_NR_capget) {
9474 for (i = 0; i < data_items; i++) {
9475 target_data[i].effective = tswap32(data[i].effective);
9476 target_data[i].permitted = tswap32(data[i].permitted);
9477 target_data[i].inheritable = tswap32(data[i].inheritable);
9478 }
9479 unlock_user(target_data, arg2, target_datalen);
9480 } else {
9481 unlock_user(target_data, arg2, 0);
9482 }
9483 }
9484 break;
9485 }
bellard31e31b82003-02-18 22:55:36 +00009486 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009487 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009488 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009489
9490#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009491 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009492 {
9493 off_t *offp = NULL;
9494 off_t off;
9495 if (arg3) {
9496 ret = get_user_sal(off, arg3);
9497 if (is_error(ret)) {
9498 break;
9499 }
9500 offp = &off;
9501 }
9502 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9503 if (!is_error(ret) && arg3) {
9504 abi_long ret2 = put_user_sal(off, arg3);
9505 if (is_error(ret2)) {
9506 ret = ret2;
9507 }
9508 }
9509 break;
9510 }
9511#ifdef TARGET_NR_sendfile64
9512 case TARGET_NR_sendfile64:
9513 {
9514 off_t *offp = NULL;
9515 off_t off;
9516 if (arg3) {
9517 ret = get_user_s64(off, arg3);
9518 if (is_error(ret)) {
9519 break;
9520 }
9521 offp = &off;
9522 }
9523 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9524 if (!is_error(ret) && arg3) {
9525 abi_long ret2 = put_user_s64(off, arg3);
9526 if (is_error(ret2)) {
9527 ret = ret2;
9528 }
9529 }
9530 break;
9531 }
9532#endif
9533#else
9534 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009535#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009536 case TARGET_NR_sendfile64:
9537#endif
bellard5cd43932003-03-29 16:54:36 +00009538 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009539#endif
9540
bellardebc05482003-09-30 21:08:41 +00009541#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009542 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009543 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009544#endif
9545#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009546 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009547 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009548#endif
bellard048f6b42005-11-26 18:47:20 +00009549#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009550 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009551 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9552 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009553 break;
bellard048f6b42005-11-26 18:47:20 +00009554#endif
bellardebc05482003-09-30 21:08:41 +00009555#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009556 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009557 {
9558 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009559 int resource = target_to_host_resource(arg1);
9560 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009561 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009562 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009563 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9564 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009565 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9566 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009567 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009568 }
9569 break;
9570 }
bellardebc05482003-09-30 21:08:41 +00009571#endif
bellarda315a142005-01-30 22:59:18 +00009572#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009573 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009574 if (!(p = lock_user_string(arg1)))
9575 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009576 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9577 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009578 break;
bellarda315a142005-01-30 22:59:18 +00009579#endif
9580#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009581 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009582 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009583 break;
bellarda315a142005-01-30 22:59:18 +00009584#endif
9585#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009586 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009587 if (!(p = lock_user_string(arg1)))
9588 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009589 ret = get_errno(stat(path(p), &st));
9590 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009591 if (!is_error(ret))
9592 ret = host_to_target_stat64(cpu_env, arg2, &st);
9593 break;
bellarda315a142005-01-30 22:59:18 +00009594#endif
9595#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009596 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009597 if (!(p = lock_user_string(arg1)))
9598 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009599 ret = get_errno(lstat(path(p), &st));
9600 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009601 if (!is_error(ret))
9602 ret = host_to_target_stat64(cpu_env, arg2, &st);
9603 break;
bellarda315a142005-01-30 22:59:18 +00009604#endif
9605#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009606 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009607 ret = get_errno(fstat(arg1, &st));
9608 if (!is_error(ret))
9609 ret = host_to_target_stat64(cpu_env, arg2, &st);
9610 break;
bellardec86b0f2003-04-11 00:15:04 +00009611#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009612#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009613#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009614 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009615#endif
9616#ifdef TARGET_NR_newfstatat
9617 case TARGET_NR_newfstatat:
9618#endif
balrog6a24a772008-09-20 02:23:36 +00009619 if (!(p = lock_user_string(arg2)))
9620 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009621 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009622 if (!is_error(ret))
9623 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009624 break;
bellarda315a142005-01-30 22:59:18 +00009625#endif
Chen Gang704eff62015-08-21 05:37:33 +08009626#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009627 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009628 if (!(p = lock_user_string(arg1)))
9629 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009630 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9631 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009632 break;
Chen Gang704eff62015-08-21 05:37:33 +08009633#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009634#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009635 case TARGET_NR_getuid:
9636 ret = get_errno(high2lowuid(getuid()));
9637 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009638#endif
9639#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009640 case TARGET_NR_getgid:
9641 ret = get_errno(high2lowgid(getgid()));
9642 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009643#endif
9644#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009645 case TARGET_NR_geteuid:
9646 ret = get_errno(high2lowuid(geteuid()));
9647 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009648#endif
9649#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009650 case TARGET_NR_getegid:
9651 ret = get_errno(high2lowgid(getegid()));
9652 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009653#endif
bellard67867302003-11-23 17:05:30 +00009654 case TARGET_NR_setreuid:
9655 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9656 break;
9657 case TARGET_NR_setregid:
9658 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9659 break;
9660 case TARGET_NR_getgroups:
9661 {
9662 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009663 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009664 gid_t *grouplist;
9665 int i;
9666
9667 grouplist = alloca(gidsetsize * sizeof(gid_t));
9668 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009669 if (gidsetsize == 0)
9670 break;
bellard67867302003-11-23 17:05:30 +00009671 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009672 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009673 if (!target_grouplist)
9674 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009675 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009676 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009677 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009678 }
9679 }
9680 break;
9681 case TARGET_NR_setgroups:
9682 {
9683 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009684 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009685 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009686 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009687 if (gidsetsize) {
9688 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009689 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009690 if (!target_grouplist) {
9691 ret = -TARGET_EFAULT;
9692 goto fail;
9693 }
9694 for (i = 0; i < gidsetsize; i++) {
9695 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9696 }
9697 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009698 }
bellard67867302003-11-23 17:05:30 +00009699 ret = get_errno(setgroups(gidsetsize, grouplist));
9700 }
9701 break;
9702 case TARGET_NR_fchown:
9703 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9704 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009705#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009706 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009707 if (!(p = lock_user_string(arg2)))
9708 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009709 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9710 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009711 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009712 break;
9713#endif
bellard67867302003-11-23 17:05:30 +00009714#ifdef TARGET_NR_setresuid
9715 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009716 ret = get_errno(sys_setresuid(low2highuid(arg1),
9717 low2highuid(arg2),
9718 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009719 break;
9720#endif
9721#ifdef TARGET_NR_getresuid
9722 case TARGET_NR_getresuid:
9723 {
pbrook53a59602006-03-25 19:31:22 +00009724 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009725 ret = get_errno(getresuid(&ruid, &euid, &suid));
9726 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009727 if (put_user_id(high2lowuid(ruid), arg1)
9728 || put_user_id(high2lowuid(euid), arg2)
9729 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009730 goto efault;
bellard67867302003-11-23 17:05:30 +00009731 }
9732 }
9733 break;
9734#endif
9735#ifdef TARGET_NR_getresgid
9736 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009737 ret = get_errno(sys_setresgid(low2highgid(arg1),
9738 low2highgid(arg2),
9739 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009740 break;
9741#endif
9742#ifdef TARGET_NR_getresgid
9743 case TARGET_NR_getresgid:
9744 {
pbrook53a59602006-03-25 19:31:22 +00009745 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009746 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9747 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009748 if (put_user_id(high2lowgid(rgid), arg1)
9749 || put_user_id(high2lowgid(egid), arg2)
9750 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009751 goto efault;
bellard67867302003-11-23 17:05:30 +00009752 }
9753 }
9754 break;
9755#endif
Chen Gang704eff62015-08-21 05:37:33 +08009756#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009757 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009758 if (!(p = lock_user_string(arg1)))
9759 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009760 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9761 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009762 break;
Chen Gang704eff62015-08-21 05:37:33 +08009763#endif
bellard67867302003-11-23 17:05:30 +00009764 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009765 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009766 break;
9767 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009768 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009769 break;
9770 case TARGET_NR_setfsuid:
9771 ret = get_errno(setfsuid(arg1));
9772 break;
9773 case TARGET_NR_setfsgid:
9774 ret = get_errno(setfsgid(arg1));
9775 break;
bellard67867302003-11-23 17:05:30 +00009776
bellarda315a142005-01-30 22:59:18 +00009777#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009778 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009779 if (!(p = lock_user_string(arg1)))
9780 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009781 ret = get_errno(lchown(p, arg2, arg3));
9782 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009783 break;
bellarda315a142005-01-30 22:59:18 +00009784#endif
9785#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009786 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009787 ret = get_errno(getuid());
9788 break;
bellarda315a142005-01-30 22:59:18 +00009789#endif
aurel3264b4d282008-11-14 17:20:15 +00009790
9791#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9792 /* Alpha specific */
9793 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009794 {
9795 uid_t euid;
9796 euid=geteuid();
9797 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9798 }
aurel3264b4d282008-11-14 17:20:15 +00009799 ret = get_errno(getuid());
9800 break;
9801#endif
9802#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9803 /* Alpha specific */
9804 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009805 {
9806 uid_t egid;
9807 egid=getegid();
9808 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9809 }
aurel3264b4d282008-11-14 17:20:15 +00009810 ret = get_errno(getgid());
9811 break;
9812#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009813#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9814 /* Alpha specific */
9815 case TARGET_NR_osf_getsysinfo:
9816 ret = -TARGET_EOPNOTSUPP;
9817 switch (arg1) {
9818 case TARGET_GSI_IEEE_FP_CONTROL:
9819 {
9820 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9821
9822 /* Copied from linux ieee_fpcr_to_swcr. */
9823 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9824 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9825 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9826 | SWCR_TRAP_ENABLE_DZE
9827 | SWCR_TRAP_ENABLE_OVF);
9828 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9829 | SWCR_TRAP_ENABLE_INE);
9830 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9831 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9832
9833 if (put_user_u64 (swcr, arg2))
9834 goto efault;
9835 ret = 0;
9836 }
9837 break;
9838
9839 /* case GSI_IEEE_STATE_AT_SIGNAL:
9840 -- Not implemented in linux kernel.
9841 case GSI_UACPROC:
9842 -- Retrieves current unaligned access state; not much used.
9843 case GSI_PROC_TYPE:
9844 -- Retrieves implver information; surely not used.
9845 case GSI_GET_HWRPB:
9846 -- Grabs a copy of the HWRPB; surely not used.
9847 */
9848 }
9849 break;
9850#endif
9851#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9852 /* Alpha specific */
9853 case TARGET_NR_osf_setsysinfo:
9854 ret = -TARGET_EOPNOTSUPP;
9855 switch (arg1) {
9856 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009857 {
9858 uint64_t swcr, fpcr, orig_fpcr;
9859
Richard Henderson6e06d512012-06-01 09:08:21 -07009860 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009861 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009862 }
9863 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009864 fpcr = orig_fpcr & FPCR_DYN_MASK;
9865
9866 /* Copied from linux ieee_swcr_to_fpcr. */
9867 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9868 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9869 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9870 | SWCR_TRAP_ENABLE_DZE
9871 | SWCR_TRAP_ENABLE_OVF)) << 48;
9872 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9873 | SWCR_TRAP_ENABLE_INE)) << 57;
9874 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9875 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9876
Richard Henderson6e06d512012-06-01 09:08:21 -07009877 cpu_alpha_store_fpcr(cpu_env, fpcr);
9878 ret = 0;
9879 }
9880 break;
9881
9882 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9883 {
9884 uint64_t exc, fpcr, orig_fpcr;
9885 int si_code;
9886
9887 if (get_user_u64(exc, arg2)) {
9888 goto efault;
9889 }
9890
9891 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9892
9893 /* We only add to the exception status here. */
9894 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9895
9896 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009897 ret = 0;
9898
Richard Henderson6e06d512012-06-01 09:08:21 -07009899 /* Old exceptions are not signaled. */
9900 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009901
Richard Henderson6e06d512012-06-01 09:08:21 -07009902 /* If any exceptions set by this call,
9903 and are unmasked, send a signal. */
9904 si_code = 0;
9905 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9906 si_code = TARGET_FPE_FLTRES;
9907 }
9908 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9909 si_code = TARGET_FPE_FLTUND;
9910 }
9911 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9912 si_code = TARGET_FPE_FLTOVF;
9913 }
9914 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9915 si_code = TARGET_FPE_FLTDIV;
9916 }
9917 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9918 si_code = TARGET_FPE_FLTINV;
9919 }
9920 if (si_code != 0) {
9921 target_siginfo_t info;
9922 info.si_signo = SIGFPE;
9923 info.si_errno = 0;
9924 info.si_code = si_code;
9925 info._sifields._sigfault._addr
9926 = ((CPUArchState *)cpu_env)->pc;
9927 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009928 }
9929 }
9930 break;
9931
9932 /* case SSI_NVPAIRS:
9933 -- Used with SSIN_UACPROC to enable unaligned accesses.
9934 case SSI_IEEE_STATE_AT_SIGNAL:
9935 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9936 -- Not implemented in linux kernel
9937 */
9938 }
9939 break;
9940#endif
9941#ifdef TARGET_NR_osf_sigprocmask
9942 /* Alpha specific. */
9943 case TARGET_NR_osf_sigprocmask:
9944 {
9945 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009946 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009947 sigset_t set, oldset;
9948
9949 switch(arg1) {
9950 case TARGET_SIG_BLOCK:
9951 how = SIG_BLOCK;
9952 break;
9953 case TARGET_SIG_UNBLOCK:
9954 how = SIG_UNBLOCK;
9955 break;
9956 case TARGET_SIG_SETMASK:
9957 how = SIG_SETMASK;
9958 break;
9959 default:
9960 ret = -TARGET_EINVAL;
9961 goto fail;
9962 }
9963 mask = arg2;
9964 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009965 ret = do_sigprocmask(how, &set, &oldset);
9966 if (!ret) {
9967 host_to_target_old_sigset(&mask, &oldset);
9968 ret = mask;
9969 }
Richard Hendersonba0e2762009-12-09 15:56:29 -08009970 }
9971 break;
9972#endif
aurel3264b4d282008-11-14 17:20:15 +00009973
bellarda315a142005-01-30 22:59:18 +00009974#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009975 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009976 ret = get_errno(getgid());
9977 break;
bellarda315a142005-01-30 22:59:18 +00009978#endif
9979#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009980 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009981 ret = get_errno(geteuid());
9982 break;
bellarda315a142005-01-30 22:59:18 +00009983#endif
9984#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009985 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009986 ret = get_errno(getegid());
9987 break;
bellarda315a142005-01-30 22:59:18 +00009988#endif
9989#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009990 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009991 ret = get_errno(setreuid(arg1, arg2));
9992 break;
bellarda315a142005-01-30 22:59:18 +00009993#endif
9994#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009995 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009996 ret = get_errno(setregid(arg1, arg2));
9997 break;
bellarda315a142005-01-30 22:59:18 +00009998#endif
9999#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010000 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010001 {
10002 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010003 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010004 gid_t *grouplist;
10005 int i;
10006
10007 grouplist = alloca(gidsetsize * sizeof(gid_t));
10008 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010009 if (gidsetsize == 0)
10010 break;
bellard99c475a2005-01-31 20:45:13 +000010011 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010012 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10013 if (!target_grouplist) {
10014 ret = -TARGET_EFAULT;
10015 goto fail;
10016 }
balroga2155fc2008-09-20 02:12:08 +000010017 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010018 target_grouplist[i] = tswap32(grouplist[i]);
10019 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010020 }
10021 }
10022 break;
bellarda315a142005-01-30 22:59:18 +000010023#endif
10024#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010025 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010026 {
10027 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010028 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010029 gid_t *grouplist;
10030 int i;
ths3b46e622007-09-17 08:09:54 +000010031
bellard99c475a2005-01-31 20:45:13 +000010032 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010033 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10034 if (!target_grouplist) {
10035 ret = -TARGET_EFAULT;
10036 goto fail;
10037 }
bellard99c475a2005-01-31 20:45:13 +000010038 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010039 grouplist[i] = tswap32(target_grouplist[i]);
10040 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010041 ret = get_errno(setgroups(gidsetsize, grouplist));
10042 }
10043 break;
bellarda315a142005-01-30 22:59:18 +000010044#endif
10045#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010046 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010047 ret = get_errno(fchown(arg1, arg2, arg3));
10048 break;
bellarda315a142005-01-30 22:59:18 +000010049#endif
10050#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010051 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010052 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010053 break;
bellarda315a142005-01-30 22:59:18 +000010054#endif
10055#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010056 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010057 {
pbrook53a59602006-03-25 19:31:22 +000010058 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010059 ret = get_errno(getresuid(&ruid, &euid, &suid));
10060 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010061 if (put_user_u32(ruid, arg1)
10062 || put_user_u32(euid, arg2)
10063 || put_user_u32(suid, arg3))
10064 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010065 }
10066 }
10067 break;
bellarda315a142005-01-30 22:59:18 +000010068#endif
10069#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010070 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010071 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010072 break;
bellarda315a142005-01-30 22:59:18 +000010073#endif
10074#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010075 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010076 {
pbrook53a59602006-03-25 19:31:22 +000010077 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010078 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10079 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010080 if (put_user_u32(rgid, arg1)
10081 || put_user_u32(egid, arg2)
10082 || put_user_u32(sgid, arg3))
10083 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010084 }
10085 }
10086 break;
bellarda315a142005-01-30 22:59:18 +000010087#endif
10088#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010089 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010090 if (!(p = lock_user_string(arg1)))
10091 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010092 ret = get_errno(chown(p, arg2, arg3));
10093 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010094 break;
bellarda315a142005-01-30 22:59:18 +000010095#endif
10096#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010097 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010098 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010099 break;
bellarda315a142005-01-30 22:59:18 +000010100#endif
10101#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010102 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010103 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010104 break;
bellarda315a142005-01-30 22:59:18 +000010105#endif
10106#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010107 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010108 ret = get_errno(setfsuid(arg1));
10109 break;
bellarda315a142005-01-30 22:59:18 +000010110#endif
10111#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010112 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010113 ret = get_errno(setfsgid(arg1));
10114 break;
bellarda315a142005-01-30 22:59:18 +000010115#endif
bellard67867302003-11-23 17:05:30 +000010116
bellard31e31b82003-02-18 22:55:36 +000010117 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010118 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010119#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010120 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010121 {
10122 void *a;
10123 ret = -TARGET_EFAULT;
10124 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10125 goto efault;
10126 if (!(p = lock_user_string(arg3)))
10127 goto mincore_fail;
10128 ret = get_errno(mincore(a, arg2, p));
10129 unlock_user(p, arg3, ret);
10130 mincore_fail:
10131 unlock_user(a, arg1, 0);
10132 }
10133 break;
bellardffa65c32004-01-04 23:57:22 +000010134#endif
aurel32408321b2008-10-01 21:46:32 +000010135#ifdef TARGET_NR_arm_fadvise64_64
10136 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010137 /* arm_fadvise64_64 looks like fadvise64_64 but
10138 * with different argument order: fd, advice, offset, len
10139 * rather than the usual fd, offset, len, advice.
10140 * Note that offset and len are both 64-bit so appear as
10141 * pairs of 32-bit registers.
10142 */
10143 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10144 target_offset64(arg5, arg6), arg2);
10145 ret = -host_to_target_errno(ret);
10146 break;
aurel32408321b2008-10-01 21:46:32 +000010147#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010148
10149#if TARGET_ABI_BITS == 32
10150
10151#ifdef TARGET_NR_fadvise64_64
10152 case TARGET_NR_fadvise64_64:
10153 /* 6 args: fd, offset (high, low), len (high, low), advice */
10154 if (regpairs_aligned(cpu_env)) {
10155 /* offset is in (3,4), len in (5,6) and advice in 7 */
10156 arg2 = arg3;
10157 arg3 = arg4;
10158 arg4 = arg5;
10159 arg5 = arg6;
10160 arg6 = arg7;
10161 }
10162 ret = -host_to_target_errno(posix_fadvise(arg1,
10163 target_offset64(arg2, arg3),
10164 target_offset64(arg4, arg5),
10165 arg6));
10166 break;
10167#endif
10168
10169#ifdef TARGET_NR_fadvise64
10170 case TARGET_NR_fadvise64:
10171 /* 5 args: fd, offset (high, low), len, advice */
10172 if (regpairs_aligned(cpu_env)) {
10173 /* offset is in (3,4), len in 5 and advice in 6 */
10174 arg2 = arg3;
10175 arg3 = arg4;
10176 arg4 = arg5;
10177 arg5 = arg6;
10178 }
10179 ret = -host_to_target_errno(posix_fadvise(arg1,
10180 target_offset64(arg2, arg3),
10181 arg4, arg5));
10182 break;
10183#endif
10184
10185#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010186#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010187#ifdef TARGET_NR_fadvise64_64
10188 case TARGET_NR_fadvise64_64:
10189#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010190#ifdef TARGET_NR_fadvise64
10191 case TARGET_NR_fadvise64:
10192#endif
10193#ifdef TARGET_S390X
10194 switch (arg4) {
10195 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10196 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10197 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10198 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10199 default: break;
10200 }
10201#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010202 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10203 break;
aurel32408321b2008-10-01 21:46:32 +000010204#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010205#endif /* end of 64-bit ABI fadvise handling */
10206
bellardffa65c32004-01-04 23:57:22 +000010207#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010208 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010209 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010210 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010211 This will break MADV_DONTNEED.
10212 This is a hint, so ignoring and returning success is ok. */
10213 ret = get_errno(0);
10214 break;
bellardffa65c32004-01-04 23:57:22 +000010215#endif
blueswir1992f48a2007-10-14 16:27:31 +000010216#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010217 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010218 {
thsb1e341e2007-03-20 21:50:52 +000010219 int cmd;
bellard77e46722003-04-29 20:39:06 +000010220 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010221 from_flock64_fn *copyfrom = copy_from_user_flock64;
10222 to_flock64_fn *copyto = copy_to_user_flock64;
10223
pbrookce4defa2006-02-09 16:49:55 +000010224#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010225 if (((CPUARMState *)cpu_env)->eabi) {
10226 copyfrom = copy_from_user_eabi_flock64;
10227 copyto = copy_to_user_eabi_flock64;
10228 }
pbrookce4defa2006-02-09 16:49:55 +000010229#endif
bellard77e46722003-04-29 20:39:06 +000010230
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010231 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010232 if (cmd == -TARGET_EINVAL) {
10233 ret = cmd;
10234 break;
10235 }
thsb1e341e2007-03-20 21:50:52 +000010236
bellard60cd49d2003-03-16 22:53:56 +000010237 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010238 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010239 ret = copyfrom(&fl, arg3);
10240 if (ret) {
10241 break;
ths58134272007-03-31 18:59:32 +000010242 }
thsb1e341e2007-03-20 21:50:52 +000010243 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010244 if (ret == 0) {
10245 ret = copyto(arg3, &fl);
10246 }
bellard77e46722003-04-29 20:39:06 +000010247 break;
10248
thsb1e341e2007-03-20 21:50:52 +000010249 case TARGET_F_SETLK64:
10250 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010251 ret = copyfrom(&fl, arg3);
10252 if (ret) {
10253 break;
pbrookce4defa2006-02-09 16:49:55 +000010254 }
thsb1e341e2007-03-20 21:50:52 +000010255 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010256 break;
bellard60cd49d2003-03-16 22:53:56 +000010257 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010258 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010259 break;
10260 }
bellard77e46722003-04-29 20:39:06 +000010261 break;
10262 }
bellard60cd49d2003-03-16 22:53:56 +000010263#endif
ths7d600c82006-12-08 01:32:58 +000010264#ifdef TARGET_NR_cacheflush
10265 case TARGET_NR_cacheflush:
10266 /* self-modifying code is handled automatically, so nothing needed */
10267 ret = 0;
10268 break;
10269#endif
bellardebc05482003-09-30 21:08:41 +000010270#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010271 case TARGET_NR_security:
10272 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010273#endif
bellardc573ff62004-01-04 15:51:36 +000010274#ifdef TARGET_NR_getpagesize
10275 case TARGET_NR_getpagesize:
10276 ret = TARGET_PAGE_SIZE;
10277 break;
10278#endif
bellard31e31b82003-02-18 22:55:36 +000010279 case TARGET_NR_gettid:
10280 ret = get_errno(gettid());
10281 break;
thse5febef2007-04-01 18:31:35 +000010282#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010283 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010284#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010285 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010286 arg2 = arg3;
10287 arg3 = arg4;
10288 arg4 = arg5;
10289 }
aurel322054ac92008-10-13 21:08:07 +000010290 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10291#else
10292 ret = get_errno(readahead(arg1, arg2, arg3));
10293#endif
10294 break;
thse5febef2007-04-01 18:31:35 +000010295#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010296#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010297#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010298 case TARGET_NR_listxattr:
10299 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010300 {
10301 void *p, *b = 0;
10302 if (arg2) {
10303 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10304 if (!b) {
10305 ret = -TARGET_EFAULT;
10306 break;
10307 }
10308 }
10309 p = lock_user_string(arg1);
10310 if (p) {
10311 if (num == TARGET_NR_listxattr) {
10312 ret = get_errno(listxattr(p, b, arg3));
10313 } else {
10314 ret = get_errno(llistxattr(p, b, arg3));
10315 }
10316 } else {
10317 ret = -TARGET_EFAULT;
10318 }
10319 unlock_user(p, arg1, 0);
10320 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010321 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010322 }
10323 case TARGET_NR_flistxattr:
10324 {
10325 void *b = 0;
10326 if (arg2) {
10327 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10328 if (!b) {
10329 ret = -TARGET_EFAULT;
10330 break;
10331 }
10332 }
10333 ret = get_errno(flistxattr(arg1, b, arg3));
10334 unlock_user(b, arg2, arg3);
10335 break;
10336 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010337 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010338 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010339 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010340 void *p, *n, *v = 0;
10341 if (arg3) {
10342 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10343 if (!v) {
10344 ret = -TARGET_EFAULT;
10345 break;
10346 }
10347 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010348 p = lock_user_string(arg1);
10349 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010350 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010351 if (num == TARGET_NR_setxattr) {
10352 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10353 } else {
10354 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10355 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010356 } else {
10357 ret = -TARGET_EFAULT;
10358 }
10359 unlock_user(p, arg1, 0);
10360 unlock_user(n, arg2, 0);
10361 unlock_user(v, arg3, 0);
10362 }
10363 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010364 case TARGET_NR_fsetxattr:
10365 {
10366 void *n, *v = 0;
10367 if (arg3) {
10368 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10369 if (!v) {
10370 ret = -TARGET_EFAULT;
10371 break;
10372 }
10373 }
10374 n = lock_user_string(arg2);
10375 if (n) {
10376 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10377 } else {
10378 ret = -TARGET_EFAULT;
10379 }
10380 unlock_user(n, arg2, 0);
10381 unlock_user(v, arg3, 0);
10382 }
10383 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010384 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010385 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010386 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010387 void *p, *n, *v = 0;
10388 if (arg3) {
10389 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10390 if (!v) {
10391 ret = -TARGET_EFAULT;
10392 break;
10393 }
10394 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010395 p = lock_user_string(arg1);
10396 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010397 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010398 if (num == TARGET_NR_getxattr) {
10399 ret = get_errno(getxattr(p, n, v, arg4));
10400 } else {
10401 ret = get_errno(lgetxattr(p, n, v, arg4));
10402 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010403 } else {
10404 ret = -TARGET_EFAULT;
10405 }
10406 unlock_user(p, arg1, 0);
10407 unlock_user(n, arg2, 0);
10408 unlock_user(v, arg3, arg4);
10409 }
10410 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010411 case TARGET_NR_fgetxattr:
10412 {
10413 void *n, *v = 0;
10414 if (arg3) {
10415 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10416 if (!v) {
10417 ret = -TARGET_EFAULT;
10418 break;
10419 }
10420 }
10421 n = lock_user_string(arg2);
10422 if (n) {
10423 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10424 } else {
10425 ret = -TARGET_EFAULT;
10426 }
10427 unlock_user(n, arg2, 0);
10428 unlock_user(v, arg3, arg4);
10429 }
10430 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010431 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010432 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010433 {
10434 void *p, *n;
10435 p = lock_user_string(arg1);
10436 n = lock_user_string(arg2);
10437 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010438 if (num == TARGET_NR_removexattr) {
10439 ret = get_errno(removexattr(p, n));
10440 } else {
10441 ret = get_errno(lremovexattr(p, n));
10442 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010443 } else {
10444 ret = -TARGET_EFAULT;
10445 }
10446 unlock_user(p, arg1, 0);
10447 unlock_user(n, arg2, 0);
10448 }
10449 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010450 case TARGET_NR_fremovexattr:
10451 {
10452 void *n;
10453 n = lock_user_string(arg2);
10454 if (n) {
10455 ret = get_errno(fremovexattr(arg1, n));
10456 } else {
10457 ret = -TARGET_EFAULT;
10458 }
10459 unlock_user(n, arg2, 0);
10460 }
10461 break;
bellardebc05482003-09-30 21:08:41 +000010462#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010463#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010464#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010465 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010466#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010467 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010468 ret = 0;
10469 break;
edgar_iglef967792009-01-07 14:19:38 +000010470#elif defined(TARGET_CRIS)
10471 if (arg1 & 0xff)
10472 ret = -TARGET_EINVAL;
10473 else {
10474 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10475 ret = 0;
10476 }
10477 break;
bellard8d18e892007-11-14 15:18:40 +000010478#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10479 ret = do_set_thread_area(cpu_env, arg1);
10480 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010481#elif defined(TARGET_M68K)
10482 {
Andreas Färber0429a972013-08-26 18:14:44 +020010483 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010484 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010485 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010486 break;
10487 }
ths6f5b89a2007-03-02 20:48:00 +000010488#else
10489 goto unimplemented_nowarn;
10490#endif
10491#endif
10492#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010493 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010494#if defined(TARGET_I386) && defined(TARGET_ABI32)
10495 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010496 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010497#elif defined(TARGET_M68K)
10498 {
Andreas Färber0429a972013-08-26 18:14:44 +020010499 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010500 ret = ts->tp_value;
10501 break;
10502 }
bellard8d18e892007-11-14 15:18:40 +000010503#else
bellard5cd43932003-03-29 16:54:36 +000010504 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010505#endif
bellard8d18e892007-11-14 15:18:40 +000010506#endif
bellard48dc41e2006-06-21 18:15:50 +000010507#ifdef TARGET_NR_getdomainname
10508 case TARGET_NR_getdomainname:
10509 goto unimplemented_nowarn;
10510#endif
ths6f5b89a2007-03-02 20:48:00 +000010511
thsb5906f92007-03-19 13:32:45 +000010512#ifdef TARGET_NR_clock_gettime
10513 case TARGET_NR_clock_gettime:
10514 {
10515 struct timespec ts;
10516 ret = get_errno(clock_gettime(arg1, &ts));
10517 if (!is_error(ret)) {
10518 host_to_target_timespec(arg2, &ts);
10519 }
10520 break;
10521 }
10522#endif
10523#ifdef TARGET_NR_clock_getres
10524 case TARGET_NR_clock_getres:
10525 {
10526 struct timespec ts;
10527 ret = get_errno(clock_getres(arg1, &ts));
10528 if (!is_error(ret)) {
10529 host_to_target_timespec(arg2, &ts);
10530 }
10531 break;
10532 }
10533#endif
pbrook63d76512008-05-29 13:43:29 +000010534#ifdef TARGET_NR_clock_nanosleep
10535 case TARGET_NR_clock_nanosleep:
10536 {
10537 struct timespec ts;
10538 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010010539 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
10540 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000010541 if (arg4)
10542 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010543
10544#if defined(TARGET_PPC)
10545 /* clock_nanosleep is odd in that it returns positive errno values.
10546 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010010547 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010548 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10549 }
10550#endif
pbrook63d76512008-05-29 13:43:29 +000010551 break;
10552 }
10553#endif
thsb5906f92007-03-19 13:32:45 +000010554
ths6f5b89a2007-03-02 20:48:00 +000010555#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10556 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010557 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10558 break;
ths6f5b89a2007-03-02 20:48:00 +000010559#endif
10560
ths4cae1d12007-07-12 11:06:53 +000010561 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010562 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010563 break;
ths4cae1d12007-07-12 11:06:53 +000010564
ths71455572007-06-21 21:45:30 +000010565 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010566 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000010567 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010010568 break;
ths71455572007-06-21 21:45:30 +000010569
ths4f2b1fe2007-06-21 21:57:12 +000010570#ifdef TARGET_NR_set_robust_list
10571 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010572 case TARGET_NR_get_robust_list:
10573 /* The ABI for supporting robust futexes has userspace pass
10574 * the kernel a pointer to a linked list which is updated by
10575 * userspace after the syscall; the list is walked by the kernel
10576 * when the thread exits. Since the linked list in QEMU guest
10577 * memory isn't a valid linked list for the host and we have
10578 * no way to reliably intercept the thread-death event, we can't
10579 * support these. Silently return ENOSYS so that guest userspace
10580 * falls back to a non-robust futex implementation (which should
10581 * be OK except in the corner case of the guest crashing while
10582 * holding a mutex that is shared with another process via
10583 * shared memory).
10584 */
10585 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010586#endif
10587
Peter Maydell1acae9f2013-07-02 14:04:12 +010010588#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010589 case TARGET_NR_utimensat:
10590 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010591 struct timespec *tsp, ts[2];
10592 if (!arg3) {
10593 tsp = NULL;
10594 } else {
10595 target_to_host_timespec(ts, arg3);
10596 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10597 tsp = ts;
10598 }
ths9007f0e2007-09-25 17:50:37 +000010599 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010600 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010601 else {
bellard579a97f2007-11-11 14:26:47 +000010602 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010603 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010604 goto fail;
10605 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010606 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010607 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010608 }
10609 }
10610 break;
10611#endif
pbrookbd0c5662008-05-29 14:34:11 +000010612 case TARGET_NR_futex:
10613 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10614 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010615#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010616 case TARGET_NR_inotify_init:
10617 ret = get_errno(sys_inotify_init());
10618 break;
10619#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010620#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010621#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10622 case TARGET_NR_inotify_init1:
10623 ret = get_errno(sys_inotify_init1(arg1));
10624 break;
10625#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010626#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010627#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010628 case TARGET_NR_inotify_add_watch:
10629 p = lock_user_string(arg2);
10630 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10631 unlock_user(p, arg2, 0);
10632 break;
10633#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010634#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010635 case TARGET_NR_inotify_rm_watch:
10636 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10637 break;
10638#endif
ths9007f0e2007-09-25 17:50:37 +000010639
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010640#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010641 case TARGET_NR_mq_open:
10642 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010643 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010644
10645 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010646 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010647 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010648 attrp = &posix_mq_attr;
10649 } else {
10650 attrp = 0;
10651 }
10652 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010653 unlock_user (p, arg1, 0);
10654 }
10655 break;
10656
10657 case TARGET_NR_mq_unlink:
10658 p = lock_user_string(arg1 - 1);
10659 ret = get_errno(mq_unlink(p));
10660 unlock_user (p, arg1, 0);
10661 break;
10662
10663 case TARGET_NR_mq_timedsend:
10664 {
10665 struct timespec ts;
10666
10667 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10668 if (arg5 != 0) {
10669 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010670 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000010671 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010672 } else {
10673 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000010674 }
aurel3224e10032009-04-15 16:11:43 +000010675 unlock_user (p, arg2, arg3);
10676 }
10677 break;
10678
10679 case TARGET_NR_mq_timedreceive:
10680 {
10681 struct timespec ts;
10682 unsigned int prio;
10683
10684 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10685 if (arg5 != 0) {
10686 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010687 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10688 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000010689 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010690 } else {
10691 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10692 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000010693 }
aurel3224e10032009-04-15 16:11:43 +000010694 unlock_user (p, arg2, arg3);
10695 if (arg4 != 0)
10696 put_user_u32(prio, arg4);
10697 }
10698 break;
10699
10700 /* Not implemented for now... */
10701/* case TARGET_NR_mq_notify: */
10702/* break; */
10703
10704 case TARGET_NR_mq_getsetattr:
10705 {
10706 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10707 ret = 0;
10708 if (arg3 != 0) {
10709 ret = mq_getattr(arg1, &posix_mq_attr_out);
10710 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10711 }
10712 if (arg2 != 0) {
10713 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10714 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10715 }
10716
10717 }
10718 break;
10719#endif
10720
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010721#ifdef CONFIG_SPLICE
10722#ifdef TARGET_NR_tee
10723 case TARGET_NR_tee:
10724 {
10725 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10726 }
10727 break;
10728#endif
10729#ifdef TARGET_NR_splice
10730 case TARGET_NR_splice:
10731 {
10732 loff_t loff_in, loff_out;
10733 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010734 if (arg2) {
10735 if (get_user_u64(loff_in, arg2)) {
10736 goto efault;
10737 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010738 ploff_in = &loff_in;
10739 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010740 if (arg4) {
10741 if (get_user_u64(loff_out, arg4)) {
10742 goto efault;
10743 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010744 ploff_out = &loff_out;
10745 }
10746 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010747 if (arg2) {
10748 if (put_user_u64(loff_in, arg2)) {
10749 goto efault;
10750 }
10751 }
10752 if (arg4) {
10753 if (put_user_u64(loff_out, arg4)) {
10754 goto efault;
10755 }
10756 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010757 }
10758 break;
10759#endif
10760#ifdef TARGET_NR_vmsplice
10761 case TARGET_NR_vmsplice:
10762 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010763 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10764 if (vec != NULL) {
10765 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10766 unlock_iovec(vec, arg2, arg3, 0);
10767 } else {
10768 ret = -host_to_target_errno(errno);
10769 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010770 }
10771 break;
10772#endif
10773#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010774#ifdef CONFIG_EVENTFD
10775#if defined(TARGET_NR_eventfd)
10776 case TARGET_NR_eventfd:
10777 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010778 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010779 break;
10780#endif
10781#if defined(TARGET_NR_eventfd2)
10782 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010783 {
10784 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10785 if (arg2 & TARGET_O_NONBLOCK) {
10786 host_flags |= O_NONBLOCK;
10787 }
10788 if (arg2 & TARGET_O_CLOEXEC) {
10789 host_flags |= O_CLOEXEC;
10790 }
10791 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010792 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010793 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010794 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010795#endif
10796#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010797#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10798 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010799#if TARGET_ABI_BITS == 32
10800 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10801 target_offset64(arg5, arg6)));
10802#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010803 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010804#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010805 break;
10806#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010807#if defined(CONFIG_SYNC_FILE_RANGE)
10808#if defined(TARGET_NR_sync_file_range)
10809 case TARGET_NR_sync_file_range:
10810#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010811#if defined(TARGET_MIPS)
10812 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10813 target_offset64(arg5, arg6), arg7));
10814#else
Peter Maydellc727f472011-01-06 11:05:10 +000010815 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10816 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010817#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010818#else
10819 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10820#endif
10821 break;
10822#endif
10823#if defined(TARGET_NR_sync_file_range2)
10824 case TARGET_NR_sync_file_range2:
10825 /* This is like sync_file_range but the arguments are reordered */
10826#if TARGET_ABI_BITS == 32
10827 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10828 target_offset64(arg5, arg6), arg2));
10829#else
10830 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10831#endif
10832 break;
10833#endif
10834#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010835#if defined(TARGET_NR_signalfd4)
10836 case TARGET_NR_signalfd4:
10837 ret = do_signalfd4(arg1, arg2, arg4);
10838 break;
10839#endif
10840#if defined(TARGET_NR_signalfd)
10841 case TARGET_NR_signalfd:
10842 ret = do_signalfd4(arg1, arg2, 0);
10843 break;
10844#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010845#if defined(CONFIG_EPOLL)
10846#if defined(TARGET_NR_epoll_create)
10847 case TARGET_NR_epoll_create:
10848 ret = get_errno(epoll_create(arg1));
10849 break;
10850#endif
10851#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10852 case TARGET_NR_epoll_create1:
10853 ret = get_errno(epoll_create1(arg1));
10854 break;
10855#endif
10856#if defined(TARGET_NR_epoll_ctl)
10857 case TARGET_NR_epoll_ctl:
10858 {
10859 struct epoll_event ep;
10860 struct epoll_event *epp = 0;
10861 if (arg4) {
10862 struct target_epoll_event *target_ep;
10863 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10864 goto efault;
10865 }
10866 ep.events = tswap32(target_ep->events);
10867 /* The epoll_data_t union is just opaque data to the kernel,
10868 * so we transfer all 64 bits across and need not worry what
10869 * actual data type it is.
10870 */
10871 ep.data.u64 = tswap64(target_ep->data.u64);
10872 unlock_user_struct(target_ep, arg4, 0);
10873 epp = &ep;
10874 }
10875 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10876 break;
10877 }
10878#endif
10879
Peter Maydell227f0212016-06-06 19:58:11 +010010880#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010881#if defined(TARGET_NR_epoll_wait)
10882 case TARGET_NR_epoll_wait:
10883#endif
Peter Maydell227f0212016-06-06 19:58:11 +010010884#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010885 case TARGET_NR_epoll_pwait:
10886#endif
10887 {
10888 struct target_epoll_event *target_ep;
10889 struct epoll_event *ep;
10890 int epfd = arg1;
10891 int maxevents = arg3;
10892 int timeout = arg4;
10893
10894 target_ep = lock_user(VERIFY_WRITE, arg2,
10895 maxevents * sizeof(struct target_epoll_event), 1);
10896 if (!target_ep) {
10897 goto efault;
10898 }
10899
10900 ep = alloca(maxevents * sizeof(struct epoll_event));
10901
10902 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010010903#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010904 case TARGET_NR_epoll_pwait:
10905 {
10906 target_sigset_t *target_set;
10907 sigset_t _set, *set = &_set;
10908
10909 if (arg5) {
10910 target_set = lock_user(VERIFY_READ, arg5,
10911 sizeof(target_sigset_t), 1);
10912 if (!target_set) {
10913 unlock_user(target_ep, arg2, 0);
10914 goto efault;
10915 }
10916 target_to_host_sigset(set, target_set);
10917 unlock_user(target_set, arg5, 0);
10918 } else {
10919 set = NULL;
10920 }
10921
Peter Maydell227f0212016-06-06 19:58:11 +010010922 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10923 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010924 break;
10925 }
10926#endif
10927#if defined(TARGET_NR_epoll_wait)
10928 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010010929 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10930 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010931 break;
10932#endif
10933 default:
10934 ret = -TARGET_ENOSYS;
10935 }
10936 if (!is_error(ret)) {
10937 int i;
10938 for (i = 0; i < ret; i++) {
10939 target_ep[i].events = tswap32(ep[i].events);
10940 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10941 }
10942 }
10943 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10944 break;
10945 }
10946#endif
10947#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010948#ifdef TARGET_NR_prlimit64
10949 case TARGET_NR_prlimit64:
10950 {
10951 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10952 struct target_rlimit64 *target_rnew, *target_rold;
10953 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010954 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010955 if (arg3) {
10956 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10957 goto efault;
10958 }
10959 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10960 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10961 unlock_user_struct(target_rnew, arg3, 0);
10962 rnewp = &rnew;
10963 }
10964
Felix Janda95018012014-12-02 22:11:17 +010010965 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010966 if (!is_error(ret) && arg4) {
10967 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10968 goto efault;
10969 }
10970 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10971 target_rold->rlim_max = tswap64(rold.rlim_max);
10972 unlock_user_struct(target_rold, arg4, 1);
10973 }
10974 break;
10975 }
10976#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010977#ifdef TARGET_NR_gethostname
10978 case TARGET_NR_gethostname:
10979 {
10980 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10981 if (name) {
10982 ret = get_errno(gethostname(name, arg2));
10983 unlock_user(name, arg1, arg2);
10984 } else {
10985 ret = -TARGET_EFAULT;
10986 }
10987 break;
10988 }
10989#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010990#ifdef TARGET_NR_atomic_cmpxchg_32
10991 case TARGET_NR_atomic_cmpxchg_32:
10992 {
10993 /* should use start_exclusive from main.c */
10994 abi_ulong mem_value;
10995 if (get_user_u32(mem_value, arg6)) {
10996 target_siginfo_t info;
10997 info.si_signo = SIGSEGV;
10998 info.si_errno = 0;
10999 info.si_code = TARGET_SEGV_MAPERR;
11000 info._sifields._sigfault._addr = arg6;
11001 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11002 ret = 0xdeadbeef;
11003
11004 }
11005 if (mem_value == arg2)
11006 put_user_u32(arg1, arg6);
11007 ret = mem_value;
11008 break;
11009 }
11010#endif
11011#ifdef TARGET_NR_atomic_barrier
11012 case TARGET_NR_atomic_barrier:
11013 {
11014 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011015 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011016 break;
11017 }
11018#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011019
11020#ifdef TARGET_NR_timer_create
11021 case TARGET_NR_timer_create:
11022 {
11023 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11024
11025 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011026
11027 int clkid = arg1;
11028 int timer_index = next_free_host_timer();
11029
11030 if (timer_index < 0) {
11031 ret = -TARGET_EAGAIN;
11032 } else {
11033 timer_t *phtimer = g_posix_timers + timer_index;
11034
11035 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011036 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011037 ret = target_to_host_sigevent(phost_sevp, arg2);
11038 if (ret != 0) {
11039 break;
11040 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011041 }
11042
11043 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11044 if (ret) {
11045 phtimer = NULL;
11046 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011047 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011048 goto efault;
11049 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011050 }
11051 }
11052 break;
11053 }
11054#endif
11055
11056#ifdef TARGET_NR_timer_settime
11057 case TARGET_NR_timer_settime:
11058 {
11059 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11060 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011061 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011062
Alexander Grafaecc8862014-11-10 21:33:03 +010011063 if (timerid < 0) {
11064 ret = timerid;
11065 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011066 ret = -TARGET_EINVAL;
11067 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011068 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011069 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11070
11071 target_to_host_itimerspec(&hspec_new, arg3);
11072 ret = get_errno(
11073 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11074 host_to_target_itimerspec(arg2, &hspec_old);
11075 }
11076 break;
11077 }
11078#endif
11079
11080#ifdef TARGET_NR_timer_gettime
11081 case TARGET_NR_timer_gettime:
11082 {
11083 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011084 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011085
Alexander Grafaecc8862014-11-10 21:33:03 +010011086 if (timerid < 0) {
11087 ret = timerid;
11088 } else if (!arg2) {
11089 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011090 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011091 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011092 struct itimerspec hspec;
11093 ret = get_errno(timer_gettime(htimer, &hspec));
11094
11095 if (host_to_target_itimerspec(arg2, &hspec)) {
11096 ret = -TARGET_EFAULT;
11097 }
11098 }
11099 break;
11100 }
11101#endif
11102
11103#ifdef TARGET_NR_timer_getoverrun
11104 case TARGET_NR_timer_getoverrun:
11105 {
11106 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011107 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011108
Alexander Grafaecc8862014-11-10 21:33:03 +010011109 if (timerid < 0) {
11110 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011111 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011112 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011113 ret = get_errno(timer_getoverrun(htimer));
11114 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011115 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011116 break;
11117 }
11118#endif
11119
11120#ifdef TARGET_NR_timer_delete
11121 case TARGET_NR_timer_delete:
11122 {
11123 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011124 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011125
Alexander Grafaecc8862014-11-10 21:33:03 +010011126 if (timerid < 0) {
11127 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011128 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011129 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011130 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011131 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011132 }
11133 break;
11134 }
11135#endif
11136
Riku Voipio51834342014-06-22 11:25:42 +010011137#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11138 case TARGET_NR_timerfd_create:
11139 ret = get_errno(timerfd_create(arg1,
11140 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11141 break;
11142#endif
11143
11144#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11145 case TARGET_NR_timerfd_gettime:
11146 {
11147 struct itimerspec its_curr;
11148
11149 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11150
11151 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11152 goto efault;
11153 }
11154 }
11155 break;
11156#endif
11157
11158#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11159 case TARGET_NR_timerfd_settime:
11160 {
11161 struct itimerspec its_new, its_old, *p_new;
11162
11163 if (arg3) {
11164 if (target_to_host_itimerspec(&its_new, arg3)) {
11165 goto efault;
11166 }
11167 p_new = &its_new;
11168 } else {
11169 p_new = NULL;
11170 }
11171
11172 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11173
11174 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11175 goto efault;
11176 }
11177 }
11178 break;
11179#endif
11180
Paul Burtonab31cda2014-06-22 11:25:43 +010011181#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11182 case TARGET_NR_ioprio_get:
11183 ret = get_errno(ioprio_get(arg1, arg2));
11184 break;
11185#endif
11186
11187#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11188 case TARGET_NR_ioprio_set:
11189 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11190 break;
11191#endif
11192
Riku Voipio9af5c902014-08-12 15:58:57 +030011193#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11194 case TARGET_NR_setns:
11195 ret = get_errno(setns(arg1, arg2));
11196 break;
11197#endif
11198#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11199 case TARGET_NR_unshare:
11200 ret = get_errno(unshare(arg1));
11201 break;
11202#endif
11203
bellard31e31b82003-02-18 22:55:36 +000011204 default:
11205 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011206 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011207#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 +000011208 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011209#endif
ths0da46a62007-10-20 20:23:07 +000011210 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011211 break;
11212 }
bellard579a97f2007-11-11 14:26:47 +000011213fail:
bellardc573ff62004-01-04 15:51:36 +000011214#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011215 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011216#endif
thsb92c47c2007-11-01 00:07:38 +000011217 if(do_strace)
11218 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000011219 return ret;
bellard579a97f2007-11-11 14:26:47 +000011220efault:
11221 ret = -TARGET_EFAULT;
11222 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011223}