blob: efcc17a3b010c0a18796c5bb643bba6f49012f99 [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 Viviera82ea932016-06-27 00:18:22 +0200103#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200104#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200105#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200106#include <linux/rtnetlink.h>
Laurent Vivierc5dff282016-06-27 18:54:30 +0200107#include <linux/if_bridge.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200108#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200109#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000110#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200111#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000112
bellard3ef693a2003-03-23 20:17:16 +0000113#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000114
pbrookd865bab2008-06-07 22:12:17 +0000115#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
116 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000117
bellard72f03902003-02-18 23:33:18 +0000118//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100119/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
120 * once. This exercises the codepaths for restart.
121 */
122//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000123
bellard1a9353d2003-03-16 20:28:50 +0000124//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000125#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
126#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000127
bellard70a194b2003-08-11 22:20:16 +0000128#undef _syscall0
129#undef _syscall1
130#undef _syscall2
131#undef _syscall3
132#undef _syscall4
133#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000134#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000155static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000156{ \
157 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000158}
159
bellard83fcb512006-06-14 13:37:16 +0000160#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000161static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000162{ \
163 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000164}
165
bellard83fcb512006-06-14 13:37:16 +0000166#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000169{ \
170 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000171}
bellard83fcb512006-06-14 13:37:16 +0000172
173
174#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
175 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000176static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
177 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000178{ \
179 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
180}
181
bellard70a194b2003-08-11 22:20:16 +0000182
bellard31e31b82003-02-18 22:55:36 +0000183#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000185#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000186#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000187#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000189#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000190#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000191#define __NR_sys_inotify_init __NR_inotify_init
192#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
193#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000194
Alexander Graf42a39fb2011-04-15 17:32:45 +0200195#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
196 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000197#define __NR__llseek __NR_lseek
198#endif
199
James Hogana29e5ba2014-03-25 21:51:08 +0000200/* Newer kernel ports have llseek() instead of _llseek() */
201#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
202#define TARGET_NR__llseek TARGET_NR_llseek
203#endif
204
bellard72f03902003-02-18 23:33:18 +0000205#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000206_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000207#else
ths0da46a62007-10-20 20:23:07 +0000208/* This is a replacement for the host gettid() and must return a host
209 errno. */
bellard72f03902003-02-18 23:33:18 +0000210static int gettid(void) {
211 return -ENOSYS;
212}
213#endif
Chen Gang704eff62015-08-21 05:37:33 +0800214#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000215_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100216#endif
217#if !defined(__NR_getdents) || \
218 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000219_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
220#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700221#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000222_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
223 loff_t *, res, uint, wh);
224#endif
225_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
226_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000227#ifdef __NR_exit_group
228_syscall1(int,exit_group,int,error_code)
229#endif
230#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
231_syscall1(int,set_tid_address,int *,tidptr)
232#endif
aurel323b3f24a2009-04-15 16:12:13 +0000233#if defined(TARGET_NR_futex) && defined(__NR_futex)
234_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
235 const struct timespec *,timeout,int *,uaddr2,int,val3)
236#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500237#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
238_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
239 unsigned long *, user_mask_ptr);
240#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
241_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
242 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200243_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
244 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000245_syscall2(int, capget, struct __user_cap_header_struct *, header,
246 struct __user_cap_data_struct *, data);
247_syscall2(int, capset, struct __user_cap_header_struct *, header,
248 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100249#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
250_syscall2(int, ioprio_get, int, which, int, who)
251#endif
252#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
253_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
254#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100255#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
256_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
257#endif
aurel323b3f24a2009-04-15 16:12:13 +0000258
259static bitmask_transtbl fcntl_flags_tbl[] = {
260 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
261 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
262 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
263 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
264 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
265 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
266 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
267 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700268 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000269 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
270 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
271 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
272 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000273#if defined(O_DIRECT)
274 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
275#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700276#if defined(O_NOATIME)
277 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
278#endif
279#if defined(O_CLOEXEC)
280 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
281#endif
282#if defined(O_PATH)
283 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
284#endif
285 /* Don't terminate the list prematurely on 64-bit host+guest. */
286#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
287 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
288#endif
aurel323b3f24a2009-04-15 16:12:13 +0000289 { 0, 0, 0, 0 }
290};
291
Michal Privoznik60c6b792016-08-19 10:06:40 +0200292enum {
293 QEMU_IFLA_BR_UNSPEC,
294 QEMU_IFLA_BR_FORWARD_DELAY,
295 QEMU_IFLA_BR_HELLO_TIME,
296 QEMU_IFLA_BR_MAX_AGE,
297 QEMU_IFLA_BR_AGEING_TIME,
298 QEMU_IFLA_BR_STP_STATE,
299 QEMU_IFLA_BR_PRIORITY,
300 QEMU_IFLA_BR_VLAN_FILTERING,
301 QEMU_IFLA_BR_VLAN_PROTOCOL,
302 QEMU_IFLA_BR_GROUP_FWD_MASK,
303 QEMU_IFLA_BR_ROOT_ID,
304 QEMU_IFLA_BR_BRIDGE_ID,
305 QEMU_IFLA_BR_ROOT_PORT,
306 QEMU_IFLA_BR_ROOT_PATH_COST,
307 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
308 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
309 QEMU_IFLA_BR_HELLO_TIMER,
310 QEMU_IFLA_BR_TCN_TIMER,
311 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
312 QEMU_IFLA_BR_GC_TIMER,
313 QEMU_IFLA_BR_GROUP_ADDR,
314 QEMU_IFLA_BR_FDB_FLUSH,
315 QEMU_IFLA_BR_MCAST_ROUTER,
316 QEMU_IFLA_BR_MCAST_SNOOPING,
317 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
318 QEMU_IFLA_BR_MCAST_QUERIER,
319 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
320 QEMU_IFLA_BR_MCAST_HASH_MAX,
321 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
322 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
323 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
324 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
325 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
326 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
327 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
328 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
329 QEMU_IFLA_BR_NF_CALL_IPTABLES,
330 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
331 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
332 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
333 QEMU_IFLA_BR_PAD,
334 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
335 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
336 QEMU___IFLA_BR_MAX,
337};
338
339enum {
340 QEMU_IFLA_UNSPEC,
341 QEMU_IFLA_ADDRESS,
342 QEMU_IFLA_BROADCAST,
343 QEMU_IFLA_IFNAME,
344 QEMU_IFLA_MTU,
345 QEMU_IFLA_LINK,
346 QEMU_IFLA_QDISC,
347 QEMU_IFLA_STATS,
348 QEMU_IFLA_COST,
349 QEMU_IFLA_PRIORITY,
350 QEMU_IFLA_MASTER,
351 QEMU_IFLA_WIRELESS,
352 QEMU_IFLA_PROTINFO,
353 QEMU_IFLA_TXQLEN,
354 QEMU_IFLA_MAP,
355 QEMU_IFLA_WEIGHT,
356 QEMU_IFLA_OPERSTATE,
357 QEMU_IFLA_LINKMODE,
358 QEMU_IFLA_LINKINFO,
359 QEMU_IFLA_NET_NS_PID,
360 QEMU_IFLA_IFALIAS,
361 QEMU_IFLA_NUM_VF,
362 QEMU_IFLA_VFINFO_LIST,
363 QEMU_IFLA_STATS64,
364 QEMU_IFLA_VF_PORTS,
365 QEMU_IFLA_PORT_SELF,
366 QEMU_IFLA_AF_SPEC,
367 QEMU_IFLA_GROUP,
368 QEMU_IFLA_NET_NS_FD,
369 QEMU_IFLA_EXT_MASK,
370 QEMU_IFLA_PROMISCUITY,
371 QEMU_IFLA_NUM_TX_QUEUES,
372 QEMU_IFLA_NUM_RX_QUEUES,
373 QEMU_IFLA_CARRIER,
374 QEMU_IFLA_PHYS_PORT_ID,
375 QEMU_IFLA_CARRIER_CHANGES,
376 QEMU_IFLA_PHYS_SWITCH_ID,
377 QEMU_IFLA_LINK_NETNSID,
378 QEMU_IFLA_PHYS_PORT_NAME,
379 QEMU_IFLA_PROTO_DOWN,
380 QEMU_IFLA_GSO_MAX_SEGS,
381 QEMU_IFLA_GSO_MAX_SIZE,
382 QEMU_IFLA_PAD,
383 QEMU_IFLA_XDP,
384 QEMU___IFLA_MAX
385};
386
387enum {
388 QEMU_IFLA_BRPORT_UNSPEC,
389 QEMU_IFLA_BRPORT_STATE,
390 QEMU_IFLA_BRPORT_PRIORITY,
391 QEMU_IFLA_BRPORT_COST,
392 QEMU_IFLA_BRPORT_MODE,
393 QEMU_IFLA_BRPORT_GUARD,
394 QEMU_IFLA_BRPORT_PROTECT,
395 QEMU_IFLA_BRPORT_FAST_LEAVE,
396 QEMU_IFLA_BRPORT_LEARNING,
397 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
398 QEMU_IFLA_BRPORT_PROXYARP,
399 QEMU_IFLA_BRPORT_LEARNING_SYNC,
400 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
401 QEMU_IFLA_BRPORT_ROOT_ID,
402 QEMU_IFLA_BRPORT_BRIDGE_ID,
403 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
404 QEMU_IFLA_BRPORT_DESIGNATED_COST,
405 QEMU_IFLA_BRPORT_ID,
406 QEMU_IFLA_BRPORT_NO,
407 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
408 QEMU_IFLA_BRPORT_CONFIG_PENDING,
409 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
410 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
411 QEMU_IFLA_BRPORT_HOLD_TIMER,
412 QEMU_IFLA_BRPORT_FLUSH,
413 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
414 QEMU_IFLA_BRPORT_PAD,
415 QEMU___IFLA_BRPORT_MAX
416};
417
418enum {
419 QEMU_IFLA_INFO_UNSPEC,
420 QEMU_IFLA_INFO_KIND,
421 QEMU_IFLA_INFO_DATA,
422 QEMU_IFLA_INFO_XSTATS,
423 QEMU_IFLA_INFO_SLAVE_KIND,
424 QEMU_IFLA_INFO_SLAVE_DATA,
425 QEMU___IFLA_INFO_MAX,
426};
427
428enum {
429 QEMU_IFLA_INET_UNSPEC,
430 QEMU_IFLA_INET_CONF,
431 QEMU___IFLA_INET_MAX,
432};
433
434enum {
435 QEMU_IFLA_INET6_UNSPEC,
436 QEMU_IFLA_INET6_FLAGS,
437 QEMU_IFLA_INET6_CONF,
438 QEMU_IFLA_INET6_STATS,
439 QEMU_IFLA_INET6_MCAST,
440 QEMU_IFLA_INET6_CACHEINFO,
441 QEMU_IFLA_INET6_ICMP6STATS,
442 QEMU_IFLA_INET6_TOKEN,
443 QEMU_IFLA_INET6_ADDR_GEN_MODE,
444 QEMU___IFLA_INET6_MAX
445};
446
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100447typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100448typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200449typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100450 TargetFdDataFunc host_to_target_data;
451 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100452 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200453} TargetFdTrans;
454
455static TargetFdTrans **target_fd_trans;
456
457static unsigned int target_fd_max;
458
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200459static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
460{
461 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
462 return target_fd_trans[fd]->target_to_host_data;
463 }
464 return NULL;
465}
466
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100467static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200468{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100469 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100470 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200471 }
472 return NULL;
473}
474
Laurent Vivier7b36f782015-10-28 21:40:44 +0100475static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
476{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100477 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100478 return target_fd_trans[fd]->target_to_host_addr;
479 }
480 return NULL;
481}
482
Laurent Viviere36800c2015-10-02 14:48:09 +0200483static void fd_trans_register(int fd, TargetFdTrans *trans)
484{
485 unsigned int oldmax;
486
487 if (fd >= target_fd_max) {
488 oldmax = target_fd_max;
489 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100490 target_fd_trans = g_renew(TargetFdTrans *,
491 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200492 memset((void *)(target_fd_trans + oldmax), 0,
493 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
494 }
495 target_fd_trans[fd] = trans;
496}
497
498static void fd_trans_unregister(int fd)
499{
500 if (fd >= 0 && fd < target_fd_max) {
501 target_fd_trans[fd] = NULL;
502 }
503}
504
505static void fd_trans_dup(int oldfd, int newfd)
506{
507 fd_trans_unregister(newfd);
508 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
509 fd_trans_register(newfd, target_fd_trans[oldfd]);
510 }
511}
512
aurel323b3f24a2009-04-15 16:12:13 +0000513static int sys_getcwd1(char *buf, size_t size)
514{
515 if (getcwd(buf, size) == NULL) {
516 /* getcwd() sets errno */
517 return (-1);
518 }
aurel32aaf4ad32009-04-16 14:17:14 +0000519 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000520}
521
Peter Maydell1acae9f2013-07-02 14:04:12 +0100522#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100523#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100524#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000525_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
526 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100527#else
528static int sys_utimensat(int dirfd, const char *pathname,
529 const struct timespec times[2], int flags)
530{
531 errno = ENOSYS;
532 return -1;
533}
ths9007f0e2007-09-25 17:50:37 +0000534#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100535#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000536
537#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000538#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000539
aurel3239b59762008-10-01 21:46:50 +0000540#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000541static int sys_inotify_init(void)
542{
543 return (inotify_init());
544}
aurel3239b59762008-10-01 21:46:50 +0000545#endif
546#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000547static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
548{
549 return (inotify_add_watch(fd, pathname, mask));
550}
aurel3239b59762008-10-01 21:46:50 +0000551#endif
552#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000553static int sys_inotify_rm_watch(int fd, int32_t wd)
554{
aurel328690e422009-04-17 13:50:32 +0000555 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000556}
aurel3239b59762008-10-01 21:46:50 +0000557#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000558#ifdef CONFIG_INOTIFY1
559#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
560static int sys_inotify_init1(int flags)
561{
562 return (inotify_init1(flags));
563}
564#endif
565#endif
aurel323b3f24a2009-04-15 16:12:13 +0000566#else
567/* Userspace can usually survive runtime without inotify */
568#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000569#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000570#undef TARGET_NR_inotify_add_watch
571#undef TARGET_NR_inotify_rm_watch
572#endif /* CONFIG_INOTIFY */
573
Peter Maydell163a05a2011-06-27 17:44:52 +0100574#if defined(TARGET_NR_prlimit64)
575#ifndef __NR_prlimit64
576# define __NR_prlimit64 -1
577#endif
578#define __NR_sys_prlimit64 __NR_prlimit64
579/* The glibc rlimit structure may not be that used by the underlying syscall */
580struct host_rlimit64 {
581 uint64_t rlim_cur;
582 uint64_t rlim_max;
583};
584_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
585 const struct host_rlimit64 *, new_limit,
586 struct host_rlimit64 *, old_limit)
587#endif
588
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100589
590#if defined(TARGET_NR_timer_create)
591/* Maxiumum of 32 active POSIX timers allowed at any one time. */
592static timer_t g_posix_timers[32] = { 0, } ;
593
594static inline int next_free_host_timer(void)
595{
596 int k ;
597 /* FIXME: Does finding the next free slot require a lock? */
598 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
599 if (g_posix_timers[k] == 0) {
600 g_posix_timers[k] = (timer_t) 1;
601 return k;
602 }
603 }
604 return -1;
605}
606#endif
607
Riku Voipio48e515d2011-07-12 15:40:51 +0300608/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000609#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300610static inline int regpairs_aligned(void *cpu_env) {
611 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
612}
613#elif defined(TARGET_MIPS)
614static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000615#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
616/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
617 * of registers which translates to the same as ARM/MIPS, because we start with
618 * r3 as arg1 */
619static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300620#else
621static inline int regpairs_aligned(void *cpu_env) { return 0; }
622#endif
623
thsb92c47c2007-11-01 00:07:38 +0000624#define ERRNO_TABLE_SIZE 1200
625
626/* target_to_host_errno_table[] is initialized from
627 * host_to_target_errno_table[] in syscall_init(). */
628static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
629};
630
ths637947f2007-06-01 12:09:19 +0000631/*
thsfe8f0962007-07-12 10:59:21 +0000632 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000633 * minus the errnos that are not actually generic to all archs.
634 */
thsb92c47c2007-11-01 00:07:38 +0000635static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800636 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000637 [EIDRM] = TARGET_EIDRM,
638 [ECHRNG] = TARGET_ECHRNG,
639 [EL2NSYNC] = TARGET_EL2NSYNC,
640 [EL3HLT] = TARGET_EL3HLT,
641 [EL3RST] = TARGET_EL3RST,
642 [ELNRNG] = TARGET_ELNRNG,
643 [EUNATCH] = TARGET_EUNATCH,
644 [ENOCSI] = TARGET_ENOCSI,
645 [EL2HLT] = TARGET_EL2HLT,
646 [EDEADLK] = TARGET_EDEADLK,
647 [ENOLCK] = TARGET_ENOLCK,
648 [EBADE] = TARGET_EBADE,
649 [EBADR] = TARGET_EBADR,
650 [EXFULL] = TARGET_EXFULL,
651 [ENOANO] = TARGET_ENOANO,
652 [EBADRQC] = TARGET_EBADRQC,
653 [EBADSLT] = TARGET_EBADSLT,
654 [EBFONT] = TARGET_EBFONT,
655 [ENOSTR] = TARGET_ENOSTR,
656 [ENODATA] = TARGET_ENODATA,
657 [ETIME] = TARGET_ETIME,
658 [ENOSR] = TARGET_ENOSR,
659 [ENONET] = TARGET_ENONET,
660 [ENOPKG] = TARGET_ENOPKG,
661 [EREMOTE] = TARGET_EREMOTE,
662 [ENOLINK] = TARGET_ENOLINK,
663 [EADV] = TARGET_EADV,
664 [ESRMNT] = TARGET_ESRMNT,
665 [ECOMM] = TARGET_ECOMM,
666 [EPROTO] = TARGET_EPROTO,
667 [EDOTDOT] = TARGET_EDOTDOT,
668 [EMULTIHOP] = TARGET_EMULTIHOP,
669 [EBADMSG] = TARGET_EBADMSG,
670 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
671 [EOVERFLOW] = TARGET_EOVERFLOW,
672 [ENOTUNIQ] = TARGET_ENOTUNIQ,
673 [EBADFD] = TARGET_EBADFD,
674 [EREMCHG] = TARGET_EREMCHG,
675 [ELIBACC] = TARGET_ELIBACC,
676 [ELIBBAD] = TARGET_ELIBBAD,
677 [ELIBSCN] = TARGET_ELIBSCN,
678 [ELIBMAX] = TARGET_ELIBMAX,
679 [ELIBEXEC] = TARGET_ELIBEXEC,
680 [EILSEQ] = TARGET_EILSEQ,
681 [ENOSYS] = TARGET_ENOSYS,
682 [ELOOP] = TARGET_ELOOP,
683 [ERESTART] = TARGET_ERESTART,
684 [ESTRPIPE] = TARGET_ESTRPIPE,
685 [ENOTEMPTY] = TARGET_ENOTEMPTY,
686 [EUSERS] = TARGET_EUSERS,
687 [ENOTSOCK] = TARGET_ENOTSOCK,
688 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
689 [EMSGSIZE] = TARGET_EMSGSIZE,
690 [EPROTOTYPE] = TARGET_EPROTOTYPE,
691 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
692 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
693 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
694 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
695 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
696 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
697 [EADDRINUSE] = TARGET_EADDRINUSE,
698 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
699 [ENETDOWN] = TARGET_ENETDOWN,
700 [ENETUNREACH] = TARGET_ENETUNREACH,
701 [ENETRESET] = TARGET_ENETRESET,
702 [ECONNABORTED] = TARGET_ECONNABORTED,
703 [ECONNRESET] = TARGET_ECONNRESET,
704 [ENOBUFS] = TARGET_ENOBUFS,
705 [EISCONN] = TARGET_EISCONN,
706 [ENOTCONN] = TARGET_ENOTCONN,
707 [EUCLEAN] = TARGET_EUCLEAN,
708 [ENOTNAM] = TARGET_ENOTNAM,
709 [ENAVAIL] = TARGET_ENAVAIL,
710 [EISNAM] = TARGET_EISNAM,
711 [EREMOTEIO] = TARGET_EREMOTEIO,
712 [ESHUTDOWN] = TARGET_ESHUTDOWN,
713 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
714 [ETIMEDOUT] = TARGET_ETIMEDOUT,
715 [ECONNREFUSED] = TARGET_ECONNREFUSED,
716 [EHOSTDOWN] = TARGET_EHOSTDOWN,
717 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
718 [EALREADY] = TARGET_EALREADY,
719 [EINPROGRESS] = TARGET_EINPROGRESS,
720 [ESTALE] = TARGET_ESTALE,
721 [ECANCELED] = TARGET_ECANCELED,
722 [ENOMEDIUM] = TARGET_ENOMEDIUM,
723 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000724#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000725 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000726#endif
727#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000728 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000729#endif
730#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000731 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000732#endif
733#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000734 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000735#endif
736#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000737 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000738#endif
739#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000740 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000741#endif
thsb92c47c2007-11-01 00:07:38 +0000742};
ths637947f2007-06-01 12:09:19 +0000743
744static inline int host_to_target_errno(int err)
745{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100746 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
747 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000748 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100749 }
ths637947f2007-06-01 12:09:19 +0000750 return err;
751}
752
thsb92c47c2007-11-01 00:07:38 +0000753static inline int target_to_host_errno(int err)
754{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100755 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
756 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000757 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100758 }
thsb92c47c2007-11-01 00:07:38 +0000759 return err;
760}
761
blueswir1992f48a2007-10-14 16:27:31 +0000762static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000763{
764 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000765 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000766 else
767 return ret;
768}
769
blueswir1992f48a2007-10-14 16:27:31 +0000770static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000771{
blueswir1992f48a2007-10-14 16:27:31 +0000772 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000773}
774
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100775const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000776{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100777 if (err == TARGET_ERESTARTSYS) {
778 return "To be restarted";
779 }
780 if (err == TARGET_QEMU_ESIGRETURN) {
781 return "Successful exit from sigreturn";
782 }
783
Alexander Graf962b2892011-11-21 12:04:07 +0100784 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
785 return NULL;
786 }
thsb92c47c2007-11-01 00:07:38 +0000787 return strerror(target_to_host_errno(err));
788}
789
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100790#define safe_syscall0(type, name) \
791static type safe_##name(void) \
792{ \
793 return safe_syscall(__NR_##name); \
794}
795
796#define safe_syscall1(type, name, type1, arg1) \
797static type safe_##name(type1 arg1) \
798{ \
799 return safe_syscall(__NR_##name, arg1); \
800}
801
802#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
803static type safe_##name(type1 arg1, type2 arg2) \
804{ \
805 return safe_syscall(__NR_##name, arg1, arg2); \
806}
807
808#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
809static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
810{ \
811 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
812}
813
814#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
815 type4, arg4) \
816static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
817{ \
818 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
819}
820
821#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
822 type4, arg4, type5, arg5) \
823static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
824 type5 arg5) \
825{ \
826 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
827}
828
829#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
830 type4, arg4, type5, arg5, type6, arg6) \
831static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
832 type5 arg5, type6 arg6) \
833{ \
834 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
835}
836
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100837safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
838safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100839safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
840 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100841safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
842 struct rusage *, rusage)
843safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
844 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100845safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100846safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
847 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100848safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
849 struct timespec *, tsp, const sigset_t *, sigmask,
850 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100851safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
852 int, maxevents, int, timeout, const sigset_t *, sigmask,
853 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100854safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
855 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100856safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100857safe_syscall2(int, kill, pid_t, pid, int, sig)
858safe_syscall2(int, tkill, int, tid, int, sig)
859safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100860safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
861safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100862safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
863 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100864safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
865 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
866safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
867 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
868safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
869safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100870safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100871safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
872 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100873safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
874 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100875safe_syscall2(int, nanosleep, const struct timespec *, req,
876 struct timespec *, rem)
877#ifdef TARGET_NR_clock_nanosleep
878safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
879 const struct timespec *, req, struct timespec *, rem)
880#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100881#ifdef __NR_msgsnd
882safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
883 int, flags)
884safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
885 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100886safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
887 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100888#else
889/* This host kernel architecture uses a single ipc syscall; fake up
890 * wrappers for the sub-operations to hide this implementation detail.
891 * Annoyingly we can't include linux/ipc.h to get the constant definitions
892 * for the call parameter because some structs in there conflict with the
893 * sys/ipc.h ones. So we just define them here, and rely on them being
894 * the same for all host architectures.
895 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100896#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100897#define Q_MSGSND 11
898#define Q_MSGRCV 12
899#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
900
901safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
902 void *, ptr, long, fifth)
903static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
904{
905 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
906}
907static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
908{
909 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
910}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100911static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
912 const struct timespec *timeout)
913{
914 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
915 (long)timeout);
916}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100917#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100918#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
919safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
920 size_t, len, unsigned, prio, const struct timespec *, timeout)
921safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
922 size_t, len, unsigned *, prio, const struct timespec *, timeout)
923#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100924/* We do ioctl like this rather than via safe_syscall3 to preserve the
925 * "third argument might be integer or pointer or not present" behaviour of
926 * the libc function.
927 */
928#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100929/* Similarly for fcntl. Note that callers must always:
930 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
931 * use the flock64 struct rather than unsuffixed flock
932 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
933 */
934#ifdef __NR_fcntl64
935#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
936#else
937#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
938#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100939
Paul Burton8289d112014-06-22 11:25:33 +0100940static inline int host_to_target_sock_type(int host_type)
941{
942 int target_type;
943
944 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
945 case SOCK_DGRAM:
946 target_type = TARGET_SOCK_DGRAM;
947 break;
948 case SOCK_STREAM:
949 target_type = TARGET_SOCK_STREAM;
950 break;
951 default:
952 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
953 break;
954 }
955
956#if defined(SOCK_CLOEXEC)
957 if (host_type & SOCK_CLOEXEC) {
958 target_type |= TARGET_SOCK_CLOEXEC;
959 }
960#endif
961
962#if defined(SOCK_NONBLOCK)
963 if (host_type & SOCK_NONBLOCK) {
964 target_type |= TARGET_SOCK_NONBLOCK;
965 }
966#endif
967
968 return target_type;
969}
970
blueswir1992f48a2007-10-14 16:27:31 +0000971static abi_ulong target_brk;
972static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000973static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000974
blueswir1992f48a2007-10-14 16:27:31 +0000975void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000976{
blueswir14c1de732007-07-07 20:45:44 +0000977 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000978 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000979}
980
vincent4d1de872011-06-14 21:56:33 +0000981//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
982#define DEBUGF_BRK(message, args...)
983
ths0da46a62007-10-20 20:23:07 +0000984/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000985abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000986{
blueswir1992f48a2007-10-14 16:27:31 +0000987 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +0100988 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +0000989
Paul Brook3a0c6c42012-02-09 19:04:27 +0000990 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000991
vincent4d1de872011-06-14 21:56:33 +0000992 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000993 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000994 return target_brk;
995 }
996 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000997 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
998 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000999 return target_brk;
1000 }
bellard31e31b82003-02-18 22:55:36 +00001001
vincent4d1de872011-06-14 21:56:33 +00001002 /* If the new brk is less than the highest page reserved to the
1003 * target heap allocation, set it and we're almost done... */
1004 if (new_brk <= brk_page) {
1005 /* Heap contents are initialized to zero, as for anonymous
1006 * mapped pages. */
1007 if (new_brk > target_brk) {
1008 memset(g2h(target_brk), 0, new_brk - target_brk);
1009 }
bellard31e31b82003-02-18 22:55:36 +00001010 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001011 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001012 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001013 }
1014
Peter Maydell00faf082011-04-18 16:34:24 +01001015 /* We need to allocate more memory after the brk... Note that
1016 * we don't use MAP_FIXED because that will map over the top of
1017 * any existing mapping (like the one with the host libc or qemu
1018 * itself); instead we treat "mapped but at wrong address" as
1019 * a failure and unmap again.
1020 */
vincent4d1de872011-06-14 21:56:33 +00001021 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001022 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001023 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001024 MAP_ANON|MAP_PRIVATE, 0, 0));
1025
1026 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001027 /* Heap contents are initialized to zero, as for anonymous
1028 * mapped pages. Technically the new pages are already
1029 * initialized to zero since they *are* anonymous mapped
1030 * pages, however we have to take care with the contents that
1031 * come from the remaining part of the previous page: it may
1032 * contains garbage data due to a previous heap usage (grown
1033 * then shrunken). */
1034 memset(g2h(target_brk), 0, brk_page - target_brk);
1035
Peter Maydell00faf082011-04-18 16:34:24 +01001036 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001037 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001038 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1039 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001040 return target_brk;
1041 } else if (mapped_addr != -1) {
1042 /* Mapped but at wrong address, meaning there wasn't actually
1043 * enough space for this brk.
1044 */
1045 target_munmap(mapped_addr, new_alloc_size);
1046 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001047 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001048 }
1049 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001050 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001051 }
balrog7ab240a2008-04-26 12:17:34 +00001052
Richard Henderson7dd46c02010-05-03 10:07:49 -07001053#if defined(TARGET_ALPHA)
1054 /* We (partially) emulate OSF/1 on Alpha, which requires we
1055 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001056 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001057#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001058 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001059 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001060}
1061
ths26edcf42007-12-09 02:25:24 +00001062static inline abi_long copy_from_user_fdset(fd_set *fds,
1063 abi_ulong target_fds_addr,
1064 int n)
bellard31e31b82003-02-18 22:55:36 +00001065{
ths26edcf42007-12-09 02:25:24 +00001066 int i, nw, j, k;
1067 abi_ulong b, *target_fds;
1068
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001069 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001070 if (!(target_fds = lock_user(VERIFY_READ,
1071 target_fds_addr,
1072 sizeof(abi_ulong) * nw,
1073 1)))
1074 return -TARGET_EFAULT;
1075
1076 FD_ZERO(fds);
1077 k = 0;
1078 for (i = 0; i < nw; i++) {
1079 /* grab the abi_ulong */
1080 __get_user(b, &target_fds[i]);
1081 for (j = 0; j < TARGET_ABI_BITS; j++) {
1082 /* check the bit inside the abi_ulong */
1083 if ((b >> j) & 1)
1084 FD_SET(k, fds);
1085 k++;
bellard31e31b82003-02-18 22:55:36 +00001086 }
bellard31e31b82003-02-18 22:55:36 +00001087 }
ths26edcf42007-12-09 02:25:24 +00001088
1089 unlock_user(target_fds, target_fds_addr, 0);
1090
1091 return 0;
bellard31e31b82003-02-18 22:55:36 +00001092}
1093
Mike Frysinger055e0902011-06-03 17:01:49 -04001094static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1095 abi_ulong target_fds_addr,
1096 int n)
1097{
1098 if (target_fds_addr) {
1099 if (copy_from_user_fdset(fds, target_fds_addr, n))
1100 return -TARGET_EFAULT;
1101 *fds_ptr = fds;
1102 } else {
1103 *fds_ptr = NULL;
1104 }
1105 return 0;
1106}
1107
ths26edcf42007-12-09 02:25:24 +00001108static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1109 const fd_set *fds,
1110 int n)
bellard31e31b82003-02-18 22:55:36 +00001111{
bellard31e31b82003-02-18 22:55:36 +00001112 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001113 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001114 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001115
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001116 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001117 if (!(target_fds = lock_user(VERIFY_WRITE,
1118 target_fds_addr,
1119 sizeof(abi_ulong) * nw,
1120 0)))
1121 return -TARGET_EFAULT;
1122
1123 k = 0;
1124 for (i = 0; i < nw; i++) {
1125 v = 0;
1126 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001127 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001128 k++;
bellard31e31b82003-02-18 22:55:36 +00001129 }
ths26edcf42007-12-09 02:25:24 +00001130 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001131 }
ths26edcf42007-12-09 02:25:24 +00001132
1133 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1134
1135 return 0;
bellard31e31b82003-02-18 22:55:36 +00001136}
1137
bellardc596ed12003-07-13 17:32:31 +00001138#if defined(__alpha__)
1139#define HOST_HZ 1024
1140#else
1141#define HOST_HZ 100
1142#endif
1143
blueswir1992f48a2007-10-14 16:27:31 +00001144static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001145{
1146#if HOST_HZ == TARGET_HZ
1147 return ticks;
1148#else
1149 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1150#endif
1151}
1152
bellard579a97f2007-11-11 14:26:47 +00001153static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1154 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001155{
pbrook53a59602006-03-25 19:31:22 +00001156 struct target_rusage *target_rusage;
1157
bellard579a97f2007-11-11 14:26:47 +00001158 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1159 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001160 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1161 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1162 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1163 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1164 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1165 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1166 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1167 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1168 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1169 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1170 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1171 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1172 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1173 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1174 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1175 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1176 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1177 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001178 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001179
1180 return 0;
bellardb4091862003-05-16 15:39:34 +00001181}
1182
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001183static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001184{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001185 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001186 rlim_t result;
1187
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001188 target_rlim_swap = tswapal(target_rlim);
1189 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1190 return RLIM_INFINITY;
1191
1192 result = target_rlim_swap;
1193 if (target_rlim_swap != (rlim_t)result)
1194 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001195
1196 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001197}
1198
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001199static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001200{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001201 abi_ulong target_rlim_swap;
1202 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001203
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001204 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001205 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001206 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001207 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001208 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001209
1210 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001211}
1212
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001213static inline int target_to_host_resource(int code)
1214{
1215 switch (code) {
1216 case TARGET_RLIMIT_AS:
1217 return RLIMIT_AS;
1218 case TARGET_RLIMIT_CORE:
1219 return RLIMIT_CORE;
1220 case TARGET_RLIMIT_CPU:
1221 return RLIMIT_CPU;
1222 case TARGET_RLIMIT_DATA:
1223 return RLIMIT_DATA;
1224 case TARGET_RLIMIT_FSIZE:
1225 return RLIMIT_FSIZE;
1226 case TARGET_RLIMIT_LOCKS:
1227 return RLIMIT_LOCKS;
1228 case TARGET_RLIMIT_MEMLOCK:
1229 return RLIMIT_MEMLOCK;
1230 case TARGET_RLIMIT_MSGQUEUE:
1231 return RLIMIT_MSGQUEUE;
1232 case TARGET_RLIMIT_NICE:
1233 return RLIMIT_NICE;
1234 case TARGET_RLIMIT_NOFILE:
1235 return RLIMIT_NOFILE;
1236 case TARGET_RLIMIT_NPROC:
1237 return RLIMIT_NPROC;
1238 case TARGET_RLIMIT_RSS:
1239 return RLIMIT_RSS;
1240 case TARGET_RLIMIT_RTPRIO:
1241 return RLIMIT_RTPRIO;
1242 case TARGET_RLIMIT_SIGPENDING:
1243 return RLIMIT_SIGPENDING;
1244 case TARGET_RLIMIT_STACK:
1245 return RLIMIT_STACK;
1246 default:
1247 return code;
1248 }
1249}
1250
ths788f5ec2007-12-09 02:37:05 +00001251static inline abi_long copy_from_user_timeval(struct timeval *tv,
1252 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001253{
pbrook53a59602006-03-25 19:31:22 +00001254 struct target_timeval *target_tv;
1255
ths788f5ec2007-12-09 02:37:05 +00001256 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001257 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001258
1259 __get_user(tv->tv_sec, &target_tv->tv_sec);
1260 __get_user(tv->tv_usec, &target_tv->tv_usec);
1261
1262 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001263
1264 return 0;
bellard31e31b82003-02-18 22:55:36 +00001265}
1266
ths788f5ec2007-12-09 02:37:05 +00001267static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1268 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001269{
pbrook53a59602006-03-25 19:31:22 +00001270 struct target_timeval *target_tv;
1271
ths788f5ec2007-12-09 02:37:05 +00001272 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001273 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001274
1275 __put_user(tv->tv_sec, &target_tv->tv_sec);
1276 __put_user(tv->tv_usec, &target_tv->tv_usec);
1277
1278 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001279
1280 return 0;
bellard31e31b82003-02-18 22:55:36 +00001281}
1282
Paul Burtonef4467e2014-06-22 11:25:40 +01001283static inline abi_long copy_from_user_timezone(struct timezone *tz,
1284 abi_ulong target_tz_addr)
1285{
1286 struct target_timezone *target_tz;
1287
1288 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1289 return -TARGET_EFAULT;
1290 }
1291
1292 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1293 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1294
1295 unlock_user_struct(target_tz, target_tz_addr, 0);
1296
1297 return 0;
1298}
1299
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001300#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1301#include <mqueue.h>
1302
aurel3224e10032009-04-15 16:11:43 +00001303static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1304 abi_ulong target_mq_attr_addr)
1305{
1306 struct target_mq_attr *target_mq_attr;
1307
1308 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1309 target_mq_attr_addr, 1))
1310 return -TARGET_EFAULT;
1311
1312 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1313 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1314 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1315 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1316
1317 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1318
1319 return 0;
1320}
1321
1322static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1323 const struct mq_attr *attr)
1324{
1325 struct target_mq_attr *target_mq_attr;
1326
1327 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1328 target_mq_attr_addr, 0))
1329 return -TARGET_EFAULT;
1330
1331 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1332 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1333 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1334 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1335
1336 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1337
1338 return 0;
1339}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001340#endif
bellard31e31b82003-02-18 22:55:36 +00001341
Mike Frysinger055e0902011-06-03 17:01:49 -04001342#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001343/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001344static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001345 abi_ulong rfd_addr, abi_ulong wfd_addr,
1346 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001347{
1348 fd_set rfds, wfds, efds;
1349 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001350 struct timeval tv;
1351 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001352 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001353
Mike Frysinger055e0902011-06-03 17:01:49 -04001354 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1355 if (ret) {
1356 return ret;
pbrook53a59602006-03-25 19:31:22 +00001357 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001358 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1359 if (ret) {
1360 return ret;
pbrook53a59602006-03-25 19:31:22 +00001361 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001362 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1363 if (ret) {
1364 return ret;
pbrook53a59602006-03-25 19:31:22 +00001365 }
ths3b46e622007-09-17 08:09:54 +00001366
ths26edcf42007-12-09 02:25:24 +00001367 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001368 if (copy_from_user_timeval(&tv, target_tv_addr))
1369 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001370 ts.tv_sec = tv.tv_sec;
1371 ts.tv_nsec = tv.tv_usec * 1000;
1372 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001373 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001374 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001375 }
ths26edcf42007-12-09 02:25:24 +00001376
Peter Maydell6df9d382016-05-12 18:47:51 +01001377 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1378 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001379
ths26edcf42007-12-09 02:25:24 +00001380 if (!is_error(ret)) {
1381 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1382 return -TARGET_EFAULT;
1383 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1384 return -TARGET_EFAULT;
1385 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1386 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001387
Peter Maydell6df9d382016-05-12 18:47:51 +01001388 if (target_tv_addr) {
1389 tv.tv_sec = ts.tv_sec;
1390 tv.tv_usec = ts.tv_nsec / 1000;
1391 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1392 return -TARGET_EFAULT;
1393 }
1394 }
bellard31e31b82003-02-18 22:55:36 +00001395 }
bellard579a97f2007-11-11 14:26:47 +00001396
bellard31e31b82003-02-18 22:55:36 +00001397 return ret;
1398}
Mike Frysinger055e0902011-06-03 17:01:49 -04001399#endif
bellard31e31b82003-02-18 22:55:36 +00001400
Riku Voipio099d6b02009-05-05 12:10:04 +03001401static abi_long do_pipe2(int host_pipe[], int flags)
1402{
1403#ifdef CONFIG_PIPE2
1404 return pipe2(host_pipe, flags);
1405#else
1406 return -ENOSYS;
1407#endif
1408}
1409
Richard Hendersonfb41a662010-05-03 10:07:52 -07001410static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1411 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001412{
1413 int host_pipe[2];
1414 abi_long ret;
1415 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1416
1417 if (is_error(ret))
1418 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001419
1420 /* Several targets have special calling conventions for the original
1421 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1422 if (!is_pipe2) {
1423#if defined(TARGET_ALPHA)
1424 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1425 return host_pipe[0];
1426#elif defined(TARGET_MIPS)
1427 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1428 return host_pipe[0];
1429#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001430 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001431 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001432#elif defined(TARGET_SPARC)
1433 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1434 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001435#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001436 }
1437
Riku Voipio099d6b02009-05-05 12:10:04 +03001438 if (put_user_s32(host_pipe[0], pipedes)
1439 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1440 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001441 return get_errno(ret);
1442}
1443
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001444static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1445 abi_ulong target_addr,
1446 socklen_t len)
1447{
1448 struct target_ip_mreqn *target_smreqn;
1449
1450 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1451 if (!target_smreqn)
1452 return -TARGET_EFAULT;
1453 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1454 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1455 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001456 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001457 unlock_user(target_smreqn, target_addr, 0);
1458
1459 return 0;
1460}
1461
Laurent Vivier7b36f782015-10-28 21:40:44 +01001462static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001463 abi_ulong target_addr,
1464 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001465{
aurel32607175e2009-04-15 16:11:59 +00001466 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1467 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001468 struct target_sockaddr *target_saddr;
1469
Laurent Vivier7b36f782015-10-28 21:40:44 +01001470 if (fd_trans_target_to_host_addr(fd)) {
1471 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1472 }
1473
bellard579a97f2007-11-11 14:26:47 +00001474 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1475 if (!target_saddr)
1476 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001477
1478 sa_family = tswap16(target_saddr->sa_family);
1479
1480 /* Oops. The caller might send a incomplete sun_path; sun_path
1481 * must be terminated by \0 (see the manual page), but
1482 * unfortunately it is quite common to specify sockaddr_un
1483 * length as "strlen(x->sun_path)" while it should be
1484 * "strlen(...) + 1". We'll fix that here if needed.
1485 * Linux kernel has a similar feature.
1486 */
1487
1488 if (sa_family == AF_UNIX) {
1489 if (len < unix_maxlen && len > 0) {
1490 char *cp = (char*)target_saddr;
1491
1492 if ( cp[len-1] && !cp[len] )
1493 len++;
1494 }
1495 if (len > unix_maxlen)
1496 len = unix_maxlen;
1497 }
1498
pbrook53a59602006-03-25 19:31:22 +00001499 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001500 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001501 if (sa_family == AF_NETLINK) {
1502 struct sockaddr_nl *nladdr;
1503
1504 nladdr = (struct sockaddr_nl *)addr;
1505 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1506 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1507 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001508 struct target_sockaddr_ll *lladdr;
1509
1510 lladdr = (struct target_sockaddr_ll *)addr;
1511 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1512 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1513 }
pbrook53a59602006-03-25 19:31:22 +00001514 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001515
1516 return 0;
bellard7854b052003-03-29 17:22:23 +00001517}
1518
bellard579a97f2007-11-11 14:26:47 +00001519static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1520 struct sockaddr *addr,
1521 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001522{
pbrook53a59602006-03-25 19:31:22 +00001523 struct target_sockaddr *target_saddr;
1524
Peter Maydella1e22192016-07-07 15:44:43 +01001525 if (len == 0) {
1526 return 0;
1527 }
1528
bellard579a97f2007-11-11 14:26:47 +00001529 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1530 if (!target_saddr)
1531 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001532 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001533 if (len >= offsetof(struct target_sockaddr, sa_family) +
1534 sizeof(target_saddr->sa_family)) {
1535 target_saddr->sa_family = tswap16(addr->sa_family);
1536 }
1537 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001538 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1539 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1540 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001541 } else if (addr->sa_family == AF_PACKET) {
1542 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1543 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1544 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001545 }
pbrook53a59602006-03-25 19:31:22 +00001546 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001547
1548 return 0;
bellard7854b052003-03-29 17:22:23 +00001549}
1550
bellard5a4a8982007-11-11 17:39:18 +00001551static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1552 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001553{
1554 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001555 abi_long msg_controllen;
1556 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001557 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001558 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001559
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001560 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001561 if (msg_controllen < sizeof (struct target_cmsghdr))
1562 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001563 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001564 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001565 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001566 if (!target_cmsg)
1567 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001568
1569 while (cmsg && target_cmsg) {
1570 void *data = CMSG_DATA(cmsg);
1571 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1572
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001573 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001574 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1575
1576 space += CMSG_SPACE(len);
1577 if (space > msgh->msg_controllen) {
1578 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001579 /* This is a QEMU bug, since we allocated the payload
1580 * area ourselves (unlike overflow in host-to-target
1581 * conversion, which is just the guest giving us a buffer
1582 * that's too small). It can't happen for the payload types
1583 * we currently support; if it becomes an issue in future
1584 * we would need to improve our allocation strategy to
1585 * something more intelligent than "twice the size of the
1586 * target buffer we're reading from".
1587 */
bellard31febb72005-12-18 20:03:27 +00001588 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001589 break;
1590 }
1591
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001592 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1593 cmsg->cmsg_level = SOL_SOCKET;
1594 } else {
1595 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1596 }
bellard7854b052003-03-29 17:22:23 +00001597 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1598 cmsg->cmsg_len = CMSG_LEN(len);
1599
Alex Suykov30b8b682014-12-23 07:52:58 +02001600 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001601 int *fd = (int *)data;
1602 int *target_fd = (int *)target_data;
1603 int i, numfds = len / sizeof(int);
1604
Peter Maydell876e23c2015-05-26 19:46:32 +01001605 for (i = 0; i < numfds; i++) {
1606 __get_user(fd[i], target_fd + i);
1607 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001608 } else if (cmsg->cmsg_level == SOL_SOCKET
1609 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1610 struct ucred *cred = (struct ucred *)data;
1611 struct target_ucred *target_cred =
1612 (struct target_ucred *)target_data;
1613
Peter Maydell876e23c2015-05-26 19:46:32 +01001614 __get_user(cred->pid, &target_cred->pid);
1615 __get_user(cred->uid, &target_cred->uid);
1616 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001617 } else {
1618 gemu_log("Unsupported ancillary data: %d/%d\n",
1619 cmsg->cmsg_level, cmsg->cmsg_type);
1620 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001621 }
1622
1623 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001624 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1625 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001626 }
bellard5a4a8982007-11-11 17:39:18 +00001627 unlock_user(target_cmsg, target_cmsg_addr, 0);
1628 the_end:
bellard7854b052003-03-29 17:22:23 +00001629 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001630 return 0;
bellard7854b052003-03-29 17:22:23 +00001631}
1632
bellard5a4a8982007-11-11 17:39:18 +00001633static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1634 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001635{
1636 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001637 abi_long msg_controllen;
1638 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001639 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001640 socklen_t space = 0;
1641
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001642 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001643 if (msg_controllen < sizeof (struct target_cmsghdr))
1644 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001645 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001646 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001647 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001648 if (!target_cmsg)
1649 return -TARGET_EFAULT;
1650
bellard7854b052003-03-29 17:22:23 +00001651 while (cmsg && target_cmsg) {
1652 void *data = CMSG_DATA(cmsg);
1653 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1654
1655 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001656 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001657
Peter Maydellc2aeb252015-05-26 19:46:31 +01001658 /* We never copy a half-header but may copy half-data;
1659 * this is Linux's behaviour in put_cmsg(). Note that
1660 * truncation here is a guest problem (which we report
1661 * to the guest via the CTRUNC bit), unlike truncation
1662 * in target_to_host_cmsg, which is a QEMU bug.
1663 */
1664 if (msg_controllen < sizeof(struct cmsghdr)) {
1665 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001666 break;
1667 }
1668
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001669 if (cmsg->cmsg_level == SOL_SOCKET) {
1670 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1671 } else {
1672 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1673 }
bellard7854b052003-03-29 17:22:23 +00001674 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001675
Peter Maydellc2aeb252015-05-26 19:46:31 +01001676 tgt_len = TARGET_CMSG_LEN(len);
1677
1678 /* Payload types which need a different size of payload on
1679 * the target must adjust tgt_len here.
1680 */
1681 switch (cmsg->cmsg_level) {
1682 case SOL_SOCKET:
1683 switch (cmsg->cmsg_type) {
1684 case SO_TIMESTAMP:
1685 tgt_len = sizeof(struct target_timeval);
1686 break;
1687 default:
1688 break;
1689 }
1690 default:
1691 break;
1692 }
1693
1694 if (msg_controllen < tgt_len) {
1695 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1696 tgt_len = msg_controllen;
1697 }
1698
1699 /* We must now copy-and-convert len bytes of payload
1700 * into tgt_len bytes of destination space. Bear in mind
1701 * that in both source and destination we may be dealing
1702 * with a truncated value!
1703 */
Huw Davies52b65492014-04-17 14:02:47 +01001704 switch (cmsg->cmsg_level) {
1705 case SOL_SOCKET:
1706 switch (cmsg->cmsg_type) {
1707 case SCM_RIGHTS:
1708 {
1709 int *fd = (int *)data;
1710 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001711 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001712
Peter Maydell876e23c2015-05-26 19:46:32 +01001713 for (i = 0; i < numfds; i++) {
1714 __put_user(fd[i], target_fd + i);
1715 }
Huw Davies52b65492014-04-17 14:02:47 +01001716 break;
1717 }
1718 case SO_TIMESTAMP:
1719 {
1720 struct timeval *tv = (struct timeval *)data;
1721 struct target_timeval *target_tv =
1722 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001723
Peter Maydellc2aeb252015-05-26 19:46:31 +01001724 if (len != sizeof(struct timeval) ||
1725 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001726 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001727 }
Huw Davies52b65492014-04-17 14:02:47 +01001728
1729 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001730 __put_user(tv->tv_sec, &target_tv->tv_sec);
1731 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001732 break;
1733 }
Huw Davies4bc29752014-04-17 14:02:48 +01001734 case SCM_CREDENTIALS:
1735 {
1736 struct ucred *cred = (struct ucred *)data;
1737 struct target_ucred *target_cred =
1738 (struct target_ucred *)target_data;
1739
1740 __put_user(cred->pid, &target_cred->pid);
1741 __put_user(cred->uid, &target_cred->uid);
1742 __put_user(cred->gid, &target_cred->gid);
1743 break;
1744 }
Huw Davies52b65492014-04-17 14:02:47 +01001745 default:
1746 goto unimplemented;
1747 }
1748 break;
1749
1750 default:
1751 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001752 gemu_log("Unsupported ancillary data: %d/%d\n",
1753 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001754 memcpy(target_data, data, MIN(len, tgt_len));
1755 if (tgt_len > len) {
1756 memset(target_data + len, 0, tgt_len - len);
1757 }
bellard7854b052003-03-29 17:22:23 +00001758 }
1759
Peter Maydellc2aeb252015-05-26 19:46:31 +01001760 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001761 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001762 if (msg_controllen < tgt_space) {
1763 tgt_space = msg_controllen;
1764 }
1765 msg_controllen -= tgt_space;
1766 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001767 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001768 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1769 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001770 }
bellard5a4a8982007-11-11 17:39:18 +00001771 unlock_user(target_cmsg, target_cmsg_addr, space);
1772 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001773 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001774 return 0;
bellard7854b052003-03-29 17:22:23 +00001775}
1776
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001777static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1778{
1779 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1780 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1781 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1782 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1783 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1784}
1785
1786static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1787 size_t len,
1788 abi_long (*host_to_target_nlmsg)
1789 (struct nlmsghdr *))
1790{
1791 uint32_t nlmsg_len;
1792 abi_long ret;
1793
1794 while (len > sizeof(struct nlmsghdr)) {
1795
1796 nlmsg_len = nlh->nlmsg_len;
1797 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1798 nlmsg_len > len) {
1799 break;
1800 }
1801
1802 switch (nlh->nlmsg_type) {
1803 case NLMSG_DONE:
1804 tswap_nlmsghdr(nlh);
1805 return 0;
1806 case NLMSG_NOOP:
1807 break;
1808 case NLMSG_ERROR:
1809 {
1810 struct nlmsgerr *e = NLMSG_DATA(nlh);
1811 e->error = tswap32(e->error);
1812 tswap_nlmsghdr(&e->msg);
1813 tswap_nlmsghdr(nlh);
1814 return 0;
1815 }
1816 default:
1817 ret = host_to_target_nlmsg(nlh);
1818 if (ret < 0) {
1819 tswap_nlmsghdr(nlh);
1820 return ret;
1821 }
1822 break;
1823 }
1824 tswap_nlmsghdr(nlh);
1825 len -= NLMSG_ALIGN(nlmsg_len);
1826 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1827 }
1828 return 0;
1829}
1830
1831static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1832 size_t len,
1833 abi_long (*target_to_host_nlmsg)
1834 (struct nlmsghdr *))
1835{
1836 int ret;
1837
1838 while (len > sizeof(struct nlmsghdr)) {
1839 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1840 tswap32(nlh->nlmsg_len) > len) {
1841 break;
1842 }
1843 tswap_nlmsghdr(nlh);
1844 switch (nlh->nlmsg_type) {
1845 case NLMSG_DONE:
1846 return 0;
1847 case NLMSG_NOOP:
1848 break;
1849 case NLMSG_ERROR:
1850 {
1851 struct nlmsgerr *e = NLMSG_DATA(nlh);
1852 e->error = tswap32(e->error);
1853 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02001854 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001855 }
1856 default:
1857 ret = target_to_host_nlmsg(nlh);
1858 if (ret < 0) {
1859 return ret;
1860 }
1861 }
1862 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1863 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1864 }
1865 return 0;
1866}
1867
Laurent Vivier575b22b2016-06-02 22:14:15 +02001868#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02001869static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
1870 size_t len, void *context,
1871 abi_long (*host_to_target_nlattr)
1872 (struct nlattr *,
1873 void *context))
1874{
1875 unsigned short nla_len;
1876 abi_long ret;
1877
1878 while (len > sizeof(struct nlattr)) {
1879 nla_len = nlattr->nla_len;
1880 if (nla_len < sizeof(struct nlattr) ||
1881 nla_len > len) {
1882 break;
1883 }
1884 ret = host_to_target_nlattr(nlattr, context);
1885 nlattr->nla_len = tswap16(nlattr->nla_len);
1886 nlattr->nla_type = tswap16(nlattr->nla_type);
1887 if (ret < 0) {
1888 return ret;
1889 }
1890 len -= NLA_ALIGN(nla_len);
1891 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
1892 }
1893 return 0;
1894}
1895
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001896static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1897 size_t len,
1898 abi_long (*host_to_target_rtattr)
1899 (struct rtattr *))
1900{
1901 unsigned short rta_len;
1902 abi_long ret;
1903
1904 while (len > sizeof(struct rtattr)) {
1905 rta_len = rtattr->rta_len;
1906 if (rta_len < sizeof(struct rtattr) ||
1907 rta_len > len) {
1908 break;
1909 }
1910 ret = host_to_target_rtattr(rtattr);
1911 rtattr->rta_len = tswap16(rtattr->rta_len);
1912 rtattr->rta_type = tswap16(rtattr->rta_type);
1913 if (ret < 0) {
1914 return ret;
1915 }
1916 len -= RTA_ALIGN(rta_len);
1917 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1918 }
1919 return 0;
1920}
1921
Laurent Vivierc5dff282016-06-27 18:54:30 +02001922#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
1923
1924static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
1925 void *context)
1926{
1927 uint16_t *u16;
1928 uint32_t *u32;
1929 uint64_t *u64;
1930
1931 switch (nlattr->nla_type) {
1932 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001933 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001934 break;
1935 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001936 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001937 break;
1938 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001939 case QEMU_IFLA_BR_VLAN_FILTERING:
1940 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
1941 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
1942 case QEMU_IFLA_BR_MCAST_ROUTER:
1943 case QEMU_IFLA_BR_MCAST_SNOOPING:
1944 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
1945 case QEMU_IFLA_BR_MCAST_QUERIER:
1946 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
1947 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
1948 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001949 break;
1950 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001951 case QEMU_IFLA_BR_PRIORITY:
1952 case QEMU_IFLA_BR_VLAN_PROTOCOL:
1953 case QEMU_IFLA_BR_GROUP_FWD_MASK:
1954 case QEMU_IFLA_BR_ROOT_PORT:
1955 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001956 u16 = NLA_DATA(nlattr);
1957 *u16 = tswap16(*u16);
1958 break;
1959 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001960 case QEMU_IFLA_BR_FORWARD_DELAY:
1961 case QEMU_IFLA_BR_HELLO_TIME:
1962 case QEMU_IFLA_BR_MAX_AGE:
1963 case QEMU_IFLA_BR_AGEING_TIME:
1964 case QEMU_IFLA_BR_STP_STATE:
1965 case QEMU_IFLA_BR_ROOT_PATH_COST:
1966 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
1967 case QEMU_IFLA_BR_MCAST_HASH_MAX:
1968 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
1969 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001970 u32 = NLA_DATA(nlattr);
1971 *u32 = tswap32(*u32);
1972 break;
1973 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001974 case QEMU_IFLA_BR_HELLO_TIMER:
1975 case QEMU_IFLA_BR_TCN_TIMER:
1976 case QEMU_IFLA_BR_GC_TIMER:
1977 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
1978 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
1979 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
1980 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
1981 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
1982 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
1983 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001984 u64 = NLA_DATA(nlattr);
1985 *u64 = tswap64(*u64);
1986 break;
1987 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001988 case QEMU_IFLA_BR_ROOT_ID:
1989 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001990 break;
1991 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02001992 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02001993 break;
1994 }
1995 return 0;
1996}
1997
1998static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
1999 void *context)
2000{
2001 uint16_t *u16;
2002 uint32_t *u32;
2003 uint64_t *u64;
2004
2005 switch (nlattr->nla_type) {
2006 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002007 case QEMU_IFLA_BRPORT_STATE:
2008 case QEMU_IFLA_BRPORT_MODE:
2009 case QEMU_IFLA_BRPORT_GUARD:
2010 case QEMU_IFLA_BRPORT_PROTECT:
2011 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2012 case QEMU_IFLA_BRPORT_LEARNING:
2013 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2014 case QEMU_IFLA_BRPORT_PROXYARP:
2015 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2016 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2017 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2018 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2019 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002020 break;
2021 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002022 case QEMU_IFLA_BRPORT_PRIORITY:
2023 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2024 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2025 case QEMU_IFLA_BRPORT_ID:
2026 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002027 u16 = NLA_DATA(nlattr);
2028 *u16 = tswap16(*u16);
2029 break;
2030 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002031 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002032 u32 = NLA_DATA(nlattr);
2033 *u32 = tswap32(*u32);
2034 break;
2035 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002036 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2037 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2038 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002039 u64 = NLA_DATA(nlattr);
2040 *u64 = tswap64(*u64);
2041 break;
2042 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002043 case QEMU_IFLA_BRPORT_ROOT_ID:
2044 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002045 break;
2046 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002047 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002048 break;
2049 }
2050 return 0;
2051}
2052
2053struct linkinfo_context {
2054 int len;
2055 char *name;
2056 int slave_len;
2057 char *slave_name;
2058};
2059
2060static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2061 void *context)
2062{
2063 struct linkinfo_context *li_context = context;
2064
2065 switch (nlattr->nla_type) {
2066 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002067 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002068 li_context->name = NLA_DATA(nlattr);
2069 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2070 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002071 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002072 li_context->slave_name = NLA_DATA(nlattr);
2073 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2074 break;
2075 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002076 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002077 /* FIXME: only used by CAN */
2078 break;
2079 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002080 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002081 if (strncmp(li_context->name, "bridge",
2082 li_context->len) == 0) {
2083 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2084 nlattr->nla_len,
2085 NULL,
2086 host_to_target_data_bridge_nlattr);
2087 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002088 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002089 }
2090 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002091 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002092 if (strncmp(li_context->slave_name, "bridge",
2093 li_context->slave_len) == 0) {
2094 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2095 nlattr->nla_len,
2096 NULL,
2097 host_to_target_slave_data_bridge_nlattr);
2098 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002099 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002100 li_context->slave_name);
2101 }
2102 break;
2103 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002104 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002105 break;
2106 }
2107
2108 return 0;
2109}
2110
2111static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2112 void *context)
2113{
2114 uint32_t *u32;
2115 int i;
2116
2117 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002118 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002119 u32 = NLA_DATA(nlattr);
2120 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2121 i++) {
2122 u32[i] = tswap32(u32[i]);
2123 }
2124 break;
2125 default:
2126 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2127 }
2128 return 0;
2129}
2130
2131static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2132 void *context)
2133{
2134 uint32_t *u32;
2135 uint64_t *u64;
2136 struct ifla_cacheinfo *ci;
2137 int i;
2138
2139 switch (nlattr->nla_type) {
2140 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002141 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002142 break;
2143 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002144 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002145 break;
2146 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002147 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002148 u32 = NLA_DATA(nlattr);
2149 *u32 = tswap32(*u32);
2150 break;
2151 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002152 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002153 u32 = NLA_DATA(nlattr);
2154 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2155 i++) {
2156 u32[i] = tswap32(u32[i]);
2157 }
2158 break;
2159 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002160 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002161 ci = NLA_DATA(nlattr);
2162 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2163 ci->tstamp = tswap32(ci->tstamp);
2164 ci->reachable_time = tswap32(ci->reachable_time);
2165 ci->retrans_time = tswap32(ci->retrans_time);
2166 break;
2167 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002168 case QEMU_IFLA_INET6_STATS:
2169 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002170 u64 = NLA_DATA(nlattr);
2171 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2172 i++) {
2173 u64[i] = tswap64(u64[i]);
2174 }
2175 break;
2176 default:
2177 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2178 }
2179 return 0;
2180}
2181
2182static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2183 void *context)
2184{
2185 switch (nlattr->nla_type) {
2186 case AF_INET:
2187 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2188 NULL,
2189 host_to_target_data_inet_nlattr);
2190 case AF_INET6:
2191 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2192 NULL,
2193 host_to_target_data_inet6_nlattr);
2194 default:
2195 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2196 break;
2197 }
2198 return 0;
2199}
2200
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002201static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2202{
2203 uint32_t *u32;
2204 struct rtnl_link_stats *st;
2205 struct rtnl_link_stats64 *st64;
2206 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002207 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002208
2209 switch (rtattr->rta_type) {
2210 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002211 case QEMU_IFLA_ADDRESS:
2212 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002213 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002214 case QEMU_IFLA_IFNAME:
2215 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002216 break;
2217 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002218 case QEMU_IFLA_OPERSTATE:
2219 case QEMU_IFLA_LINKMODE:
2220 case QEMU_IFLA_CARRIER:
2221 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002222 break;
2223 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002224 case QEMU_IFLA_MTU:
2225 case QEMU_IFLA_LINK:
2226 case QEMU_IFLA_WEIGHT:
2227 case QEMU_IFLA_TXQLEN:
2228 case QEMU_IFLA_CARRIER_CHANGES:
2229 case QEMU_IFLA_NUM_RX_QUEUES:
2230 case QEMU_IFLA_NUM_TX_QUEUES:
2231 case QEMU_IFLA_PROMISCUITY:
2232 case QEMU_IFLA_EXT_MASK:
2233 case QEMU_IFLA_LINK_NETNSID:
2234 case QEMU_IFLA_GROUP:
2235 case QEMU_IFLA_MASTER:
2236 case QEMU_IFLA_NUM_VF:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002237 u32 = RTA_DATA(rtattr);
2238 *u32 = tswap32(*u32);
2239 break;
2240 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002241 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002242 st = RTA_DATA(rtattr);
2243 st->rx_packets = tswap32(st->rx_packets);
2244 st->tx_packets = tswap32(st->tx_packets);
2245 st->rx_bytes = tswap32(st->rx_bytes);
2246 st->tx_bytes = tswap32(st->tx_bytes);
2247 st->rx_errors = tswap32(st->rx_errors);
2248 st->tx_errors = tswap32(st->tx_errors);
2249 st->rx_dropped = tswap32(st->rx_dropped);
2250 st->tx_dropped = tswap32(st->tx_dropped);
2251 st->multicast = tswap32(st->multicast);
2252 st->collisions = tswap32(st->collisions);
2253
2254 /* detailed rx_errors: */
2255 st->rx_length_errors = tswap32(st->rx_length_errors);
2256 st->rx_over_errors = tswap32(st->rx_over_errors);
2257 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2258 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2259 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2260 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2261
2262 /* detailed tx_errors */
2263 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2264 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2265 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2266 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2267 st->tx_window_errors = tswap32(st->tx_window_errors);
2268
2269 /* for cslip etc */
2270 st->rx_compressed = tswap32(st->rx_compressed);
2271 st->tx_compressed = tswap32(st->tx_compressed);
2272 break;
2273 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002274 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002275 st64 = RTA_DATA(rtattr);
2276 st64->rx_packets = tswap64(st64->rx_packets);
2277 st64->tx_packets = tswap64(st64->tx_packets);
2278 st64->rx_bytes = tswap64(st64->rx_bytes);
2279 st64->tx_bytes = tswap64(st64->tx_bytes);
2280 st64->rx_errors = tswap64(st64->rx_errors);
2281 st64->tx_errors = tswap64(st64->tx_errors);
2282 st64->rx_dropped = tswap64(st64->rx_dropped);
2283 st64->tx_dropped = tswap64(st64->tx_dropped);
2284 st64->multicast = tswap64(st64->multicast);
2285 st64->collisions = tswap64(st64->collisions);
2286
2287 /* detailed rx_errors: */
2288 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2289 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2290 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2291 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2292 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2293 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2294
2295 /* detailed tx_errors */
2296 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2297 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2298 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2299 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2300 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2301
2302 /* for cslip etc */
2303 st64->rx_compressed = tswap64(st64->rx_compressed);
2304 st64->tx_compressed = tswap64(st64->tx_compressed);
2305 break;
2306 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002307 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002308 map = RTA_DATA(rtattr);
2309 map->mem_start = tswap64(map->mem_start);
2310 map->mem_end = tswap64(map->mem_end);
2311 map->base_addr = tswap64(map->base_addr);
2312 map->irq = tswap16(map->irq);
2313 break;
2314 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002315 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002316 memset(&li_context, 0, sizeof(li_context));
2317 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2318 &li_context,
2319 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002320 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002321 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2322 NULL,
2323 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002324 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002325 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002326 break;
2327 }
2328 return 0;
2329}
2330
2331static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2332{
2333 uint32_t *u32;
2334 struct ifa_cacheinfo *ci;
2335
2336 switch (rtattr->rta_type) {
2337 /* binary: depends on family type */
2338 case IFA_ADDRESS:
2339 case IFA_LOCAL:
2340 break;
2341 /* string */
2342 case IFA_LABEL:
2343 break;
2344 /* u32 */
2345 case IFA_FLAGS:
2346 case IFA_BROADCAST:
2347 u32 = RTA_DATA(rtattr);
2348 *u32 = tswap32(*u32);
2349 break;
2350 /* struct ifa_cacheinfo */
2351 case IFA_CACHEINFO:
2352 ci = RTA_DATA(rtattr);
2353 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2354 ci->ifa_valid = tswap32(ci->ifa_valid);
2355 ci->cstamp = tswap32(ci->cstamp);
2356 ci->tstamp = tswap32(ci->tstamp);
2357 break;
2358 default:
2359 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2360 break;
2361 }
2362 return 0;
2363}
2364
2365static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2366{
2367 uint32_t *u32;
2368 switch (rtattr->rta_type) {
2369 /* binary: depends on family type */
2370 case RTA_GATEWAY:
2371 case RTA_DST:
2372 case RTA_PREFSRC:
2373 break;
2374 /* u32 */
2375 case RTA_PRIORITY:
2376 case RTA_TABLE:
2377 case RTA_OIF:
2378 u32 = RTA_DATA(rtattr);
2379 *u32 = tswap32(*u32);
2380 break;
2381 default:
2382 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2383 break;
2384 }
2385 return 0;
2386}
2387
2388static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2389 uint32_t rtattr_len)
2390{
2391 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2392 host_to_target_data_link_rtattr);
2393}
2394
2395static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2396 uint32_t rtattr_len)
2397{
2398 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2399 host_to_target_data_addr_rtattr);
2400}
2401
2402static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2403 uint32_t rtattr_len)
2404{
2405 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2406 host_to_target_data_route_rtattr);
2407}
2408
2409static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2410{
2411 uint32_t nlmsg_len;
2412 struct ifinfomsg *ifi;
2413 struct ifaddrmsg *ifa;
2414 struct rtmsg *rtm;
2415
2416 nlmsg_len = nlh->nlmsg_len;
2417 switch (nlh->nlmsg_type) {
2418 case RTM_NEWLINK:
2419 case RTM_DELLINK:
2420 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002421 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2422 ifi = NLMSG_DATA(nlh);
2423 ifi->ifi_type = tswap16(ifi->ifi_type);
2424 ifi->ifi_index = tswap32(ifi->ifi_index);
2425 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2426 ifi->ifi_change = tswap32(ifi->ifi_change);
2427 host_to_target_link_rtattr(IFLA_RTA(ifi),
2428 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2429 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002430 break;
2431 case RTM_NEWADDR:
2432 case RTM_DELADDR:
2433 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002434 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2435 ifa = NLMSG_DATA(nlh);
2436 ifa->ifa_index = tswap32(ifa->ifa_index);
2437 host_to_target_addr_rtattr(IFA_RTA(ifa),
2438 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2439 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002440 break;
2441 case RTM_NEWROUTE:
2442 case RTM_DELROUTE:
2443 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002444 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2445 rtm = NLMSG_DATA(nlh);
2446 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2447 host_to_target_route_rtattr(RTM_RTA(rtm),
2448 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2449 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002450 break;
2451 default:
2452 return -TARGET_EINVAL;
2453 }
2454 return 0;
2455}
2456
2457static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2458 size_t len)
2459{
2460 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2461}
2462
2463static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2464 size_t len,
2465 abi_long (*target_to_host_rtattr)
2466 (struct rtattr *))
2467{
2468 abi_long ret;
2469
2470 while (len >= sizeof(struct rtattr)) {
2471 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2472 tswap16(rtattr->rta_len) > len) {
2473 break;
2474 }
2475 rtattr->rta_len = tswap16(rtattr->rta_len);
2476 rtattr->rta_type = tswap16(rtattr->rta_type);
2477 ret = target_to_host_rtattr(rtattr);
2478 if (ret < 0) {
2479 return ret;
2480 }
2481 len -= RTA_ALIGN(rtattr->rta_len);
2482 rtattr = (struct rtattr *)(((char *)rtattr) +
2483 RTA_ALIGN(rtattr->rta_len));
2484 }
2485 return 0;
2486}
2487
2488static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2489{
2490 switch (rtattr->rta_type) {
2491 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002492 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002493 break;
2494 }
2495 return 0;
2496}
2497
2498static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2499{
2500 switch (rtattr->rta_type) {
2501 /* binary: depends on family type */
2502 case IFA_LOCAL:
2503 case IFA_ADDRESS:
2504 break;
2505 default:
2506 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2507 break;
2508 }
2509 return 0;
2510}
2511
2512static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2513{
2514 uint32_t *u32;
2515 switch (rtattr->rta_type) {
2516 /* binary: depends on family type */
2517 case RTA_DST:
2518 case RTA_SRC:
2519 case RTA_GATEWAY:
2520 break;
2521 /* u32 */
2522 case RTA_OIF:
2523 u32 = RTA_DATA(rtattr);
2524 *u32 = tswap32(*u32);
2525 break;
2526 default:
2527 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2528 break;
2529 }
2530 return 0;
2531}
2532
2533static void target_to_host_link_rtattr(struct rtattr *rtattr,
2534 uint32_t rtattr_len)
2535{
2536 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2537 target_to_host_data_link_rtattr);
2538}
2539
2540static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2541 uint32_t rtattr_len)
2542{
2543 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2544 target_to_host_data_addr_rtattr);
2545}
2546
2547static void target_to_host_route_rtattr(struct rtattr *rtattr,
2548 uint32_t rtattr_len)
2549{
2550 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2551 target_to_host_data_route_rtattr);
2552}
2553
2554static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2555{
2556 struct ifinfomsg *ifi;
2557 struct ifaddrmsg *ifa;
2558 struct rtmsg *rtm;
2559
2560 switch (nlh->nlmsg_type) {
2561 case RTM_GETLINK:
2562 break;
2563 case RTM_NEWLINK:
2564 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002565 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2566 ifi = NLMSG_DATA(nlh);
2567 ifi->ifi_type = tswap16(ifi->ifi_type);
2568 ifi->ifi_index = tswap32(ifi->ifi_index);
2569 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2570 ifi->ifi_change = tswap32(ifi->ifi_change);
2571 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2572 NLMSG_LENGTH(sizeof(*ifi)));
2573 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002574 break;
2575 case RTM_GETADDR:
2576 case RTM_NEWADDR:
2577 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002578 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2579 ifa = NLMSG_DATA(nlh);
2580 ifa->ifa_index = tswap32(ifa->ifa_index);
2581 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2582 NLMSG_LENGTH(sizeof(*ifa)));
2583 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002584 break;
2585 case RTM_GETROUTE:
2586 break;
2587 case RTM_NEWROUTE:
2588 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002589 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2590 rtm = NLMSG_DATA(nlh);
2591 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2592 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2593 NLMSG_LENGTH(sizeof(*rtm)));
2594 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002595 break;
2596 default:
2597 return -TARGET_EOPNOTSUPP;
2598 }
2599 return 0;
2600}
2601
2602static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2603{
2604 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2605}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002606#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002607
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002608static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2609{
2610 switch (nlh->nlmsg_type) {
2611 default:
2612 gemu_log("Unknown host audit message type %d\n",
2613 nlh->nlmsg_type);
2614 return -TARGET_EINVAL;
2615 }
2616 return 0;
2617}
2618
2619static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2620 size_t len)
2621{
2622 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2623}
2624
2625static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2626{
2627 switch (nlh->nlmsg_type) {
2628 case AUDIT_USER:
2629 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2630 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2631 break;
2632 default:
2633 gemu_log("Unknown target audit message type %d\n",
2634 nlh->nlmsg_type);
2635 return -TARGET_EINVAL;
2636 }
2637
2638 return 0;
2639}
2640
2641static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2642{
2643 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2644}
2645
ths0da46a62007-10-20 20:23:07 +00002646/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002647static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002648 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002649{
blueswir1992f48a2007-10-14 16:27:31 +00002650 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002651 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002652 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002653 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002654
bellard8853f862004-02-22 14:57:26 +00002655 switch(level) {
2656 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002657 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002658 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002659 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002660
bellard2f619692007-11-16 10:46:05 +00002661 if (get_user_u32(val, optval_addr))
2662 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002663 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2664 break;
2665 case SOL_IP:
2666 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002667 case IP_TOS:
2668 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002669 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002670 case IP_ROUTER_ALERT:
2671 case IP_RECVOPTS:
2672 case IP_RETOPTS:
2673 case IP_PKTINFO:
2674 case IP_MTU_DISCOVER:
2675 case IP_RECVERR:
2676 case IP_RECVTOS:
2677#ifdef IP_FREEBIND
2678 case IP_FREEBIND:
2679#endif
2680 case IP_MULTICAST_TTL:
2681 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002682 val = 0;
2683 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002684 if (get_user_u32(val, optval_addr))
2685 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002686 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002687 if (get_user_u8(val, optval_addr))
2688 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002689 }
2690 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2691 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002692 case IP_ADD_MEMBERSHIP:
2693 case IP_DROP_MEMBERSHIP:
2694 if (optlen < sizeof (struct target_ip_mreq) ||
2695 optlen > sizeof (struct target_ip_mreqn))
2696 return -TARGET_EINVAL;
2697
2698 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2699 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2700 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2701 break;
2702
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002703 case IP_BLOCK_SOURCE:
2704 case IP_UNBLOCK_SOURCE:
2705 case IP_ADD_SOURCE_MEMBERSHIP:
2706 case IP_DROP_SOURCE_MEMBERSHIP:
2707 if (optlen != sizeof (struct target_ip_mreq_source))
2708 return -TARGET_EINVAL;
2709
2710 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2711 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2712 unlock_user (ip_mreq_source, optval_addr, 0);
2713 break;
2714
bellard8853f862004-02-22 14:57:26 +00002715 default:
2716 goto unimplemented;
2717 }
2718 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002719 case SOL_IPV6:
2720 switch (optname) {
2721 case IPV6_MTU_DISCOVER:
2722 case IPV6_MTU:
2723 case IPV6_V6ONLY:
2724 case IPV6_RECVPKTINFO:
2725 val = 0;
2726 if (optlen < sizeof(uint32_t)) {
2727 return -TARGET_EINVAL;
2728 }
2729 if (get_user_u32(val, optval_addr)) {
2730 return -TARGET_EFAULT;
2731 }
2732 ret = get_errno(setsockopt(sockfd, level, optname,
2733 &val, sizeof(val)));
2734 break;
2735 default:
2736 goto unimplemented;
2737 }
2738 break;
Jing Huang920394d2012-07-24 13:59:23 +00002739 case SOL_RAW:
2740 switch (optname) {
2741 case ICMP_FILTER:
2742 /* struct icmp_filter takes an u32 value */
2743 if (optlen < sizeof(uint32_t)) {
2744 return -TARGET_EINVAL;
2745 }
2746
2747 if (get_user_u32(val, optval_addr)) {
2748 return -TARGET_EFAULT;
2749 }
2750 ret = get_errno(setsockopt(sockfd, level, optname,
2751 &val, sizeof(val)));
2752 break;
2753
2754 default:
2755 goto unimplemented;
2756 }
2757 break;
bellard3532fa72006-06-24 15:06:03 +00002758 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002759 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002760 case TARGET_SO_RCVTIMEO:
2761 {
2762 struct timeval tv;
2763
2764 optname = SO_RCVTIMEO;
2765
2766set_timeout:
2767 if (optlen != sizeof(struct target_timeval)) {
2768 return -TARGET_EINVAL;
2769 }
2770
2771 if (copy_from_user_timeval(&tv, optval_addr)) {
2772 return -TARGET_EFAULT;
2773 }
2774
2775 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2776 &tv, sizeof(tv)));
2777 return ret;
2778 }
2779 case TARGET_SO_SNDTIMEO:
2780 optname = SO_SNDTIMEO;
2781 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002782 case TARGET_SO_ATTACH_FILTER:
2783 {
2784 struct target_sock_fprog *tfprog;
2785 struct target_sock_filter *tfilter;
2786 struct sock_fprog fprog;
2787 struct sock_filter *filter;
2788 int i;
2789
2790 if (optlen != sizeof(*tfprog)) {
2791 return -TARGET_EINVAL;
2792 }
2793 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2794 return -TARGET_EFAULT;
2795 }
2796 if (!lock_user_struct(VERIFY_READ, tfilter,
2797 tswapal(tfprog->filter), 0)) {
2798 unlock_user_struct(tfprog, optval_addr, 1);
2799 return -TARGET_EFAULT;
2800 }
2801
2802 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302803 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002804 if (filter == NULL) {
2805 unlock_user_struct(tfilter, tfprog->filter, 1);
2806 unlock_user_struct(tfprog, optval_addr, 1);
2807 return -TARGET_ENOMEM;
2808 }
2809 for (i = 0; i < fprog.len; i++) {
2810 filter[i].code = tswap16(tfilter[i].code);
2811 filter[i].jt = tfilter[i].jt;
2812 filter[i].jf = tfilter[i].jf;
2813 filter[i].k = tswap32(tfilter[i].k);
2814 }
2815 fprog.filter = filter;
2816
2817 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2818 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302819 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002820
2821 unlock_user_struct(tfilter, tfprog->filter, 1);
2822 unlock_user_struct(tfprog, optval_addr, 1);
2823 return ret;
2824 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002825 case TARGET_SO_BINDTODEVICE:
2826 {
2827 char *dev_ifname, *addr_ifname;
2828
2829 if (optlen > IFNAMSIZ - 1) {
2830 optlen = IFNAMSIZ - 1;
2831 }
2832 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2833 if (!dev_ifname) {
2834 return -TARGET_EFAULT;
2835 }
2836 optname = SO_BINDTODEVICE;
2837 addr_ifname = alloca(IFNAMSIZ);
2838 memcpy(addr_ifname, dev_ifname, optlen);
2839 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002840 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2841 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002842 unlock_user (dev_ifname, optval_addr, 0);
2843 return ret;
2844 }
bellard8853f862004-02-22 14:57:26 +00002845 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002846 case TARGET_SO_DEBUG:
2847 optname = SO_DEBUG;
2848 break;
2849 case TARGET_SO_REUSEADDR:
2850 optname = SO_REUSEADDR;
2851 break;
2852 case TARGET_SO_TYPE:
2853 optname = SO_TYPE;
2854 break;
2855 case TARGET_SO_ERROR:
2856 optname = SO_ERROR;
2857 break;
2858 case TARGET_SO_DONTROUTE:
2859 optname = SO_DONTROUTE;
2860 break;
2861 case TARGET_SO_BROADCAST:
2862 optname = SO_BROADCAST;
2863 break;
2864 case TARGET_SO_SNDBUF:
2865 optname = SO_SNDBUF;
2866 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002867 case TARGET_SO_SNDBUFFORCE:
2868 optname = SO_SNDBUFFORCE;
2869 break;
bellard3532fa72006-06-24 15:06:03 +00002870 case TARGET_SO_RCVBUF:
2871 optname = SO_RCVBUF;
2872 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002873 case TARGET_SO_RCVBUFFORCE:
2874 optname = SO_RCVBUFFORCE;
2875 break;
bellard3532fa72006-06-24 15:06:03 +00002876 case TARGET_SO_KEEPALIVE:
2877 optname = SO_KEEPALIVE;
2878 break;
2879 case TARGET_SO_OOBINLINE:
2880 optname = SO_OOBINLINE;
2881 break;
2882 case TARGET_SO_NO_CHECK:
2883 optname = SO_NO_CHECK;
2884 break;
2885 case TARGET_SO_PRIORITY:
2886 optname = SO_PRIORITY;
2887 break;
bellard5e83e8e2005-03-01 22:32:06 +00002888#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002889 case TARGET_SO_BSDCOMPAT:
2890 optname = SO_BSDCOMPAT;
2891 break;
bellard5e83e8e2005-03-01 22:32:06 +00002892#endif
bellard3532fa72006-06-24 15:06:03 +00002893 case TARGET_SO_PASSCRED:
2894 optname = SO_PASSCRED;
2895 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002896 case TARGET_SO_PASSSEC:
2897 optname = SO_PASSSEC;
2898 break;
bellard3532fa72006-06-24 15:06:03 +00002899 case TARGET_SO_TIMESTAMP:
2900 optname = SO_TIMESTAMP;
2901 break;
2902 case TARGET_SO_RCVLOWAT:
2903 optname = SO_RCVLOWAT;
2904 break;
bellard8853f862004-02-22 14:57:26 +00002905 break;
2906 default:
2907 goto unimplemented;
2908 }
bellard3532fa72006-06-24 15:06:03 +00002909 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002910 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002911
bellard2f619692007-11-16 10:46:05 +00002912 if (get_user_u32(val, optval_addr))
2913 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002914 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002915 break;
bellard7854b052003-03-29 17:22:23 +00002916 default:
bellard8853f862004-02-22 14:57:26 +00002917 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002918 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002919 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002920 }
bellard8853f862004-02-22 14:57:26 +00002921 return ret;
bellard7854b052003-03-29 17:22:23 +00002922}
2923
ths0da46a62007-10-20 20:23:07 +00002924/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002925static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002926 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002927{
blueswir1992f48a2007-10-14 16:27:31 +00002928 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002929 int len, val;
2930 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002931
2932 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002933 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002934 level = SOL_SOCKET;
2935 switch (optname) {
2936 /* These don't just return a single integer */
2937 case TARGET_SO_LINGER:
2938 case TARGET_SO_RCVTIMEO:
2939 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002940 case TARGET_SO_PEERNAME:
2941 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002942 case TARGET_SO_PEERCRED: {
2943 struct ucred cr;
2944 socklen_t crlen;
2945 struct target_ucred *tcr;
2946
2947 if (get_user_u32(len, optlen)) {
2948 return -TARGET_EFAULT;
2949 }
2950 if (len < 0) {
2951 return -TARGET_EINVAL;
2952 }
2953
2954 crlen = sizeof(cr);
2955 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2956 &cr, &crlen));
2957 if (ret < 0) {
2958 return ret;
2959 }
2960 if (len > crlen) {
2961 len = crlen;
2962 }
2963 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2964 return -TARGET_EFAULT;
2965 }
2966 __put_user(cr.pid, &tcr->pid);
2967 __put_user(cr.uid, &tcr->uid);
2968 __put_user(cr.gid, &tcr->gid);
2969 unlock_user_struct(tcr, optval_addr, 1);
2970 if (put_user_u32(len, optlen)) {
2971 return -TARGET_EFAULT;
2972 }
2973 break;
2974 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002975 /* Options with 'int' argument. */
2976 case TARGET_SO_DEBUG:
2977 optname = SO_DEBUG;
2978 goto int_case;
2979 case TARGET_SO_REUSEADDR:
2980 optname = SO_REUSEADDR;
2981 goto int_case;
2982 case TARGET_SO_TYPE:
2983 optname = SO_TYPE;
2984 goto int_case;
2985 case TARGET_SO_ERROR:
2986 optname = SO_ERROR;
2987 goto int_case;
2988 case TARGET_SO_DONTROUTE:
2989 optname = SO_DONTROUTE;
2990 goto int_case;
2991 case TARGET_SO_BROADCAST:
2992 optname = SO_BROADCAST;
2993 goto int_case;
2994 case TARGET_SO_SNDBUF:
2995 optname = SO_SNDBUF;
2996 goto int_case;
2997 case TARGET_SO_RCVBUF:
2998 optname = SO_RCVBUF;
2999 goto int_case;
3000 case TARGET_SO_KEEPALIVE:
3001 optname = SO_KEEPALIVE;
3002 goto int_case;
3003 case TARGET_SO_OOBINLINE:
3004 optname = SO_OOBINLINE;
3005 goto int_case;
3006 case TARGET_SO_NO_CHECK:
3007 optname = SO_NO_CHECK;
3008 goto int_case;
3009 case TARGET_SO_PRIORITY:
3010 optname = SO_PRIORITY;
3011 goto int_case;
3012#ifdef SO_BSDCOMPAT
3013 case TARGET_SO_BSDCOMPAT:
3014 optname = SO_BSDCOMPAT;
3015 goto int_case;
3016#endif
3017 case TARGET_SO_PASSCRED:
3018 optname = SO_PASSCRED;
3019 goto int_case;
3020 case TARGET_SO_TIMESTAMP:
3021 optname = SO_TIMESTAMP;
3022 goto int_case;
3023 case TARGET_SO_RCVLOWAT:
3024 optname = SO_RCVLOWAT;
3025 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003026 case TARGET_SO_ACCEPTCONN:
3027 optname = SO_ACCEPTCONN;
3028 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003029 default:
bellard2efbe912005-07-23 15:10:20 +00003030 goto int_case;
3031 }
3032 break;
3033 case SOL_TCP:
3034 /* TCP options all take an 'int' value. */
3035 int_case:
bellard2f619692007-11-16 10:46:05 +00003036 if (get_user_u32(len, optlen))
3037 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003038 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003039 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003040 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003041 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3042 if (ret < 0)
3043 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003044 if (optname == SO_TYPE) {
3045 val = host_to_target_sock_type(val);
3046 }
bellard2efbe912005-07-23 15:10:20 +00003047 if (len > lv)
3048 len = lv;
bellard2f619692007-11-16 10:46:05 +00003049 if (len == 4) {
3050 if (put_user_u32(val, optval_addr))
3051 return -TARGET_EFAULT;
3052 } else {
3053 if (put_user_u8(val, optval_addr))
3054 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003055 }
bellard2f619692007-11-16 10:46:05 +00003056 if (put_user_u32(len, optlen))
3057 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003058 break;
3059 case SOL_IP:
3060 switch(optname) {
3061 case IP_TOS:
3062 case IP_TTL:
3063 case IP_HDRINCL:
3064 case IP_ROUTER_ALERT:
3065 case IP_RECVOPTS:
3066 case IP_RETOPTS:
3067 case IP_PKTINFO:
3068 case IP_MTU_DISCOVER:
3069 case IP_RECVERR:
3070 case IP_RECVTOS:
3071#ifdef IP_FREEBIND
3072 case IP_FREEBIND:
3073#endif
3074 case IP_MULTICAST_TTL:
3075 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003076 if (get_user_u32(len, optlen))
3077 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003078 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003079 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003080 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003081 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3082 if (ret < 0)
3083 return ret;
bellard2efbe912005-07-23 15:10:20 +00003084 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003085 len = 1;
bellard2f619692007-11-16 10:46:05 +00003086 if (put_user_u32(len, optlen)
3087 || put_user_u8(val, optval_addr))
3088 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003089 } else {
bellard2efbe912005-07-23 15:10:20 +00003090 if (len > sizeof(int))
3091 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003092 if (put_user_u32(len, optlen)
3093 || put_user_u32(val, optval_addr))
3094 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003095 }
bellard8853f862004-02-22 14:57:26 +00003096 break;
bellard2efbe912005-07-23 15:10:20 +00003097 default:
thsc02f4992007-12-18 02:39:59 +00003098 ret = -TARGET_ENOPROTOOPT;
3099 break;
bellard8853f862004-02-22 14:57:26 +00003100 }
3101 break;
3102 default:
3103 unimplemented:
3104 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3105 level, optname);
thsc02f4992007-12-18 02:39:59 +00003106 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003107 break;
3108 }
3109 return ret;
bellard7854b052003-03-29 17:22:23 +00003110}
3111
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003112static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003113 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003114{
3115 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003116 struct iovec *vec;
3117 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003118 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003119 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003120 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003121
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003122 if (count == 0) {
3123 errno = 0;
3124 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003125 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003126 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003127 errno = EINVAL;
3128 return NULL;
3129 }
3130
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303131 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003132 if (vec == NULL) {
3133 errno = ENOMEM;
3134 return NULL;
3135 }
3136
3137 target_vec = lock_user(VERIFY_READ, target_addr,
3138 count * sizeof(struct target_iovec), 1);
3139 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003140 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003141 goto fail2;
3142 }
3143
3144 /* ??? If host page size > target page size, this will result in a
3145 value larger than what we can actually support. */
3146 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3147 total_len = 0;
3148
3149 for (i = 0; i < count; i++) {
3150 abi_ulong base = tswapal(target_vec[i].iov_base);
3151 abi_long len = tswapal(target_vec[i].iov_len);
3152
3153 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003154 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003155 goto fail;
3156 } else if (len == 0) {
3157 /* Zero length pointer is ignored. */
3158 vec[i].iov_base = 0;
3159 } else {
3160 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003161 /* If the first buffer pointer is bad, this is a fault. But
3162 * subsequent bad buffers will result in a partial write; this
3163 * is realized by filling the vector with null pointers and
3164 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003165 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003166 if (i == 0) {
3167 err = EFAULT;
3168 goto fail;
3169 } else {
3170 bad_address = true;
3171 }
3172 }
3173 if (bad_address) {
3174 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003175 }
3176 if (len > max_len - total_len) {
3177 len = max_len - total_len;
3178 }
3179 }
3180 vec[i].iov_len = len;
3181 total_len += len;
3182 }
3183
3184 unlock_user(target_vec, target_addr, 0);
3185 return vec;
3186
3187 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003188 while (--i >= 0) {
3189 if (tswapal(target_vec[i].iov_len) > 0) {
3190 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3191 }
3192 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003193 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003194 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303195 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003196 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003197 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003198}
3199
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003200static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003201 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003202{
3203 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003204 int i;
3205
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003206 target_vec = lock_user(VERIFY_READ, target_addr,
3207 count * sizeof(struct target_iovec), 1);
3208 if (target_vec) {
3209 for (i = 0; i < count; i++) {
3210 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003211 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003212 if (len < 0) {
3213 break;
3214 }
balrogd732dcb2008-10-28 10:21:03 +00003215 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3216 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003217 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003218 }
bellard579a97f2007-11-11 14:26:47 +00003219
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303220 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003221}
3222
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003223static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003224{
3225 int host_type = 0;
3226 int target_type = *type;
3227
3228 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3229 case TARGET_SOCK_DGRAM:
3230 host_type = SOCK_DGRAM;
3231 break;
3232 case TARGET_SOCK_STREAM:
3233 host_type = SOCK_STREAM;
3234 break;
3235 default:
3236 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3237 break;
3238 }
3239 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003240#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003241 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003242#else
3243 return -TARGET_EINVAL;
3244#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003245 }
3246 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003247#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003248 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003249#elif !defined(O_NONBLOCK)
3250 return -TARGET_EINVAL;
3251#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003252 }
3253 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003254 return 0;
3255}
3256
3257/* Try to emulate socket type flags after socket creation. */
3258static int sock_flags_fixup(int fd, int target_type)
3259{
3260#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3261 if (target_type & TARGET_SOCK_NONBLOCK) {
3262 int flags = fcntl(fd, F_GETFL);
3263 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3264 close(fd);
3265 return -TARGET_EINVAL;
3266 }
3267 }
3268#endif
3269 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003270}
3271
Laurent Vivier0cf22722015-10-28 21:40:45 +01003272static abi_long packet_target_to_host_sockaddr(void *host_addr,
3273 abi_ulong target_addr,
3274 socklen_t len)
3275{
3276 struct sockaddr *addr = host_addr;
3277 struct target_sockaddr *target_saddr;
3278
3279 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3280 if (!target_saddr) {
3281 return -TARGET_EFAULT;
3282 }
3283
3284 memcpy(addr, target_saddr, len);
3285 addr->sa_family = tswap16(target_saddr->sa_family);
3286 /* spkt_protocol is big-endian */
3287
3288 unlock_user(target_saddr, target_addr, 0);
3289 return 0;
3290}
3291
3292static TargetFdTrans target_packet_trans = {
3293 .target_to_host_addr = packet_target_to_host_sockaddr,
3294};
3295
Laurent Vivier575b22b2016-06-02 22:14:15 +02003296#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003297static abi_long netlink_route_target_to_host(void *buf, size_t len)
3298{
Laurent Vivieref759f62016-06-21 19:51:13 +02003299 abi_long ret;
3300
3301 ret = target_to_host_nlmsg_route(buf, len);
3302 if (ret < 0) {
3303 return ret;
3304 }
3305
3306 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003307}
3308
3309static abi_long netlink_route_host_to_target(void *buf, size_t len)
3310{
Laurent Vivieref759f62016-06-21 19:51:13 +02003311 abi_long ret;
3312
3313 ret = host_to_target_nlmsg_route(buf, len);
3314 if (ret < 0) {
3315 return ret;
3316 }
3317
3318 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003319}
3320
3321static TargetFdTrans target_netlink_route_trans = {
3322 .target_to_host_data = netlink_route_target_to_host,
3323 .host_to_target_data = netlink_route_host_to_target,
3324};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003325#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003326
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003327static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3328{
Laurent Vivieref759f62016-06-21 19:51:13 +02003329 abi_long ret;
3330
3331 ret = target_to_host_nlmsg_audit(buf, len);
3332 if (ret < 0) {
3333 return ret;
3334 }
3335
3336 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003337}
3338
3339static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3340{
Laurent Vivieref759f62016-06-21 19:51:13 +02003341 abi_long ret;
3342
3343 ret = host_to_target_nlmsg_audit(buf, len);
3344 if (ret < 0) {
3345 return ret;
3346 }
3347
3348 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003349}
3350
3351static TargetFdTrans target_netlink_audit_trans = {
3352 .target_to_host_data = netlink_audit_target_to_host,
3353 .host_to_target_data = netlink_audit_host_to_target,
3354};
3355
ths0da46a62007-10-20 20:23:07 +00003356/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003357static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003358{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003359 int target_type = type;
3360 int ret;
3361
3362 ret = target_to_host_sock_type(&type);
3363 if (ret) {
3364 return ret;
3365 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003366
Laurent Vivier575b22b2016-06-02 22:14:15 +02003367 if (domain == PF_NETLINK && !(
3368#ifdef CONFIG_RTNETLINK
3369 protocol == NETLINK_ROUTE ||
3370#endif
3371 protocol == NETLINK_KOBJECT_UEVENT ||
3372 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003373 return -EPFNOSUPPORT;
3374 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003375
3376 if (domain == AF_PACKET ||
3377 (domain == AF_INET && type == SOCK_PACKET)) {
3378 protocol = tswap16(protocol);
3379 }
3380
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003381 ret = get_errno(socket(domain, type, protocol));
3382 if (ret >= 0) {
3383 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003384 if (type == SOCK_PACKET) {
3385 /* Manage an obsolete case :
3386 * if socket type is SOCK_PACKET, bind by name
3387 */
3388 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003389 } else if (domain == PF_NETLINK) {
3390 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003391#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003392 case NETLINK_ROUTE:
3393 fd_trans_register(ret, &target_netlink_route_trans);
3394 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003395#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003396 case NETLINK_KOBJECT_UEVENT:
3397 /* nothing to do: messages are strings */
3398 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003399 case NETLINK_AUDIT:
3400 fd_trans_register(ret, &target_netlink_audit_trans);
3401 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003402 default:
3403 g_assert_not_reached();
3404 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003405 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003406 }
3407 return ret;
bellard3532fa72006-06-24 15:06:03 +00003408}
3409
ths0da46a62007-10-20 20:23:07 +00003410/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003411static abi_long do_bind(int sockfd, abi_ulong target_addr,
3412 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003413{
aurel328f7aeaf2009-01-30 19:47:57 +00003414 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003415 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003416
Blue Swirl38724252010-09-18 05:53:14 +00003417 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003418 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003419 }
aurel328f7aeaf2009-01-30 19:47:57 +00003420
aurel32607175e2009-04-15 16:11:59 +00003421 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003422
Laurent Vivier7b36f782015-10-28 21:40:44 +01003423 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003424 if (ret)
3425 return ret;
3426
bellard3532fa72006-06-24 15:06:03 +00003427 return get_errno(bind(sockfd, addr, addrlen));
3428}
3429
ths0da46a62007-10-20 20:23:07 +00003430/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003431static abi_long do_connect(int sockfd, abi_ulong target_addr,
3432 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003433{
aurel328f7aeaf2009-01-30 19:47:57 +00003434 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003435 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003436
Blue Swirl38724252010-09-18 05:53:14 +00003437 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003438 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003439 }
aurel328f7aeaf2009-01-30 19:47:57 +00003440
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003441 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003442
Laurent Vivier7b36f782015-10-28 21:40:44 +01003443 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003444 if (ret)
3445 return ret;
3446
Peter Maydell2a3c7612016-06-06 19:58:03 +01003447 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003448}
3449
Alexander Graff19e00d2014-03-02 19:36:42 +00003450/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3451static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3452 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003453{
balrog6de645c2008-10-28 10:26:29 +00003454 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003455 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003456 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003457 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003458 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003459
bellard3532fa72006-06-24 15:06:03 +00003460 if (msgp->msg_name) {
3461 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003462 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003463 ret = target_to_host_sockaddr(fd, msg.msg_name,
3464 tswapal(msgp->msg_name),
3465 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003466 if (ret == -TARGET_EFAULT) {
3467 /* For connected sockets msg_name and msg_namelen must
3468 * be ignored, so returning EFAULT immediately is wrong.
3469 * Instead, pass a bad msg_name to the host kernel, and
3470 * let it decide whether to return EFAULT or not.
3471 */
3472 msg.msg_name = (void *)-1;
3473 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003474 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003475 }
bellard3532fa72006-06-24 15:06:03 +00003476 } else {
3477 msg.msg_name = NULL;
3478 msg.msg_namelen = 0;
3479 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003480 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003481 msg.msg_control = alloca(msg.msg_controllen);
3482 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003483
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003484 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003485 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003486
3487 if (count > IOV_MAX) {
3488 /* sendrcvmsg returns a different errno for this condition than
3489 * readv/writev, so we must catch it here before lock_iovec() does.
3490 */
3491 ret = -TARGET_EMSGSIZE;
3492 goto out2;
3493 }
3494
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003495 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3496 target_vec, count, send);
3497 if (vec == NULL) {
3498 ret = -host_to_target_errno(errno);
3499 goto out2;
3500 }
bellard3532fa72006-06-24 15:06:03 +00003501 msg.msg_iovlen = count;
3502 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003503
bellard3532fa72006-06-24 15:06:03 +00003504 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003505 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003506 void *host_msg;
3507
3508 host_msg = g_malloc(msg.msg_iov->iov_len);
3509 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3510 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003511 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003512 if (ret >= 0) {
3513 msg.msg_iov->iov_base = host_msg;
3514 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3515 }
3516 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003517 } else {
3518 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003519 if (ret == 0) {
3520 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3521 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003522 }
bellard3532fa72006-06-24 15:06:03 +00003523 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003524 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003525 if (!is_error(ret)) {
3526 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003527 if (fd_trans_host_to_target_data(fd)) {
3528 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003529 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003530 } else {
3531 ret = host_to_target_cmsg(msgp, &msg);
3532 }
Jing Huangca619062012-07-24 13:58:02 +00003533 if (!is_error(ret)) {
3534 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003535 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003536 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3537 msg.msg_name, msg.msg_namelen);
3538 if (ret) {
3539 goto out;
3540 }
3541 }
3542
balrog6de645c2008-10-28 10:26:29 +00003543 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003544 }
balrog6de645c2008-10-28 10:26:29 +00003545 }
bellard3532fa72006-06-24 15:06:03 +00003546 }
Jing Huangca619062012-07-24 13:58:02 +00003547
3548out:
bellard3532fa72006-06-24 15:06:03 +00003549 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003550out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003551 return ret;
3552}
3553
3554static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3555 int flags, int send)
3556{
3557 abi_long ret;
3558 struct target_msghdr *msgp;
3559
3560 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3561 msgp,
3562 target_msg,
3563 send ? 1 : 0)) {
3564 return -TARGET_EFAULT;
3565 }
3566 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003567 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003568 return ret;
3569}
3570
Alexander Graff19e00d2014-03-02 19:36:42 +00003571/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3572 * so it might not have this *mmsg-specific flag either.
3573 */
3574#ifndef MSG_WAITFORONE
3575#define MSG_WAITFORONE 0x10000
3576#endif
3577
3578static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3579 unsigned int vlen, unsigned int flags,
3580 int send)
3581{
3582 struct target_mmsghdr *mmsgp;
3583 abi_long ret = 0;
3584 int i;
3585
3586 if (vlen > UIO_MAXIOV) {
3587 vlen = UIO_MAXIOV;
3588 }
3589
3590 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3591 if (!mmsgp) {
3592 return -TARGET_EFAULT;
3593 }
3594
3595 for (i = 0; i < vlen; i++) {
3596 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3597 if (is_error(ret)) {
3598 break;
3599 }
3600 mmsgp[i].msg_len = tswap32(ret);
3601 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3602 if (flags & MSG_WAITFORONE) {
3603 flags |= MSG_DONTWAIT;
3604 }
3605 }
3606
3607 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3608
3609 /* Return number of datagrams sent if we sent any at all;
3610 * otherwise return the error.
3611 */
3612 if (i) {
3613 return i;
3614 }
3615 return ret;
3616}
Alexander Graff19e00d2014-03-02 19:36:42 +00003617
Peter Maydella94b4982013-02-08 04:35:04 +00003618/* do_accept4() Must return target values and target errnos. */
3619static abi_long do_accept4(int fd, abi_ulong target_addr,
3620 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003621{
bellard2f619692007-11-16 10:46:05 +00003622 socklen_t addrlen;
3623 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003624 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003625 int host_flags;
3626
3627 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003628
Peter Maydella94b4982013-02-08 04:35:04 +00003629 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003630 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003631 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003632
3633 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003634 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003635 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003636
Blue Swirl38724252010-09-18 05:53:14 +00003637 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003638 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003639 }
aurel328f7aeaf2009-01-30 19:47:57 +00003640
Arnaud Patard917507b2009-06-19 10:44:45 +03003641 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3642 return -TARGET_EINVAL;
3643
bellard2f619692007-11-16 10:46:05 +00003644 addr = alloca(addrlen);
3645
Peter Maydellff6dc132016-06-06 19:58:13 +01003646 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003647 if (!is_error(ret)) {
3648 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003649 if (put_user_u32(addrlen, target_addrlen_addr))
3650 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003651 }
3652 return ret;
3653}
3654
ths0da46a62007-10-20 20:23:07 +00003655/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003656static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003657 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003658{
bellard2f619692007-11-16 10:46:05 +00003659 socklen_t addrlen;
3660 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003661 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003662
bellard2f619692007-11-16 10:46:05 +00003663 if (get_user_u32(addrlen, target_addrlen_addr))
3664 return -TARGET_EFAULT;
3665
Blue Swirl38724252010-09-18 05:53:14 +00003666 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003667 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003668 }
aurel328f7aeaf2009-01-30 19:47:57 +00003669
Arnaud Patard917507b2009-06-19 10:44:45 +03003670 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3671 return -TARGET_EFAULT;
3672
bellard2f619692007-11-16 10:46:05 +00003673 addr = alloca(addrlen);
3674
pbrook1be9e1d2006-11-19 15:26:04 +00003675 ret = get_errno(getpeername(fd, addr, &addrlen));
3676 if (!is_error(ret)) {
3677 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003678 if (put_user_u32(addrlen, target_addrlen_addr))
3679 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003680 }
3681 return ret;
3682}
3683
ths0da46a62007-10-20 20:23:07 +00003684/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003685static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003686 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003687{
bellard2f619692007-11-16 10:46:05 +00003688 socklen_t addrlen;
3689 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003690 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003691
bellard2f619692007-11-16 10:46:05 +00003692 if (get_user_u32(addrlen, target_addrlen_addr))
3693 return -TARGET_EFAULT;
3694
Blue Swirl38724252010-09-18 05:53:14 +00003695 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003696 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003697 }
aurel328f7aeaf2009-01-30 19:47:57 +00003698
Arnaud Patard917507b2009-06-19 10:44:45 +03003699 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3700 return -TARGET_EFAULT;
3701
bellard2f619692007-11-16 10:46:05 +00003702 addr = alloca(addrlen);
3703
pbrook1be9e1d2006-11-19 15:26:04 +00003704 ret = get_errno(getsockname(fd, addr, &addrlen));
3705 if (!is_error(ret)) {
3706 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003707 if (put_user_u32(addrlen, target_addrlen_addr))
3708 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003709 }
3710 return ret;
3711}
3712
ths0da46a62007-10-20 20:23:07 +00003713/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003714static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003715 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003716{
3717 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003718 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003719
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003720 target_to_host_sock_type(&type);
3721
pbrook1be9e1d2006-11-19 15:26:04 +00003722 ret = get_errno(socketpair(domain, type, protocol, tab));
3723 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003724 if (put_user_s32(tab[0], target_tab_addr)
3725 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3726 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003727 }
3728 return ret;
3729}
3730
ths0da46a62007-10-20 20:23:07 +00003731/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003732static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3733 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003734{
3735 void *addr;
3736 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003737 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003738 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003739
Blue Swirl38724252010-09-18 05:53:14 +00003740 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003741 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003742 }
aurel328f7aeaf2009-01-30 19:47:57 +00003743
bellard579a97f2007-11-11 14:26:47 +00003744 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3745 if (!host_msg)
3746 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003747 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003748 copy_msg = host_msg;
3749 host_msg = g_malloc(len);
3750 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003751 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3752 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003753 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003754 }
3755 }
pbrook1be9e1d2006-11-19 15:26:04 +00003756 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003757 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003758 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003759 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003760 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003761 }
Peter Maydell66687532016-06-06 19:58:04 +01003762 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003763 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003764 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003765 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003766fail:
3767 if (copy_msg) {
3768 g_free(host_msg);
3769 host_msg = copy_msg;
3770 }
pbrook1be9e1d2006-11-19 15:26:04 +00003771 unlock_user(host_msg, msg, 0);
3772 return ret;
3773}
3774
ths0da46a62007-10-20 20:23:07 +00003775/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003776static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3777 abi_ulong target_addr,
3778 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003779{
3780 socklen_t addrlen;
3781 void *addr;
3782 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003783 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003784
bellard579a97f2007-11-11 14:26:47 +00003785 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3786 if (!host_msg)
3787 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003788 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003789 if (get_user_u32(addrlen, target_addrlen)) {
3790 ret = -TARGET_EFAULT;
3791 goto fail;
3792 }
Blue Swirl38724252010-09-18 05:53:14 +00003793 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003794 ret = -TARGET_EINVAL;
3795 goto fail;
3796 }
pbrook1be9e1d2006-11-19 15:26:04 +00003797 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003798 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3799 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003800 } else {
3801 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003802 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003803 }
3804 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003805 if (fd_trans_host_to_target_data(fd)) {
3806 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
3807 }
pbrook1be9e1d2006-11-19 15:26:04 +00003808 if (target_addr) {
3809 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003810 if (put_user_u32(addrlen, target_addrlen)) {
3811 ret = -TARGET_EFAULT;
3812 goto fail;
3813 }
pbrook1be9e1d2006-11-19 15:26:04 +00003814 }
3815 unlock_user(host_msg, msg, len);
3816 } else {
bellard2f619692007-11-16 10:46:05 +00003817fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003818 unlock_user(host_msg, msg, 0);
3819 }
3820 return ret;
3821}
3822
j_mayer32407102007-09-26 23:01:49 +00003823#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003824/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003825static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003826{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003827 static const unsigned ac[] = { /* number of arguments per call */
3828 [SOCKOP_socket] = 3, /* domain, type, protocol */
3829 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3830 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3831 [SOCKOP_listen] = 2, /* sockfd, backlog */
3832 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3833 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3834 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3835 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3836 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3837 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3838 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3839 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3840 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3841 [SOCKOP_shutdown] = 2, /* sockfd, how */
3842 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3843 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003844 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3845 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003846 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3847 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3848 };
3849 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003850
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003851 /* first, collect the arguments in a[] according to ac[] */
3852 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3853 unsigned i;
3854 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3855 for (i = 0; i < ac[num]; ++i) {
3856 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003857 return -TARGET_EFAULT;
3858 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003859 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003860 }
bellard2f619692007-11-16 10:46:05 +00003861
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003862 /* now when we have the args, actually handle the call */
3863 switch (num) {
3864 case SOCKOP_socket: /* domain, type, protocol */
3865 return do_socket(a[0], a[1], a[2]);
3866 case SOCKOP_bind: /* sockfd, addr, addrlen */
3867 return do_bind(a[0], a[1], a[2]);
3868 case SOCKOP_connect: /* sockfd, addr, addrlen */
3869 return do_connect(a[0], a[1], a[2]);
3870 case SOCKOP_listen: /* sockfd, backlog */
3871 return get_errno(listen(a[0], a[1]));
3872 case SOCKOP_accept: /* sockfd, addr, addrlen */
3873 return do_accept4(a[0], a[1], a[2], 0);
3874 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3875 return do_accept4(a[0], a[1], a[2], a[3]);
3876 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3877 return do_getsockname(a[0], a[1], a[2]);
3878 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3879 return do_getpeername(a[0], a[1], a[2]);
3880 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3881 return do_socketpair(a[0], a[1], a[2], a[3]);
3882 case SOCKOP_send: /* sockfd, msg, len, flags */
3883 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3884 case SOCKOP_recv: /* sockfd, msg, len, flags */
3885 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3886 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3887 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3888 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3889 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3890 case SOCKOP_shutdown: /* sockfd, how */
3891 return get_errno(shutdown(a[0], a[1]));
3892 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3893 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3894 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3895 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003896 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3897 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3898 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3899 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003900 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3901 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3902 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3903 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003904 default:
3905 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003906 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003907 }
bellard31e31b82003-02-18 22:55:36 +00003908}
j_mayer32407102007-09-26 23:01:49 +00003909#endif
bellard31e31b82003-02-18 22:55:36 +00003910
bellard8853f862004-02-22 14:57:26 +00003911#define N_SHM_REGIONS 32
3912
3913static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003914 abi_ulong start;
3915 abi_ulong size;
3916 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003917} shm_regions[N_SHM_REGIONS];
3918
Peter Maydell005eb2a2016-07-15 16:50:47 +01003919#ifndef TARGET_SEMID64_DS
3920/* asm-generic version of this struct */
3921struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00003922{
3923 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003924 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003925#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003926 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003927#endif
blueswir1992f48a2007-10-14 16:27:31 +00003928 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003929#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003930 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003931#endif
blueswir1992f48a2007-10-14 16:27:31 +00003932 abi_ulong sem_nsems;
3933 abi_ulong __unused3;
3934 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003935};
Peter Maydell005eb2a2016-07-15 16:50:47 +01003936#endif
ths3eb6b042007-06-03 14:26:27 +00003937
bellard579a97f2007-11-11 14:26:47 +00003938static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3939 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003940{
3941 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003942 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003943
bellard579a97f2007-11-11 14:26:47 +00003944 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3945 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003946 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003947 host_ip->__key = tswap32(target_ip->__key);
3948 host_ip->uid = tswap32(target_ip->uid);
3949 host_ip->gid = tswap32(target_ip->gid);
3950 host_ip->cuid = tswap32(target_ip->cuid);
3951 host_ip->cgid = tswap32(target_ip->cgid);
3952#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3953 host_ip->mode = tswap32(target_ip->mode);
3954#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003955 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003956#endif
3957#if defined(TARGET_PPC)
3958 host_ip->__seq = tswap32(target_ip->__seq);
3959#else
3960 host_ip->__seq = tswap16(target_ip->__seq);
3961#endif
ths3eb6b042007-06-03 14:26:27 +00003962 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003963 return 0;
ths3eb6b042007-06-03 14:26:27 +00003964}
3965
bellard579a97f2007-11-11 14:26:47 +00003966static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3967 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003968{
3969 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003970 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003971
bellard579a97f2007-11-11 14:26:47 +00003972 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3973 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003974 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003975 target_ip->__key = tswap32(host_ip->__key);
3976 target_ip->uid = tswap32(host_ip->uid);
3977 target_ip->gid = tswap32(host_ip->gid);
3978 target_ip->cuid = tswap32(host_ip->cuid);
3979 target_ip->cgid = tswap32(host_ip->cgid);
3980#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3981 target_ip->mode = tswap32(host_ip->mode);
3982#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003983 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003984#endif
3985#if defined(TARGET_PPC)
3986 target_ip->__seq = tswap32(host_ip->__seq);
3987#else
3988 target_ip->__seq = tswap16(host_ip->__seq);
3989#endif
ths3eb6b042007-06-03 14:26:27 +00003990 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003991 return 0;
ths3eb6b042007-06-03 14:26:27 +00003992}
3993
bellard579a97f2007-11-11 14:26:47 +00003994static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3995 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003996{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003997 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003998
bellard579a97f2007-11-11 14:26:47 +00003999 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4000 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004001 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4002 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004003 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4004 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4005 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004006 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004007 return 0;
ths3eb6b042007-06-03 14:26:27 +00004008}
4009
bellard579a97f2007-11-11 14:26:47 +00004010static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4011 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004012{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004013 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004014
bellard579a97f2007-11-11 14:26:47 +00004015 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4016 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004017 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004018 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004019 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4020 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4021 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004022 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004023 return 0;
ths3eb6b042007-06-03 14:26:27 +00004024}
4025
aurel32e5289082009-04-18 16:16:12 +00004026struct target_seminfo {
4027 int semmap;
4028 int semmni;
4029 int semmns;
4030 int semmnu;
4031 int semmsl;
4032 int semopm;
4033 int semume;
4034 int semusz;
4035 int semvmx;
4036 int semaem;
4037};
4038
4039static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4040 struct seminfo *host_seminfo)
4041{
4042 struct target_seminfo *target_seminfo;
4043 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4044 return -TARGET_EFAULT;
4045 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4046 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4047 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4048 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4049 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4050 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4051 __put_user(host_seminfo->semume, &target_seminfo->semume);
4052 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4053 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4054 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4055 unlock_user_struct(target_seminfo, target_addr, 1);
4056 return 0;
4057}
4058
thsfa294812007-02-02 22:05:00 +00004059union semun {
4060 int val;
ths3eb6b042007-06-03 14:26:27 +00004061 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004062 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004063 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004064};
4065
ths3eb6b042007-06-03 14:26:27 +00004066union target_semun {
4067 int val;
aurel32e5289082009-04-18 16:16:12 +00004068 abi_ulong buf;
4069 abi_ulong array;
4070 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004071};
4072
aurel32e5289082009-04-18 16:16:12 +00004073static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4074 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004075{
aurel32e5289082009-04-18 16:16:12 +00004076 int nsems;
4077 unsigned short *array;
4078 union semun semun;
4079 struct semid_ds semid_ds;
4080 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004081
aurel32e5289082009-04-18 16:16:12 +00004082 semun.buf = &semid_ds;
4083
4084 ret = semctl(semid, 0, IPC_STAT, semun);
4085 if (ret == -1)
4086 return get_errno(ret);
4087
4088 nsems = semid_ds.sem_nsems;
4089
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304090 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004091 if (!*host_array) {
4092 return -TARGET_ENOMEM;
4093 }
aurel32e5289082009-04-18 16:16:12 +00004094 array = lock_user(VERIFY_READ, target_addr,
4095 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004096 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304097 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004098 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004099 }
aurel32e5289082009-04-18 16:16:12 +00004100
4101 for(i=0; i<nsems; i++) {
4102 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004103 }
aurel32e5289082009-04-18 16:16:12 +00004104 unlock_user(array, target_addr, 0);
4105
bellard579a97f2007-11-11 14:26:47 +00004106 return 0;
ths3eb6b042007-06-03 14:26:27 +00004107}
4108
aurel32e5289082009-04-18 16:16:12 +00004109static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4110 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004111{
aurel32e5289082009-04-18 16:16:12 +00004112 int nsems;
4113 unsigned short *array;
4114 union semun semun;
4115 struct semid_ds semid_ds;
4116 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004117
aurel32e5289082009-04-18 16:16:12 +00004118 semun.buf = &semid_ds;
4119
4120 ret = semctl(semid, 0, IPC_STAT, semun);
4121 if (ret == -1)
4122 return get_errno(ret);
4123
4124 nsems = semid_ds.sem_nsems;
4125
4126 array = lock_user(VERIFY_WRITE, target_addr,
4127 nsems*sizeof(unsigned short), 0);
4128 if (!array)
4129 return -TARGET_EFAULT;
4130
4131 for(i=0; i<nsems; i++) {
4132 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004133 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304134 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004135 unlock_user(array, target_addr, 1);
4136
bellard579a97f2007-11-11 14:26:47 +00004137 return 0;
ths3eb6b042007-06-03 14:26:27 +00004138}
4139
aurel32e5289082009-04-18 16:16:12 +00004140static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004141 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004142{
Stefan Weild1c002b2015-02-08 15:40:58 +01004143 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004144 union semun arg;
4145 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304146 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004147 struct seminfo seminfo;
4148 abi_long ret = -TARGET_EINVAL;
4149 abi_long err;
4150 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004151
4152 switch( cmd ) {
4153 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004154 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004155 /* In 64 bit cross-endian situations, we will erroneously pick up
4156 * the wrong half of the union for the "val" element. To rectify
4157 * this, the entire 8-byte structure is byteswapped, followed by
4158 * a swap of the 4 byte val field. In other cases, the data is
4159 * already in proper host byte order. */
4160 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4161 target_su.buf = tswapal(target_su.buf);
4162 arg.val = tswap32(target_su.val);
4163 } else {
4164 arg.val = target_su.val;
4165 }
aurel32e5289082009-04-18 16:16:12 +00004166 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004167 break;
4168 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004169 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004170 err = target_to_host_semarray(semid, &array, target_su.array);
4171 if (err)
4172 return err;
4173 arg.array = array;
4174 ret = get_errno(semctl(semid, semnum, cmd, arg));
4175 err = host_to_target_semarray(semid, target_su.array, &array);
4176 if (err)
4177 return err;
ths3eb6b042007-06-03 14:26:27 +00004178 break;
4179 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004180 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004181 case SEM_STAT:
4182 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4183 if (err)
4184 return err;
4185 arg.buf = &dsarg;
4186 ret = get_errno(semctl(semid, semnum, cmd, arg));
4187 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4188 if (err)
4189 return err;
ths3eb6b042007-06-03 14:26:27 +00004190 break;
aurel32e5289082009-04-18 16:16:12 +00004191 case IPC_INFO:
4192 case SEM_INFO:
4193 arg.__buf = &seminfo;
4194 ret = get_errno(semctl(semid, semnum, cmd, arg));
4195 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4196 if (err)
4197 return err;
4198 break;
4199 case IPC_RMID:
4200 case GETPID:
4201 case GETNCNT:
4202 case GETZCNT:
4203 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4204 break;
ths3eb6b042007-06-03 14:26:27 +00004205 }
4206
4207 return ret;
4208}
4209
aurel32e5289082009-04-18 16:16:12 +00004210struct target_sembuf {
4211 unsigned short sem_num;
4212 short sem_op;
4213 short sem_flg;
4214};
4215
4216static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4217 abi_ulong target_addr,
4218 unsigned nsops)
4219{
4220 struct target_sembuf *target_sembuf;
4221 int i;
4222
4223 target_sembuf = lock_user(VERIFY_READ, target_addr,
4224 nsops*sizeof(struct target_sembuf), 1);
4225 if (!target_sembuf)
4226 return -TARGET_EFAULT;
4227
4228 for(i=0; i<nsops; i++) {
4229 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4230 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4231 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4232 }
4233
4234 unlock_user(target_sembuf, target_addr, 0);
4235
4236 return 0;
4237}
4238
4239static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4240{
4241 struct sembuf sops[nsops];
4242
4243 if (target_to_host_sembuf(sops, ptr, nsops))
4244 return -TARGET_EFAULT;
4245
Peter Maydellffb7ee72016-06-06 19:58:12 +01004246 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004247}
4248
ths1bc012f2007-06-03 14:27:49 +00004249struct target_msqid_ds
4250{
aurel321c54ff92008-10-13 21:08:44 +00004251 struct target_ipc_perm msg_perm;
4252 abi_ulong msg_stime;
4253#if TARGET_ABI_BITS == 32
4254 abi_ulong __unused1;
4255#endif
4256 abi_ulong msg_rtime;
4257#if TARGET_ABI_BITS == 32
4258 abi_ulong __unused2;
4259#endif
4260 abi_ulong msg_ctime;
4261#if TARGET_ABI_BITS == 32
4262 abi_ulong __unused3;
4263#endif
4264 abi_ulong __msg_cbytes;
4265 abi_ulong msg_qnum;
4266 abi_ulong msg_qbytes;
4267 abi_ulong msg_lspid;
4268 abi_ulong msg_lrpid;
4269 abi_ulong __unused4;
4270 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004271};
4272
bellard579a97f2007-11-11 14:26:47 +00004273static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4274 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004275{
4276 struct target_msqid_ds *target_md;
4277
bellard579a97f2007-11-11 14:26:47 +00004278 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4279 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004280 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4281 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004282 host_md->msg_stime = tswapal(target_md->msg_stime);
4283 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4284 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4285 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4286 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4287 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4288 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4289 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004290 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004291 return 0;
ths1bc012f2007-06-03 14:27:49 +00004292}
4293
bellard579a97f2007-11-11 14:26:47 +00004294static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4295 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004296{
4297 struct target_msqid_ds *target_md;
4298
bellard579a97f2007-11-11 14:26:47 +00004299 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4300 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004301 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4302 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004303 target_md->msg_stime = tswapal(host_md->msg_stime);
4304 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4305 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4306 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4307 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4308 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4309 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4310 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004311 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004312 return 0;
ths1bc012f2007-06-03 14:27:49 +00004313}
4314
aurel321c54ff92008-10-13 21:08:44 +00004315struct target_msginfo {
4316 int msgpool;
4317 int msgmap;
4318 int msgmax;
4319 int msgmnb;
4320 int msgmni;
4321 int msgssz;
4322 int msgtql;
4323 unsigned short int msgseg;
4324};
4325
4326static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4327 struct msginfo *host_msginfo)
4328{
4329 struct target_msginfo *target_msginfo;
4330 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4331 return -TARGET_EFAULT;
4332 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4333 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4334 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4335 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4336 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4337 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4338 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4339 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4340 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004341 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004342}
4343
4344static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004345{
4346 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004347 struct msginfo msginfo;
4348 abi_long ret = -TARGET_EINVAL;
4349
4350 cmd &= 0xff;
4351
4352 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004353 case IPC_STAT:
4354 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004355 case MSG_STAT:
4356 if (target_to_host_msqid_ds(&dsarg,ptr))
4357 return -TARGET_EFAULT;
4358 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4359 if (host_to_target_msqid_ds(ptr,&dsarg))
4360 return -TARGET_EFAULT;
4361 break;
4362 case IPC_RMID:
4363 ret = get_errno(msgctl(msgid, cmd, NULL));
4364 break;
4365 case IPC_INFO:
4366 case MSG_INFO:
4367 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4368 if (host_to_target_msginfo(ptr, &msginfo))
4369 return -TARGET_EFAULT;
4370 break;
ths1bc012f2007-06-03 14:27:49 +00004371 }
aurel321c54ff92008-10-13 21:08:44 +00004372
ths1bc012f2007-06-03 14:27:49 +00004373 return ret;
4374}
4375
4376struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004377 abi_long mtype;
4378 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004379};
4380
blueswir1992f48a2007-10-14 16:27:31 +00004381static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004382 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004383{
4384 struct target_msgbuf *target_mb;
4385 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004386 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004387
Tom Mustaedcc5f92014-08-12 13:53:37 -05004388 if (msgsz < 0) {
4389 return -TARGET_EINVAL;
4390 }
4391
bellard579a97f2007-11-11 14:26:47 +00004392 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4393 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304394 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004395 if (!host_mb) {
4396 unlock_user_struct(target_mb, msgp, 0);
4397 return -TARGET_ENOMEM;
4398 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004399 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004400 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004401 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304402 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004403 unlock_user_struct(target_mb, msgp, 0);
4404
4405 return ret;
4406}
4407
blueswir1992f48a2007-10-14 16:27:31 +00004408static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004409 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004410 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004411{
4412 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004413 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004414 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004415 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004416
Peter Maydell99874f62016-05-20 19:00:56 +01004417 if (msgsz < 0) {
4418 return -TARGET_EINVAL;
4419 }
4420
bellard579a97f2007-11-11 14:26:47 +00004421 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4422 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004423
Peter Maydell415d8472016-05-20 19:00:57 +01004424 host_mb = g_try_malloc(msgsz + sizeof(long));
4425 if (!host_mb) {
4426 ret = -TARGET_ENOMEM;
4427 goto end;
4428 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004429 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004430
bellard579a97f2007-11-11 14:26:47 +00004431 if (ret > 0) {
4432 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4433 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4434 if (!target_mtext) {
4435 ret = -TARGET_EFAULT;
4436 goto end;
4437 }
aurel321c54ff92008-10-13 21:08:44 +00004438 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004439 unlock_user(target_mtext, target_mtext_addr, ret);
4440 }
aurel321c54ff92008-10-13 21:08:44 +00004441
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004442 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004443
bellard579a97f2007-11-11 14:26:47 +00004444end:
4445 if (target_mb)
4446 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004447 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004448 return ret;
4449}
4450
Riku Voipio88a8c982009-04-03 10:42:00 +03004451static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4452 abi_ulong target_addr)
4453{
4454 struct target_shmid_ds *target_sd;
4455
4456 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4457 return -TARGET_EFAULT;
4458 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4459 return -TARGET_EFAULT;
4460 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4461 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4462 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4463 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4464 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4465 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4466 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4467 unlock_user_struct(target_sd, target_addr, 0);
4468 return 0;
4469}
4470
4471static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4472 struct shmid_ds *host_sd)
4473{
4474 struct target_shmid_ds *target_sd;
4475
4476 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4477 return -TARGET_EFAULT;
4478 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4479 return -TARGET_EFAULT;
4480 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4481 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4482 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4483 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4484 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4485 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4486 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4487 unlock_user_struct(target_sd, target_addr, 1);
4488 return 0;
4489}
4490
4491struct target_shminfo {
4492 abi_ulong shmmax;
4493 abi_ulong shmmin;
4494 abi_ulong shmmni;
4495 abi_ulong shmseg;
4496 abi_ulong shmall;
4497};
4498
4499static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4500 struct shminfo *host_shminfo)
4501{
4502 struct target_shminfo *target_shminfo;
4503 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4504 return -TARGET_EFAULT;
4505 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4506 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4507 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4508 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4509 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4510 unlock_user_struct(target_shminfo, target_addr, 1);
4511 return 0;
4512}
4513
4514struct target_shm_info {
4515 int used_ids;
4516 abi_ulong shm_tot;
4517 abi_ulong shm_rss;
4518 abi_ulong shm_swp;
4519 abi_ulong swap_attempts;
4520 abi_ulong swap_successes;
4521};
4522
4523static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4524 struct shm_info *host_shm_info)
4525{
4526 struct target_shm_info *target_shm_info;
4527 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4528 return -TARGET_EFAULT;
4529 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4530 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4531 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4532 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4533 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4534 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4535 unlock_user_struct(target_shm_info, target_addr, 1);
4536 return 0;
4537}
4538
4539static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4540{
4541 struct shmid_ds dsarg;
4542 struct shminfo shminfo;
4543 struct shm_info shm_info;
4544 abi_long ret = -TARGET_EINVAL;
4545
4546 cmd &= 0xff;
4547
4548 switch(cmd) {
4549 case IPC_STAT:
4550 case IPC_SET:
4551 case SHM_STAT:
4552 if (target_to_host_shmid_ds(&dsarg, buf))
4553 return -TARGET_EFAULT;
4554 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4555 if (host_to_target_shmid_ds(buf, &dsarg))
4556 return -TARGET_EFAULT;
4557 break;
4558 case IPC_INFO:
4559 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4560 if (host_to_target_shminfo(buf, &shminfo))
4561 return -TARGET_EFAULT;
4562 break;
4563 case SHM_INFO:
4564 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4565 if (host_to_target_shm_info(buf, &shm_info))
4566 return -TARGET_EFAULT;
4567 break;
4568 case IPC_RMID:
4569 case SHM_LOCK:
4570 case SHM_UNLOCK:
4571 ret = get_errno(shmctl(shmid, cmd, NULL));
4572 break;
4573 }
4574
4575 return ret;
4576}
4577
4578static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4579{
4580 abi_long raddr;
4581 void *host_raddr;
4582 struct shmid_ds shm_info;
4583 int i,ret;
4584
4585 /* find out the length of the shared memory segment */
4586 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4587 if (is_error(ret)) {
4588 /* can't get length, bail out */
4589 return ret;
4590 }
4591
4592 mmap_lock();
4593
4594 if (shmaddr)
4595 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4596 else {
4597 abi_ulong mmap_start;
4598
4599 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4600
4601 if (mmap_start == -1) {
4602 errno = ENOMEM;
4603 host_raddr = (void *)-1;
4604 } else
4605 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4606 }
4607
4608 if (host_raddr == (void *)-1) {
4609 mmap_unlock();
4610 return get_errno((long)host_raddr);
4611 }
4612 raddr=h2g((unsigned long)host_raddr);
4613
4614 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4615 PAGE_VALID | PAGE_READ |
4616 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4617
4618 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004619 if (!shm_regions[i].in_use) {
4620 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004621 shm_regions[i].start = raddr;
4622 shm_regions[i].size = shm_info.shm_segsz;
4623 break;
4624 }
4625 }
4626
4627 mmap_unlock();
4628 return raddr;
4629
4630}
4631
4632static inline abi_long do_shmdt(abi_ulong shmaddr)
4633{
4634 int i;
4635
4636 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004637 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4638 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004639 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004640 break;
4641 }
4642 }
4643
4644 return get_errno(shmdt(g2h(shmaddr)));
4645}
4646
aurel321c54ff92008-10-13 21:08:44 +00004647#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004648/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004649/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004650static abi_long do_ipc(unsigned int call, abi_long first,
4651 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004652 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004653{
4654 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004655 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004656
4657 version = call >> 16;
4658 call &= 0xffff;
4659
4660 switch (call) {
thsfa294812007-02-02 22:05:00 +00004661 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004662 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004663 break;
4664
4665 case IPCOP_semget:
4666 ret = get_errno(semget(first, second, third));
4667 break;
4668
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004669 case IPCOP_semctl: {
4670 /* The semun argument to semctl is passed by value, so dereference the
4671 * ptr argument. */
4672 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004673 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004674 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004675 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004676 }
thsd96372e2007-02-02 22:05:44 +00004677
aurel321c54ff92008-10-13 21:08:44 +00004678 case IPCOP_msgget:
4679 ret = get_errno(msgget(first, second));
4680 break;
thsd96372e2007-02-02 22:05:44 +00004681
aurel321c54ff92008-10-13 21:08:44 +00004682 case IPCOP_msgsnd:
4683 ret = do_msgsnd(first, ptr, second, third);
4684 break;
thsd96372e2007-02-02 22:05:44 +00004685
aurel321c54ff92008-10-13 21:08:44 +00004686 case IPCOP_msgctl:
4687 ret = do_msgctl(first, second, ptr);
4688 break;
thsd96372e2007-02-02 22:05:44 +00004689
aurel321c54ff92008-10-13 21:08:44 +00004690 case IPCOP_msgrcv:
4691 switch (version) {
4692 case 0:
4693 {
4694 struct target_ipc_kludge {
4695 abi_long msgp;
4696 abi_long msgtyp;
4697 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004698
aurel321c54ff92008-10-13 21:08:44 +00004699 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4700 ret = -TARGET_EFAULT;
4701 break;
ths1bc012f2007-06-03 14:27:49 +00004702 }
aurel321c54ff92008-10-13 21:08:44 +00004703
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004704 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004705
4706 unlock_user_struct(tmp, ptr, 0);
4707 break;
4708 }
4709 default:
4710 ret = do_msgrcv(first, ptr, second, fifth, third);
4711 }
4712 break;
thsd96372e2007-02-02 22:05:44 +00004713
bellard8853f862004-02-22 14:57:26 +00004714 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004715 switch (version) {
4716 default:
bellard5a4a8982007-11-11 17:39:18 +00004717 {
4718 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004719 raddr = do_shmat(first, ptr, second);
4720 if (is_error(raddr))
4721 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004722 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004723 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004724 break;
4725 }
4726 case 1:
4727 ret = -TARGET_EINVAL;
4728 break;
bellard5a4a8982007-11-11 17:39:18 +00004729 }
bellard8853f862004-02-22 14:57:26 +00004730 break;
4731 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004732 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004733 break;
4734
4735 case IPCOP_shmget:
4736 /* IPC_* flag values are the same on all linux platforms */
4737 ret = get_errno(shmget(first, second, third));
4738 break;
4739
4740 /* IPC_* and SHM_* command values are the same on all linux platforms */
4741 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004742 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004743 break;
4744 default:
j_mayer32407102007-09-26 23:01:49 +00004745 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004746 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004747 break;
4748 }
4749 return ret;
4750}
j_mayer32407102007-09-26 23:01:49 +00004751#endif
bellard8853f862004-02-22 14:57:26 +00004752
bellard31e31b82003-02-18 22:55:36 +00004753/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004754
Blue Swirl001faf32009-05-13 17:53:17 +00004755#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004756#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4757enum {
4758#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004759STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004760};
4761#undef STRUCT
4762#undef STRUCT_SPECIAL
4763
Blue Swirl001faf32009-05-13 17:53:17 +00004764#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004765#define STRUCT_SPECIAL(name)
4766#include "syscall_types.h"
4767#undef STRUCT
4768#undef STRUCT_SPECIAL
4769
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004770typedef struct IOCTLEntry IOCTLEntry;
4771
4772typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004773 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004774
4775struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004776 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004777 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004778 const char *name;
4779 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004780 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004781 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004782};
bellard31e31b82003-02-18 22:55:36 +00004783
4784#define IOC_R 0x0001
4785#define IOC_W 0x0002
4786#define IOC_RW (IOC_R | IOC_W)
4787
4788#define MAX_STRUCT_SIZE 4096
4789
Peter Maydelldace20d2011-01-10 13:11:24 +00004790#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004791/* So fiemap access checks don't overflow on 32 bit systems.
4792 * This is very slightly smaller than the limit imposed by
4793 * the underlying kernel.
4794 */
4795#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4796 / sizeof(struct fiemap_extent))
4797
4798static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004799 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004800{
4801 /* The parameter for this ioctl is a struct fiemap followed
4802 * by an array of struct fiemap_extent whose size is set
4803 * in fiemap->fm_extent_count. The array is filled in by the
4804 * ioctl.
4805 */
4806 int target_size_in, target_size_out;
4807 struct fiemap *fm;
4808 const argtype *arg_type = ie->arg_type;
4809 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4810 void *argptr, *p;
4811 abi_long ret;
4812 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4813 uint32_t outbufsz;
4814 int free_fm = 0;
4815
4816 assert(arg_type[0] == TYPE_PTR);
4817 assert(ie->access == IOC_RW);
4818 arg_type++;
4819 target_size_in = thunk_type_size(arg_type, 0);
4820 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4821 if (!argptr) {
4822 return -TARGET_EFAULT;
4823 }
4824 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4825 unlock_user(argptr, arg, 0);
4826 fm = (struct fiemap *)buf_temp;
4827 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4828 return -TARGET_EINVAL;
4829 }
4830
4831 outbufsz = sizeof (*fm) +
4832 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4833
4834 if (outbufsz > MAX_STRUCT_SIZE) {
4835 /* We can't fit all the extents into the fixed size buffer.
4836 * Allocate one that is large enough and use it instead.
4837 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304838 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004839 if (!fm) {
4840 return -TARGET_ENOMEM;
4841 }
4842 memcpy(fm, buf_temp, sizeof(struct fiemap));
4843 free_fm = 1;
4844 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004845 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004846 if (!is_error(ret)) {
4847 target_size_out = target_size_in;
4848 /* An extent_count of 0 means we were only counting the extents
4849 * so there are no structs to copy
4850 */
4851 if (fm->fm_extent_count != 0) {
4852 target_size_out += fm->fm_mapped_extents * extent_size;
4853 }
4854 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4855 if (!argptr) {
4856 ret = -TARGET_EFAULT;
4857 } else {
4858 /* Convert the struct fiemap */
4859 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4860 if (fm->fm_extent_count != 0) {
4861 p = argptr + target_size_in;
4862 /* ...and then all the struct fiemap_extents */
4863 for (i = 0; i < fm->fm_mapped_extents; i++) {
4864 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4865 THUNK_TARGET);
4866 p += extent_size;
4867 }
4868 }
4869 unlock_user(argptr, arg, target_size_out);
4870 }
4871 }
4872 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304873 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004874 }
4875 return ret;
4876}
Peter Maydelldace20d2011-01-10 13:11:24 +00004877#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004878
Laurent Vivier059c2f22011-03-30 00:12:12 +02004879static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004880 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004881{
4882 const argtype *arg_type = ie->arg_type;
4883 int target_size;
4884 void *argptr;
4885 int ret;
4886 struct ifconf *host_ifconf;
4887 uint32_t outbufsz;
4888 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4889 int target_ifreq_size;
4890 int nb_ifreq;
4891 int free_buf = 0;
4892 int i;
4893 int target_ifc_len;
4894 abi_long target_ifc_buf;
4895 int host_ifc_len;
4896 char *host_ifc_buf;
4897
4898 assert(arg_type[0] == TYPE_PTR);
4899 assert(ie->access == IOC_RW);
4900
4901 arg_type++;
4902 target_size = thunk_type_size(arg_type, 0);
4903
4904 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4905 if (!argptr)
4906 return -TARGET_EFAULT;
4907 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4908 unlock_user(argptr, arg, 0);
4909
4910 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4911 target_ifc_len = host_ifconf->ifc_len;
4912 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4913
4914 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4915 nb_ifreq = target_ifc_len / target_ifreq_size;
4916 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4917
4918 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4919 if (outbufsz > MAX_STRUCT_SIZE) {
4920 /* We can't fit all the extents into the fixed size buffer.
4921 * Allocate one that is large enough and use it instead.
4922 */
4923 host_ifconf = malloc(outbufsz);
4924 if (!host_ifconf) {
4925 return -TARGET_ENOMEM;
4926 }
4927 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4928 free_buf = 1;
4929 }
4930 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4931
4932 host_ifconf->ifc_len = host_ifc_len;
4933 host_ifconf->ifc_buf = host_ifc_buf;
4934
Peter Maydell49ca6f32016-06-06 19:58:14 +01004935 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004936 if (!is_error(ret)) {
4937 /* convert host ifc_len to target ifc_len */
4938
4939 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4940 target_ifc_len = nb_ifreq * target_ifreq_size;
4941 host_ifconf->ifc_len = target_ifc_len;
4942
4943 /* restore target ifc_buf */
4944
4945 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4946
4947 /* copy struct ifconf to target user */
4948
4949 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4950 if (!argptr)
4951 return -TARGET_EFAULT;
4952 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4953 unlock_user(argptr, arg, target_size);
4954
4955 /* copy ifreq[] to target user */
4956
4957 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4958 for (i = 0; i < nb_ifreq ; i++) {
4959 thunk_convert(argptr + i * target_ifreq_size,
4960 host_ifc_buf + i * sizeof(struct ifreq),
4961 ifreq_arg_type, THUNK_TARGET);
4962 }
4963 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4964 }
4965
4966 if (free_buf) {
4967 free(host_ifconf);
4968 }
4969
4970 return ret;
4971}
4972
Alexander Graf56e904e2012-01-31 18:42:06 +01004973static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004974 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004975{
4976 void *argptr;
4977 struct dm_ioctl *host_dm;
4978 abi_long guest_data;
4979 uint32_t guest_data_size;
4980 int target_size;
4981 const argtype *arg_type = ie->arg_type;
4982 abi_long ret;
4983 void *big_buf = NULL;
4984 char *host_data;
4985
4986 arg_type++;
4987 target_size = thunk_type_size(arg_type, 0);
4988 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4989 if (!argptr) {
4990 ret = -TARGET_EFAULT;
4991 goto out;
4992 }
4993 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4994 unlock_user(argptr, arg, 0);
4995
4996 /* buf_temp is too small, so fetch things into a bigger buffer */
4997 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4998 memcpy(big_buf, buf_temp, target_size);
4999 buf_temp = big_buf;
5000 host_dm = big_buf;
5001
5002 guest_data = arg + host_dm->data_start;
5003 if ((guest_data - arg) < 0) {
5004 ret = -EINVAL;
5005 goto out;
5006 }
5007 guest_data_size = host_dm->data_size - host_dm->data_start;
5008 host_data = (char*)host_dm + host_dm->data_start;
5009
5010 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005011 if (!argptr) {
5012 ret = -TARGET_EFAULT;
5013 goto out;
5014 }
5015
Alexander Graf56e904e2012-01-31 18:42:06 +01005016 switch (ie->host_cmd) {
5017 case DM_REMOVE_ALL:
5018 case DM_LIST_DEVICES:
5019 case DM_DEV_CREATE:
5020 case DM_DEV_REMOVE:
5021 case DM_DEV_SUSPEND:
5022 case DM_DEV_STATUS:
5023 case DM_DEV_WAIT:
5024 case DM_TABLE_STATUS:
5025 case DM_TABLE_CLEAR:
5026 case DM_TABLE_DEPS:
5027 case DM_LIST_VERSIONS:
5028 /* no input data */
5029 break;
5030 case DM_DEV_RENAME:
5031 case DM_DEV_SET_GEOMETRY:
5032 /* data contains only strings */
5033 memcpy(host_data, argptr, guest_data_size);
5034 break;
5035 case DM_TARGET_MSG:
5036 memcpy(host_data, argptr, guest_data_size);
5037 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5038 break;
5039 case DM_TABLE_LOAD:
5040 {
5041 void *gspec = argptr;
5042 void *cur_data = host_data;
5043 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5044 int spec_size = thunk_type_size(arg_type, 0);
5045 int i;
5046
5047 for (i = 0; i < host_dm->target_count; i++) {
5048 struct dm_target_spec *spec = cur_data;
5049 uint32_t next;
5050 int slen;
5051
5052 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5053 slen = strlen((char*)gspec + spec_size) + 1;
5054 next = spec->next;
5055 spec->next = sizeof(*spec) + slen;
5056 strcpy((char*)&spec[1], gspec + spec_size);
5057 gspec += next;
5058 cur_data += spec->next;
5059 }
5060 break;
5061 }
5062 default:
5063 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005064 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005065 goto out;
5066 }
5067 unlock_user(argptr, guest_data, 0);
5068
Peter Maydell49ca6f32016-06-06 19:58:14 +01005069 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005070 if (!is_error(ret)) {
5071 guest_data = arg + host_dm->data_start;
5072 guest_data_size = host_dm->data_size - host_dm->data_start;
5073 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5074 switch (ie->host_cmd) {
5075 case DM_REMOVE_ALL:
5076 case DM_DEV_CREATE:
5077 case DM_DEV_REMOVE:
5078 case DM_DEV_RENAME:
5079 case DM_DEV_SUSPEND:
5080 case DM_DEV_STATUS:
5081 case DM_TABLE_LOAD:
5082 case DM_TABLE_CLEAR:
5083 case DM_TARGET_MSG:
5084 case DM_DEV_SET_GEOMETRY:
5085 /* no return data */
5086 break;
5087 case DM_LIST_DEVICES:
5088 {
5089 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5090 uint32_t remaining_data = guest_data_size;
5091 void *cur_data = argptr;
5092 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5093 int nl_size = 12; /* can't use thunk_size due to alignment */
5094
5095 while (1) {
5096 uint32_t next = nl->next;
5097 if (next) {
5098 nl->next = nl_size + (strlen(nl->name) + 1);
5099 }
5100 if (remaining_data < nl->next) {
5101 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5102 break;
5103 }
5104 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5105 strcpy(cur_data + nl_size, nl->name);
5106 cur_data += nl->next;
5107 remaining_data -= nl->next;
5108 if (!next) {
5109 break;
5110 }
5111 nl = (void*)nl + next;
5112 }
5113 break;
5114 }
5115 case DM_DEV_WAIT:
5116 case DM_TABLE_STATUS:
5117 {
5118 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5119 void *cur_data = argptr;
5120 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5121 int spec_size = thunk_type_size(arg_type, 0);
5122 int i;
5123
5124 for (i = 0; i < host_dm->target_count; i++) {
5125 uint32_t next = spec->next;
5126 int slen = strlen((char*)&spec[1]) + 1;
5127 spec->next = (cur_data - argptr) + spec_size + slen;
5128 if (guest_data_size < spec->next) {
5129 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5130 break;
5131 }
5132 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5133 strcpy(cur_data + spec_size, (char*)&spec[1]);
5134 cur_data = argptr + spec->next;
5135 spec = (void*)host_dm + host_dm->data_start + next;
5136 }
5137 break;
5138 }
5139 case DM_TABLE_DEPS:
5140 {
5141 void *hdata = (void*)host_dm + host_dm->data_start;
5142 int count = *(uint32_t*)hdata;
5143 uint64_t *hdev = hdata + 8;
5144 uint64_t *gdev = argptr + 8;
5145 int i;
5146
5147 *(uint32_t*)argptr = tswap32(count);
5148 for (i = 0; i < count; i++) {
5149 *gdev = tswap64(*hdev);
5150 gdev++;
5151 hdev++;
5152 }
5153 break;
5154 }
5155 case DM_LIST_VERSIONS:
5156 {
5157 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5158 uint32_t remaining_data = guest_data_size;
5159 void *cur_data = argptr;
5160 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5161 int vers_size = thunk_type_size(arg_type, 0);
5162
5163 while (1) {
5164 uint32_t next = vers->next;
5165 if (next) {
5166 vers->next = vers_size + (strlen(vers->name) + 1);
5167 }
5168 if (remaining_data < vers->next) {
5169 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5170 break;
5171 }
5172 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5173 strcpy(cur_data + vers_size, vers->name);
5174 cur_data += vers->next;
5175 remaining_data -= vers->next;
5176 if (!next) {
5177 break;
5178 }
5179 vers = (void*)vers + next;
5180 }
5181 break;
5182 }
5183 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005184 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005185 ret = -TARGET_EINVAL;
5186 goto out;
5187 }
5188 unlock_user(argptr, guest_data, guest_data_size);
5189
5190 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5191 if (!argptr) {
5192 ret = -TARGET_EFAULT;
5193 goto out;
5194 }
5195 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5196 unlock_user(argptr, arg, target_size);
5197 }
5198out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005199 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005200 return ret;
5201}
5202
Alexander Grafa59b5e32014-08-22 13:15:50 +02005203static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005204 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005205{
5206 void *argptr;
5207 int target_size;
5208 const argtype *arg_type = ie->arg_type;
5209 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5210 abi_long ret;
5211
5212 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5213 struct blkpg_partition host_part;
5214
5215 /* Read and convert blkpg */
5216 arg_type++;
5217 target_size = thunk_type_size(arg_type, 0);
5218 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5219 if (!argptr) {
5220 ret = -TARGET_EFAULT;
5221 goto out;
5222 }
5223 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5224 unlock_user(argptr, arg, 0);
5225
5226 switch (host_blkpg->op) {
5227 case BLKPG_ADD_PARTITION:
5228 case BLKPG_DEL_PARTITION:
5229 /* payload is struct blkpg_partition */
5230 break;
5231 default:
5232 /* Unknown opcode */
5233 ret = -TARGET_EINVAL;
5234 goto out;
5235 }
5236
5237 /* Read and convert blkpg->data */
5238 arg = (abi_long)(uintptr_t)host_blkpg->data;
5239 target_size = thunk_type_size(part_arg_type, 0);
5240 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5241 if (!argptr) {
5242 ret = -TARGET_EFAULT;
5243 goto out;
5244 }
5245 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5246 unlock_user(argptr, arg, 0);
5247
5248 /* Swizzle the data pointer to our local copy and call! */
5249 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005250 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005251
5252out:
5253 return ret;
5254}
5255
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005256static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005257 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005258{
5259 const argtype *arg_type = ie->arg_type;
5260 const StructEntry *se;
5261 const argtype *field_types;
5262 const int *dst_offsets, *src_offsets;
5263 int target_size;
5264 void *argptr;
5265 abi_ulong *target_rt_dev_ptr;
5266 unsigned long *host_rt_dev_ptr;
5267 abi_long ret;
5268 int i;
5269
5270 assert(ie->access == IOC_W);
5271 assert(*arg_type == TYPE_PTR);
5272 arg_type++;
5273 assert(*arg_type == TYPE_STRUCT);
5274 target_size = thunk_type_size(arg_type, 0);
5275 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5276 if (!argptr) {
5277 return -TARGET_EFAULT;
5278 }
5279 arg_type++;
5280 assert(*arg_type == (int)STRUCT_rtentry);
5281 se = struct_entries + *arg_type++;
5282 assert(se->convert[0] == NULL);
5283 /* convert struct here to be able to catch rt_dev string */
5284 field_types = se->field_types;
5285 dst_offsets = se->field_offsets[THUNK_HOST];
5286 src_offsets = se->field_offsets[THUNK_TARGET];
5287 for (i = 0; i < se->nb_fields; i++) {
5288 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5289 assert(*field_types == TYPE_PTRVOID);
5290 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5291 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5292 if (*target_rt_dev_ptr != 0) {
5293 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5294 tswapal(*target_rt_dev_ptr));
5295 if (!*host_rt_dev_ptr) {
5296 unlock_user(argptr, arg, 0);
5297 return -TARGET_EFAULT;
5298 }
5299 } else {
5300 *host_rt_dev_ptr = 0;
5301 }
5302 field_types++;
5303 continue;
5304 }
5305 field_types = thunk_convert(buf_temp + dst_offsets[i],
5306 argptr + src_offsets[i],
5307 field_types, THUNK_HOST);
5308 }
5309 unlock_user(argptr, arg, 0);
5310
Peter Maydell49ca6f32016-06-06 19:58:14 +01005311 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005312 if (*host_rt_dev_ptr != 0) {
5313 unlock_user((void *)*host_rt_dev_ptr,
5314 *target_rt_dev_ptr, 0);
5315 }
5316 return ret;
5317}
5318
Paul Burtonca56f5b2014-06-22 11:25:47 +01005319static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005320 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005321{
5322 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005323 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005324}
5325
blueswir19f106a72008-10-05 10:52:52 +00005326static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005327#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005328 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5329#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5330 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00005331#include "ioctls.h"
5332 { 0, 0, },
5333};
5334
pbrook53a59602006-03-25 19:31:22 +00005335/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005336/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005337static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005338{
5339 const IOCTLEntry *ie;
5340 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005341 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005342 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005343 int target_size;
5344 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005345
5346 ie = ioctl_entries;
5347 for(;;) {
5348 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005349 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005350 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005351 }
5352 if (ie->target_cmd == cmd)
5353 break;
5354 ie++;
5355 }
5356 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005357#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005358 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005359#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005360 if (ie->do_ioctl) {
5361 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
5362 }
5363
bellard31e31b82003-02-18 22:55:36 +00005364 switch(arg_type[0]) {
5365 case TYPE_NULL:
5366 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005367 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005368 break;
5369 case TYPE_PTRVOID:
5370 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005371 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005372 break;
5373 case TYPE_PTR:
5374 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005375 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005376 switch(ie->access) {
5377 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005378 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005379 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005380 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5381 if (!argptr)
5382 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005383 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5384 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005385 }
5386 break;
5387 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005388 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5389 if (!argptr)
5390 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005391 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5392 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005393 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005394 break;
5395 default:
5396 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005397 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5398 if (!argptr)
5399 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005400 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5401 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005402 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005403 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005404 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5405 if (!argptr)
5406 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005407 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5408 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005409 }
5410 break;
5411 }
5412 break;
5413 default:
j_mayer32407102007-09-26 23:01:49 +00005414 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5415 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005416 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005417 break;
5418 }
5419 return ret;
5420}
5421
blueswir1b39bc502008-10-05 10:51:10 +00005422static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005423 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5424 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5425 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5426 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5427 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5428 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5429 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5430 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5431 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5432 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5433 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5434 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5435 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5436 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5437 { 0, 0, 0, 0 }
5438};
5439
blueswir1b39bc502008-10-05 10:51:10 +00005440static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005441 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5442 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5443 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5444 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5445 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5446 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5447 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5448 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5449 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5450 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5451 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5452 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5453 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5454 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5455 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5456 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5457 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5458 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5459 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5460 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5461 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5462 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5463 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5464 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5465 { 0, 0, 0, 0 }
5466};
5467
blueswir1b39bc502008-10-05 10:51:10 +00005468static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005469 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5470 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5471 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5472 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5473 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5474 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5475 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5476 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5477 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5478 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5479 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5480 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5481 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5482 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5483 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5484 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5485 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5486 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5487 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5488 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5489 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5490 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5491 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5492 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5493 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5494 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5495 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5496 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5497 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5498 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5499 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5500 { 0, 0, 0, 0 }
5501};
5502
blueswir1b39bc502008-10-05 10:51:10 +00005503static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005504 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5505 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5506 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5507 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5508 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5509 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5510 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5511 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5512 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5513 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5514 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5515 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5516 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5517 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5518 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5519 { 0, 0, 0, 0 }
5520};
5521
5522static void target_to_host_termios (void *dst, const void *src)
5523{
5524 struct host_termios *host = dst;
5525 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005526
ths5fafdf22007-09-16 21:08:06 +00005527 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005528 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005529 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005530 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005531 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005532 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005533 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005534 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5535 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005536
Arnaud Patard44607122009-04-21 17:39:08 +03005537 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005538 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5539 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005540 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005541 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005542 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005543 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005544 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005545 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005546 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005547 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5548 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005549 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5550 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5551 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5552 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5553 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005554 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005555}
ths3b46e622007-09-17 08:09:54 +00005556
bellard31e31b82003-02-18 22:55:36 +00005557static void host_to_target_termios (void *dst, const void *src)
5558{
5559 struct target_termios *target = dst;
5560 const struct host_termios *host = src;
5561
ths5fafdf22007-09-16 21:08:06 +00005562 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005563 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005564 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005565 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005566 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005567 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005568 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005569 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5570 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005571
Arnaud Patard44607122009-04-21 17:39:08 +03005572 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005573 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5574 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5575 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5576 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5577 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5578 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5579 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5580 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5581 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5582 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5583 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5584 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5585 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5586 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5587 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5588 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5589 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5590}
5591
blueswir18e853dc2008-10-05 10:49:32 +00005592static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005593 .convert = { host_to_target_termios, target_to_host_termios },
5594 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5595 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5596};
5597
bellard5286db72003-06-05 00:57:30 +00005598static bitmask_transtbl mmap_flags_tbl[] = {
5599 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5600 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5601 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5602 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5603 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5604 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5605 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5606 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005607 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5608 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005609 { 0, 0, 0, 0 }
5610};
5611
bellard2ab83ea2003-06-15 19:56:46 +00005612#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005613
5614/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005615static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005616
bellard03acab62007-11-11 14:57:14 +00005617static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005618{
5619 int size;
pbrook53a59602006-03-25 19:31:22 +00005620 void *p;
bellard6dbad632003-03-16 18:05:05 +00005621
5622 if (!ldt_table)
5623 return 0;
5624 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5625 if (size > bytecount)
5626 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005627 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5628 if (!p)
bellard03acab62007-11-11 14:57:14 +00005629 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005630 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005631 memcpy(p, ldt_table, size);
5632 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005633 return size;
5634}
5635
5636/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005637static abi_long write_ldt(CPUX86State *env,
5638 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005639{
5640 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005641 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005642 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005643 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005644 uint32_t *lp, entry_1, entry_2;
5645
5646 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005647 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005648 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005649 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005650 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005651 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005652 ldt_info.limit = tswap32(target_ldt_info->limit);
5653 ldt_info.flags = tswap32(target_ldt_info->flags);
5654 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005655
bellard6dbad632003-03-16 18:05:05 +00005656 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005657 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005658 seg_32bit = ldt_info.flags & 1;
5659 contents = (ldt_info.flags >> 1) & 3;
5660 read_exec_only = (ldt_info.flags >> 3) & 1;
5661 limit_in_pages = (ldt_info.flags >> 4) & 1;
5662 seg_not_present = (ldt_info.flags >> 5) & 1;
5663 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005664#ifdef TARGET_ABI32
5665 lm = 0;
5666#else
5667 lm = (ldt_info.flags >> 7) & 1;
5668#endif
bellard6dbad632003-03-16 18:05:05 +00005669 if (contents == 3) {
5670 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005671 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005672 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005673 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005674 }
5675 /* allocate the LDT */
5676 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005677 env->ldt.base = target_mmap(0,
5678 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5679 PROT_READ|PROT_WRITE,
5680 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5681 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005682 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005683 memset(g2h(env->ldt.base), 0,
5684 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005685 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005686 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005687 }
5688
5689 /* NOTE: same code as Linux kernel */
5690 /* Allow LDTs to be cleared by the user. */
5691 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5692 if (oldmode ||
5693 (contents == 0 &&
5694 read_exec_only == 1 &&
5695 seg_32bit == 0 &&
5696 limit_in_pages == 0 &&
5697 seg_not_present == 1 &&
5698 useable == 0 )) {
5699 entry_1 = 0;
5700 entry_2 = 0;
5701 goto install;
5702 }
5703 }
ths3b46e622007-09-17 08:09:54 +00005704
bellard6dbad632003-03-16 18:05:05 +00005705 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5706 (ldt_info.limit & 0x0ffff);
5707 entry_2 = (ldt_info.base_addr & 0xff000000) |
5708 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5709 (ldt_info.limit & 0xf0000) |
5710 ((read_exec_only ^ 1) << 9) |
5711 (contents << 10) |
5712 ((seg_not_present ^ 1) << 15) |
5713 (seg_32bit << 22) |
5714 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005715 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005716 0x7000;
5717 if (!oldmode)
5718 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005719
bellard6dbad632003-03-16 18:05:05 +00005720 /* Install the new entry ... */
5721install:
5722 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5723 lp[0] = tswap32(entry_1);
5724 lp[1] = tswap32(entry_2);
5725 return 0;
5726}
5727
5728/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005729static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5730 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005731{
bellard03acab62007-11-11 14:57:14 +00005732 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005733
bellard6dbad632003-03-16 18:05:05 +00005734 switch (func) {
5735 case 0:
5736 ret = read_ldt(ptr, bytecount);
5737 break;
5738 case 1:
5739 ret = write_ldt(env, ptr, bytecount, 1);
5740 break;
5741 case 0x11:
5742 ret = write_ldt(env, ptr, bytecount, 0);
5743 break;
bellard03acab62007-11-11 14:57:14 +00005744 default:
5745 ret = -TARGET_ENOSYS;
5746 break;
bellard6dbad632003-03-16 18:05:05 +00005747 }
5748 return ret;
5749}
bellard1b6b0292003-03-22 17:31:38 +00005750
blueswir14583f582008-08-24 10:35:55 +00005751#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005752abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005753{
5754 uint64_t *gdt_table = g2h(env->gdt.base);
5755 struct target_modify_ldt_ldt_s ldt_info;
5756 struct target_modify_ldt_ldt_s *target_ldt_info;
5757 int seg_32bit, contents, read_exec_only, limit_in_pages;
5758 int seg_not_present, useable, lm;
5759 uint32_t *lp, entry_1, entry_2;
5760 int i;
5761
5762 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5763 if (!target_ldt_info)
5764 return -TARGET_EFAULT;
5765 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005766 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005767 ldt_info.limit = tswap32(target_ldt_info->limit);
5768 ldt_info.flags = tswap32(target_ldt_info->flags);
5769 if (ldt_info.entry_number == -1) {
5770 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5771 if (gdt_table[i] == 0) {
5772 ldt_info.entry_number = i;
5773 target_ldt_info->entry_number = tswap32(i);
5774 break;
5775 }
5776 }
5777 }
5778 unlock_user_struct(target_ldt_info, ptr, 1);
5779
5780 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5781 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5782 return -TARGET_EINVAL;
5783 seg_32bit = ldt_info.flags & 1;
5784 contents = (ldt_info.flags >> 1) & 3;
5785 read_exec_only = (ldt_info.flags >> 3) & 1;
5786 limit_in_pages = (ldt_info.flags >> 4) & 1;
5787 seg_not_present = (ldt_info.flags >> 5) & 1;
5788 useable = (ldt_info.flags >> 6) & 1;
5789#ifdef TARGET_ABI32
5790 lm = 0;
5791#else
5792 lm = (ldt_info.flags >> 7) & 1;
5793#endif
5794
5795 if (contents == 3) {
5796 if (seg_not_present == 0)
5797 return -TARGET_EINVAL;
5798 }
5799
5800 /* NOTE: same code as Linux kernel */
5801 /* Allow LDTs to be cleared by the user. */
5802 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5803 if ((contents == 0 &&
5804 read_exec_only == 1 &&
5805 seg_32bit == 0 &&
5806 limit_in_pages == 0 &&
5807 seg_not_present == 1 &&
5808 useable == 0 )) {
5809 entry_1 = 0;
5810 entry_2 = 0;
5811 goto install;
5812 }
5813 }
5814
5815 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5816 (ldt_info.limit & 0x0ffff);
5817 entry_2 = (ldt_info.base_addr & 0xff000000) |
5818 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5819 (ldt_info.limit & 0xf0000) |
5820 ((read_exec_only ^ 1) << 9) |
5821 (contents << 10) |
5822 ((seg_not_present ^ 1) << 15) |
5823 (seg_32bit << 22) |
5824 (limit_in_pages << 23) |
5825 (useable << 20) |
5826 (lm << 21) |
5827 0x7000;
5828
5829 /* Install the new entry ... */
5830install:
5831 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5832 lp[0] = tswap32(entry_1);
5833 lp[1] = tswap32(entry_2);
5834 return 0;
5835}
5836
blueswir18fcd3692008-08-17 20:26:25 +00005837static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005838{
5839 struct target_modify_ldt_ldt_s *target_ldt_info;
5840 uint64_t *gdt_table = g2h(env->gdt.base);
5841 uint32_t base_addr, limit, flags;
5842 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5843 int seg_not_present, useable, lm;
5844 uint32_t *lp, entry_1, entry_2;
5845
5846 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5847 if (!target_ldt_info)
5848 return -TARGET_EFAULT;
5849 idx = tswap32(target_ldt_info->entry_number);
5850 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5851 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5852 unlock_user_struct(target_ldt_info, ptr, 1);
5853 return -TARGET_EINVAL;
5854 }
5855 lp = (uint32_t *)(gdt_table + idx);
5856 entry_1 = tswap32(lp[0]);
5857 entry_2 = tswap32(lp[1]);
5858
5859 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5860 contents = (entry_2 >> 10) & 3;
5861 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5862 seg_32bit = (entry_2 >> 22) & 1;
5863 limit_in_pages = (entry_2 >> 23) & 1;
5864 useable = (entry_2 >> 20) & 1;
5865#ifdef TARGET_ABI32
5866 lm = 0;
5867#else
5868 lm = (entry_2 >> 21) & 1;
5869#endif
5870 flags = (seg_32bit << 0) | (contents << 1) |
5871 (read_exec_only << 3) | (limit_in_pages << 4) |
5872 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5873 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5874 base_addr = (entry_1 >> 16) |
5875 (entry_2 & 0xff000000) |
5876 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005877 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005878 target_ldt_info->limit = tswap32(limit);
5879 target_ldt_info->flags = tswap32(flags);
5880 unlock_user_struct(target_ldt_info, ptr, 1);
5881 return 0;
5882}
blueswir14583f582008-08-24 10:35:55 +00005883#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005884
bellardd2fd1af2007-11-14 18:08:56 +00005885#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005886abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005887{
Juan Quintela1add8692011-06-16 17:37:09 +01005888 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005889 abi_ulong val;
5890 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005891
bellardd2fd1af2007-11-14 18:08:56 +00005892 switch(code) {
5893 case TARGET_ARCH_SET_GS:
5894 case TARGET_ARCH_SET_FS:
5895 if (code == TARGET_ARCH_SET_GS)
5896 idx = R_GS;
5897 else
5898 idx = R_FS;
5899 cpu_x86_load_seg(env, idx, 0);
5900 env->segs[idx].base = addr;
5901 break;
5902 case TARGET_ARCH_GET_GS:
5903 case TARGET_ARCH_GET_FS:
5904 if (code == TARGET_ARCH_GET_GS)
5905 idx = R_GS;
5906 else
5907 idx = R_FS;
5908 val = env->segs[idx].base;
5909 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005910 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005911 break;
5912 default:
5913 ret = -TARGET_EINVAL;
5914 break;
5915 }
Juan Quintela1add8692011-06-16 17:37:09 +01005916 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005917}
5918#endif
5919
bellard2ab83ea2003-06-15 19:56:46 +00005920#endif /* defined(TARGET_I386) */
5921
Riku Voipio05098a92011-03-04 15:27:29 +02005922#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005923
pbrookd865bab2008-06-07 22:12:17 +00005924
5925static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5926typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005927 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005928 pthread_mutex_t mutex;
5929 pthread_cond_t cond;
5930 pthread_t thread;
5931 uint32_t tid;
5932 abi_ulong child_tidptr;
5933 abi_ulong parent_tidptr;
5934 sigset_t sigmask;
5935} new_thread_info;
5936
5937static void *clone_func(void *arg)
5938{
5939 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005940 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005941 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005942 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005943
Emilio G. Cota70903762015-08-23 20:23:41 -04005944 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005945 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005946 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005947 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005948 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005949 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005950 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005951 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005952 if (info->child_tidptr)
5953 put_user_u32(info->tid, info->child_tidptr);
5954 if (info->parent_tidptr)
5955 put_user_u32(info->tid, info->parent_tidptr);
5956 /* Enable signals. */
5957 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5958 /* Signal to the parent that we're ready. */
5959 pthread_mutex_lock(&info->mutex);
5960 pthread_cond_broadcast(&info->cond);
5961 pthread_mutex_unlock(&info->mutex);
5962 /* Wait until the parent has finshed initializing the tls state. */
5963 pthread_mutex_lock(&clone_lock);
5964 pthread_mutex_unlock(&clone_lock);
5965 cpu_loop(env);
5966 /* never exits */
5967 return NULL;
5968}
bellard1b6b0292003-03-22 17:31:38 +00005969
ths0da46a62007-10-20 20:23:07 +00005970/* do_fork() Must return host values and target errnos (unlike most
5971 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005972static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005973 abi_ulong parent_tidptr, target_ulong newtls,
5974 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005975{
Andreas Färber0429a972013-08-26 18:14:44 +02005976 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005977 int ret;
bellard5cd43932003-03-29 16:54:36 +00005978 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005979 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005980 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005981 unsigned int nptl_flags;
5982 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005983
balrog436d1242008-09-21 02:39:45 +00005984 /* Emulate vfork() with fork() */
5985 if (flags & CLONE_VFORK)
5986 flags &= ~(CLONE_VFORK | CLONE_VM);
5987
bellard1b6b0292003-03-22 17:31:38 +00005988 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005989 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005990 new_thread_info info;
5991 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005992
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005993 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005994 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005995 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005996 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005997 /* Init regs that differ from the parent. */
5998 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005999 new_cpu = ENV_GET_CPU(new_env);
6000 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006001 ts->bprm = parent_ts->bprm;
6002 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006003 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006004 nptl_flags = flags;
6005 flags &= ~CLONE_NPTL_FLAGS2;
6006
pbrookc2764712009-03-07 15:24:59 +00006007 if (nptl_flags & CLONE_CHILD_CLEARTID) {
6008 ts->child_tidptr = child_tidptr;
6009 }
6010
pbrookd865bab2008-06-07 22:12:17 +00006011 if (nptl_flags & CLONE_SETTLS)
6012 cpu_set_tls (new_env, newtls);
6013
6014 /* Grab a mutex so that thread setup appears atomic. */
6015 pthread_mutex_lock(&clone_lock);
6016
6017 memset(&info, 0, sizeof(info));
6018 pthread_mutex_init(&info.mutex, NULL);
6019 pthread_mutex_lock(&info.mutex);
6020 pthread_cond_init(&info.cond, NULL);
6021 info.env = new_env;
6022 if (nptl_flags & CLONE_CHILD_SETTID)
6023 info.child_tidptr = child_tidptr;
6024 if (nptl_flags & CLONE_PARENT_SETTID)
6025 info.parent_tidptr = parent_tidptr;
6026
6027 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006028 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6029 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006030 /* It is not safe to deliver signals until the child has finished
6031 initializing, so temporarily block all signals. */
6032 sigfillset(&sigmask);
6033 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6034
6035 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006036 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006037
6038 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6039 pthread_attr_destroy(&attr);
6040 if (ret == 0) {
6041 /* Wait for the child to initialize. */
6042 pthread_cond_wait(&info.cond, &info.mutex);
6043 ret = info.tid;
6044 if (flags & CLONE_PARENT_SETTID)
6045 put_user_u32(ret, parent_tidptr);
6046 } else {
6047 ret = -1;
6048 }
6049 pthread_mutex_unlock(&info.mutex);
6050 pthread_cond_destroy(&info.cond);
6051 pthread_mutex_destroy(&info.mutex);
6052 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006053 } else {
6054 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006055 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
6056 return -TARGET_EINVAL;
6057 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006058
6059 if (block_signals()) {
6060 return -TARGET_ERESTARTSYS;
6061 }
6062
pbrookd865bab2008-06-07 22:12:17 +00006063 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006064 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006065 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006066 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02006067 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00006068 cpu_clone_regs(env, newsp);
6069 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006070 /* There is a race condition here. The parent process could
6071 theoretically read the TID in the child process before the child
6072 tid is set. This would require using either ptrace
6073 (not implemented) or having *_tidptr to point at a shared memory
6074 mapping. We can't repeat the spinlock hack used above because
6075 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006076 if (flags & CLONE_CHILD_SETTID)
6077 put_user_u32(gettid(), child_tidptr);
6078 if (flags & CLONE_PARENT_SETTID)
6079 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006080 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006081 if (flags & CLONE_SETTLS)
6082 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006083 if (flags & CLONE_CHILD_CLEARTID)
6084 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006085 } else {
6086 fork_end(0);
6087 }
bellard1b6b0292003-03-22 17:31:38 +00006088 }
6089 return ret;
6090}
6091
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006092/* warning : doesn't handle linux specific flags... */
6093static int target_to_host_fcntl_cmd(int cmd)
6094{
6095 switch(cmd) {
6096 case TARGET_F_DUPFD:
6097 case TARGET_F_GETFD:
6098 case TARGET_F_SETFD:
6099 case TARGET_F_GETFL:
6100 case TARGET_F_SETFL:
6101 return cmd;
6102 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006103 return F_GETLK64;
6104 case TARGET_F_SETLK:
6105 return F_SETLK64;
6106 case TARGET_F_SETLKW:
6107 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006108 case TARGET_F_GETOWN:
6109 return F_GETOWN;
6110 case TARGET_F_SETOWN:
6111 return F_SETOWN;
6112 case TARGET_F_GETSIG:
6113 return F_GETSIG;
6114 case TARGET_F_SETSIG:
6115 return F_SETSIG;
6116#if TARGET_ABI_BITS == 32
6117 case TARGET_F_GETLK64:
6118 return F_GETLK64;
6119 case TARGET_F_SETLK64:
6120 return F_SETLK64;
6121 case TARGET_F_SETLKW64:
6122 return F_SETLKW64;
6123#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006124 case TARGET_F_SETLEASE:
6125 return F_SETLEASE;
6126 case TARGET_F_GETLEASE:
6127 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006128#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006129 case TARGET_F_DUPFD_CLOEXEC:
6130 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006131#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006132 case TARGET_F_NOTIFY:
6133 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006134#ifdef F_GETOWN_EX
6135 case TARGET_F_GETOWN_EX:
6136 return F_GETOWN_EX;
6137#endif
6138#ifdef F_SETOWN_EX
6139 case TARGET_F_SETOWN_EX:
6140 return F_SETOWN_EX;
6141#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006142#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006143 case TARGET_F_SETPIPE_SZ:
6144 return F_SETPIPE_SZ;
6145 case TARGET_F_GETPIPE_SZ:
6146 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006147#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006148 default:
6149 return -TARGET_EINVAL;
6150 }
6151 return -TARGET_EINVAL;
6152}
6153
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006154#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6155static const bitmask_transtbl flock_tbl[] = {
6156 TRANSTBL_CONVERT(F_RDLCK),
6157 TRANSTBL_CONVERT(F_WRLCK),
6158 TRANSTBL_CONVERT(F_UNLCK),
6159 TRANSTBL_CONVERT(F_EXLCK),
6160 TRANSTBL_CONVERT(F_SHLCK),
6161 { 0, 0, 0, 0 }
6162};
6163
Peter Maydell213d3e92016-06-13 11:22:05 +01006164static inline abi_long copy_from_user_flock(struct flock64 *fl,
6165 abi_ulong target_flock_addr)
6166{
6167 struct target_flock *target_fl;
6168 short l_type;
6169
6170 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6171 return -TARGET_EFAULT;
6172 }
6173
6174 __get_user(l_type, &target_fl->l_type);
6175 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6176 __get_user(fl->l_whence, &target_fl->l_whence);
6177 __get_user(fl->l_start, &target_fl->l_start);
6178 __get_user(fl->l_len, &target_fl->l_len);
6179 __get_user(fl->l_pid, &target_fl->l_pid);
6180 unlock_user_struct(target_fl, target_flock_addr, 0);
6181 return 0;
6182}
6183
6184static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6185 const struct flock64 *fl)
6186{
6187 struct target_flock *target_fl;
6188 short l_type;
6189
6190 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6191 return -TARGET_EFAULT;
6192 }
6193
6194 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6195 __put_user(l_type, &target_fl->l_type);
6196 __put_user(fl->l_whence, &target_fl->l_whence);
6197 __put_user(fl->l_start, &target_fl->l_start);
6198 __put_user(fl->l_len, &target_fl->l_len);
6199 __put_user(fl->l_pid, &target_fl->l_pid);
6200 unlock_user_struct(target_fl, target_flock_addr, 1);
6201 return 0;
6202}
6203
6204typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6205typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6206
6207#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6208static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6209 abi_ulong target_flock_addr)
6210{
6211 struct target_eabi_flock64 *target_fl;
6212 short l_type;
6213
6214 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6215 return -TARGET_EFAULT;
6216 }
6217
6218 __get_user(l_type, &target_fl->l_type);
6219 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6220 __get_user(fl->l_whence, &target_fl->l_whence);
6221 __get_user(fl->l_start, &target_fl->l_start);
6222 __get_user(fl->l_len, &target_fl->l_len);
6223 __get_user(fl->l_pid, &target_fl->l_pid);
6224 unlock_user_struct(target_fl, target_flock_addr, 0);
6225 return 0;
6226}
6227
6228static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6229 const struct flock64 *fl)
6230{
6231 struct target_eabi_flock64 *target_fl;
6232 short l_type;
6233
6234 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6235 return -TARGET_EFAULT;
6236 }
6237
6238 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6239 __put_user(l_type, &target_fl->l_type);
6240 __put_user(fl->l_whence, &target_fl->l_whence);
6241 __put_user(fl->l_start, &target_fl->l_start);
6242 __put_user(fl->l_len, &target_fl->l_len);
6243 __put_user(fl->l_pid, &target_fl->l_pid);
6244 unlock_user_struct(target_fl, target_flock_addr, 1);
6245 return 0;
6246}
6247#endif
6248
6249static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6250 abi_ulong target_flock_addr)
6251{
6252 struct target_flock64 *target_fl;
6253 short l_type;
6254
6255 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6256 return -TARGET_EFAULT;
6257 }
6258
6259 __get_user(l_type, &target_fl->l_type);
6260 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6261 __get_user(fl->l_whence, &target_fl->l_whence);
6262 __get_user(fl->l_start, &target_fl->l_start);
6263 __get_user(fl->l_len, &target_fl->l_len);
6264 __get_user(fl->l_pid, &target_fl->l_pid);
6265 unlock_user_struct(target_fl, target_flock_addr, 0);
6266 return 0;
6267}
6268
6269static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6270 const struct flock64 *fl)
6271{
6272 struct target_flock64 *target_fl;
6273 short l_type;
6274
6275 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6276 return -TARGET_EFAULT;
6277 }
6278
6279 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6280 __put_user(l_type, &target_fl->l_type);
6281 __put_user(fl->l_whence, &target_fl->l_whence);
6282 __put_user(fl->l_start, &target_fl->l_start);
6283 __put_user(fl->l_len, &target_fl->l_len);
6284 __put_user(fl->l_pid, &target_fl->l_pid);
6285 unlock_user_struct(target_fl, target_flock_addr, 1);
6286 return 0;
6287}
6288
blueswir1992f48a2007-10-14 16:27:31 +00006289static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006290{
ths43f238d2007-01-05 20:55:49 +00006291 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006292#ifdef F_GETOWN_EX
6293 struct f_owner_ex fox;
6294 struct target_f_owner_ex *target_fox;
6295#endif
blueswir1992f48a2007-10-14 16:27:31 +00006296 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006297 int host_cmd = target_to_host_fcntl_cmd(cmd);
6298
6299 if (host_cmd == -TARGET_EINVAL)
6300 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006301
bellard7775e9e2003-05-14 22:46:48 +00006302 switch(cmd) {
6303 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006304 ret = copy_from_user_flock(&fl64, arg);
6305 if (ret) {
6306 return ret;
6307 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006308 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006309 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006310 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006311 }
6312 break;
ths3b46e622007-09-17 08:09:54 +00006313
bellard7775e9e2003-05-14 22:46:48 +00006314 case TARGET_F_SETLK:
6315 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006316 ret = copy_from_user_flock(&fl64, arg);
6317 if (ret) {
6318 return ret;
6319 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006320 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006321 break;
ths3b46e622007-09-17 08:09:54 +00006322
bellard7775e9e2003-05-14 22:46:48 +00006323 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006324 ret = copy_from_user_flock64(&fl64, arg);
6325 if (ret) {
6326 return ret;
6327 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006328 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006329 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006330 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006331 }
bellard9ee1fa22007-11-11 15:11:19 +00006332 break;
bellard7775e9e2003-05-14 22:46:48 +00006333 case TARGET_F_SETLK64:
6334 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006335 ret = copy_from_user_flock64(&fl64, arg);
6336 if (ret) {
6337 return ret;
6338 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006339 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006340 break;
6341
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006342 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006343 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006344 if (ret >= 0) {
6345 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6346 }
bellardffa65c32004-01-04 23:57:22 +00006347 break;
6348
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006349 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006350 ret = get_errno(safe_fcntl(fd, host_cmd,
6351 target_to_host_bitmask(arg,
6352 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006353 break;
6354
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006355#ifdef F_GETOWN_EX
6356 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006357 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006358 if (ret >= 0) {
6359 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6360 return -TARGET_EFAULT;
6361 target_fox->type = tswap32(fox.type);
6362 target_fox->pid = tswap32(fox.pid);
6363 unlock_user_struct(target_fox, arg, 1);
6364 }
6365 break;
6366#endif
6367
6368#ifdef F_SETOWN_EX
6369 case TARGET_F_SETOWN_EX:
6370 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6371 return -TARGET_EFAULT;
6372 fox.type = tswap32(target_fox->type);
6373 fox.pid = tswap32(target_fox->pid);
6374 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006375 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006376 break;
6377#endif
6378
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006379 case TARGET_F_SETOWN:
6380 case TARGET_F_GETOWN:
6381 case TARGET_F_SETSIG:
6382 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006383 case TARGET_F_SETLEASE:
6384 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006385 case TARGET_F_SETPIPE_SZ:
6386 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006387 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006388 break;
6389
bellard7775e9e2003-05-14 22:46:48 +00006390 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006391 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006392 break;
6393 }
6394 return ret;
6395}
6396
bellard67867302003-11-23 17:05:30 +00006397#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006398
bellard67867302003-11-23 17:05:30 +00006399static inline int high2lowuid(int uid)
6400{
6401 if (uid > 65535)
6402 return 65534;
6403 else
6404 return uid;
6405}
6406
6407static inline int high2lowgid(int gid)
6408{
6409 if (gid > 65535)
6410 return 65534;
6411 else
6412 return gid;
6413}
6414
6415static inline int low2highuid(int uid)
6416{
6417 if ((int16_t)uid == -1)
6418 return -1;
6419 else
6420 return uid;
6421}
6422
6423static inline int low2highgid(int gid)
6424{
6425 if ((int16_t)gid == -1)
6426 return -1;
6427 else
6428 return gid;
6429}
Riku Voipio0c866a72011-04-18 15:23:06 +03006430static inline int tswapid(int id)
6431{
6432 return tswap16(id);
6433}
Peter Maydell76ca3102014-03-02 19:36:41 +00006434
6435#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6436
Riku Voipio0c866a72011-04-18 15:23:06 +03006437#else /* !USE_UID16 */
6438static inline int high2lowuid(int uid)
6439{
6440 return uid;
6441}
6442static inline int high2lowgid(int gid)
6443{
6444 return gid;
6445}
6446static inline int low2highuid(int uid)
6447{
6448 return uid;
6449}
6450static inline int low2highgid(int gid)
6451{
6452 return gid;
6453}
6454static inline int tswapid(int id)
6455{
6456 return tswap32(id);
6457}
Peter Maydell76ca3102014-03-02 19:36:41 +00006458
6459#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6460
bellard67867302003-11-23 17:05:30 +00006461#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006462
Peter Maydellfd6f7792016-03-01 16:33:02 +00006463/* We must do direct syscalls for setting UID/GID, because we want to
6464 * implement the Linux system call semantics of "change only for this thread",
6465 * not the libc/POSIX semantics of "change for all threads in process".
6466 * (See http://ewontfix.com/17/ for more details.)
6467 * We use the 32-bit version of the syscalls if present; if it is not
6468 * then either the host architecture supports 32-bit UIDs natively with
6469 * the standard syscall, or the 16-bit UID is the best we can do.
6470 */
6471#ifdef __NR_setuid32
6472#define __NR_sys_setuid __NR_setuid32
6473#else
6474#define __NR_sys_setuid __NR_setuid
6475#endif
6476#ifdef __NR_setgid32
6477#define __NR_sys_setgid __NR_setgid32
6478#else
6479#define __NR_sys_setgid __NR_setgid
6480#endif
6481#ifdef __NR_setresuid32
6482#define __NR_sys_setresuid __NR_setresuid32
6483#else
6484#define __NR_sys_setresuid __NR_setresuid
6485#endif
6486#ifdef __NR_setresgid32
6487#define __NR_sys_setresgid __NR_setresgid32
6488#else
6489#define __NR_sys_setresgid __NR_setresgid
6490#endif
6491
6492_syscall1(int, sys_setuid, uid_t, uid)
6493_syscall1(int, sys_setgid, gid_t, gid)
6494_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6495_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6496
bellard31e31b82003-02-18 22:55:36 +00006497void syscall_init(void)
6498{
bellard2ab83ea2003-06-15 19:56:46 +00006499 IOCTLEntry *ie;
6500 const argtype *arg_type;
6501 int size;
thsb92c47c2007-11-01 00:07:38 +00006502 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006503
Alexander Graf8be656b2015-05-06 23:47:32 +02006504 thunk_init(STRUCT_MAX);
6505
Blue Swirl001faf32009-05-13 17:53:17 +00006506#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006507#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006508#include "syscall_types.h"
6509#undef STRUCT
6510#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006511
Peter Maydelldd6e9572012-07-23 08:07:22 +00006512 /* Build target_to_host_errno_table[] table from
6513 * host_to_target_errno_table[]. */
6514 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6515 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6516 }
6517
bellard2ab83ea2003-06-15 19:56:46 +00006518 /* we patch the ioctl size if necessary. We rely on the fact that
6519 no ioctl has all the bits at '1' in the size field */
6520 ie = ioctl_entries;
6521 while (ie->target_cmd != 0) {
6522 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6523 TARGET_IOC_SIZEMASK) {
6524 arg_type = ie->arg_type;
6525 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006526 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006527 ie->target_cmd);
6528 exit(1);
6529 }
6530 arg_type++;
6531 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006532 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006533 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6534 (size << TARGET_IOC_SIZESHIFT);
6535 }
thsb92c47c2007-11-01 00:07:38 +00006536
bellard2ab83ea2003-06-15 19:56:46 +00006537 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006538#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6539 (defined(__x86_64__) && defined(TARGET_X86_64))
6540 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6541 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6542 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006543 }
6544#endif
6545 ie++;
6546 }
bellard31e31b82003-02-18 22:55:36 +00006547}
bellardc573ff62004-01-04 15:51:36 +00006548
blueswir1992f48a2007-10-14 16:27:31 +00006549#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006550static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6551{
thsaf325d32008-06-10 15:29:15 +00006552#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006553 return ((uint64_t)word0 << 32) | word1;
6554#else
6555 return ((uint64_t)word1 << 32) | word0;
6556#endif
6557}
blueswir1992f48a2007-10-14 16:27:31 +00006558#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006559static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6560{
6561 return word0;
6562}
blueswir1992f48a2007-10-14 16:27:31 +00006563#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006564
6565#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006566static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6567 abi_long arg2,
6568 abi_long arg3,
6569 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006570{
Riku Voipio48e515d2011-07-12 15:40:51 +03006571 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006572 arg2 = arg3;
6573 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006574 }
pbrookce4defa2006-02-09 16:49:55 +00006575 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6576}
6577#endif
6578
6579#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006580static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6581 abi_long arg2,
6582 abi_long arg3,
6583 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006584{
Riku Voipio48e515d2011-07-12 15:40:51 +03006585 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006586 arg2 = arg3;
6587 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006588 }
pbrookce4defa2006-02-09 16:49:55 +00006589 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6590}
6591#endif
6592
bellard579a97f2007-11-11 14:26:47 +00006593static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6594 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006595{
6596 struct target_timespec *target_ts;
6597
bellard579a97f2007-11-11 14:26:47 +00006598 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6599 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006600 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6601 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006602 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006603 return 0;
pbrook53a59602006-03-25 19:31:22 +00006604}
6605
bellard579a97f2007-11-11 14:26:47 +00006606static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6607 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006608{
6609 struct target_timespec *target_ts;
6610
bellard579a97f2007-11-11 14:26:47 +00006611 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6612 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006613 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6614 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006615 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006616 return 0;
pbrook53a59602006-03-25 19:31:22 +00006617}
6618
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006619static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6620 abi_ulong target_addr)
6621{
6622 struct target_itimerspec *target_itspec;
6623
6624 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6625 return -TARGET_EFAULT;
6626 }
6627
6628 host_itspec->it_interval.tv_sec =
6629 tswapal(target_itspec->it_interval.tv_sec);
6630 host_itspec->it_interval.tv_nsec =
6631 tswapal(target_itspec->it_interval.tv_nsec);
6632 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6633 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6634
6635 unlock_user_struct(target_itspec, target_addr, 1);
6636 return 0;
6637}
6638
6639static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6640 struct itimerspec *host_its)
6641{
6642 struct target_itimerspec *target_itspec;
6643
6644 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6645 return -TARGET_EFAULT;
6646 }
6647
6648 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6649 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6650
6651 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6652 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6653
6654 unlock_user_struct(target_itspec, target_addr, 0);
6655 return 0;
6656}
6657
Peter Maydellc0659762014-08-09 15:42:32 +01006658static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6659 abi_ulong target_addr)
6660{
6661 struct target_sigevent *target_sevp;
6662
6663 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6664 return -TARGET_EFAULT;
6665 }
6666
6667 /* This union is awkward on 64 bit systems because it has a 32 bit
6668 * integer and a pointer in it; we follow the conversion approach
6669 * used for handling sigval types in signal.c so the guest should get
6670 * the correct value back even if we did a 64 bit byteswap and it's
6671 * using the 32 bit integer.
6672 */
6673 host_sevp->sigev_value.sival_ptr =
6674 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6675 host_sevp->sigev_signo =
6676 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6677 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6678 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6679
6680 unlock_user_struct(target_sevp, target_addr, 1);
6681 return 0;
6682}
6683
Tom Musta6f6a4032014-08-12 13:53:42 -05006684#if defined(TARGET_NR_mlockall)
6685static inline int target_to_host_mlockall_arg(int arg)
6686{
6687 int result = 0;
6688
6689 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6690 result |= MCL_CURRENT;
6691 }
6692 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6693 result |= MCL_FUTURE;
6694 }
6695 return result;
6696}
6697#endif
6698
balrog6a24a772008-09-20 02:23:36 +00006699static inline abi_long host_to_target_stat64(void *cpu_env,
6700 abi_ulong target_addr,
6701 struct stat *host_st)
6702{
Alexander Graf09701192013-09-03 20:12:15 +01006703#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006704 if (((CPUARMState *)cpu_env)->eabi) {
6705 struct target_eabi_stat64 *target_st;
6706
6707 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6708 return -TARGET_EFAULT;
6709 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6710 __put_user(host_st->st_dev, &target_st->st_dev);
6711 __put_user(host_st->st_ino, &target_st->st_ino);
6712#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6713 __put_user(host_st->st_ino, &target_st->__st_ino);
6714#endif
6715 __put_user(host_st->st_mode, &target_st->st_mode);
6716 __put_user(host_st->st_nlink, &target_st->st_nlink);
6717 __put_user(host_st->st_uid, &target_st->st_uid);
6718 __put_user(host_st->st_gid, &target_st->st_gid);
6719 __put_user(host_st->st_rdev, &target_st->st_rdev);
6720 __put_user(host_st->st_size, &target_st->st_size);
6721 __put_user(host_st->st_blksize, &target_st->st_blksize);
6722 __put_user(host_st->st_blocks, &target_st->st_blocks);
6723 __put_user(host_st->st_atime, &target_st->target_st_atime);
6724 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6725 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6726 unlock_user_struct(target_st, target_addr, 1);
6727 } else
6728#endif
6729 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006730#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006731 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006732#else
6733 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006734#endif
balrog6a24a772008-09-20 02:23:36 +00006735
6736 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6737 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006738 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006739 __put_user(host_st->st_dev, &target_st->st_dev);
6740 __put_user(host_st->st_ino, &target_st->st_ino);
6741#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6742 __put_user(host_st->st_ino, &target_st->__st_ino);
6743#endif
6744 __put_user(host_st->st_mode, &target_st->st_mode);
6745 __put_user(host_st->st_nlink, &target_st->st_nlink);
6746 __put_user(host_st->st_uid, &target_st->st_uid);
6747 __put_user(host_st->st_gid, &target_st->st_gid);
6748 __put_user(host_st->st_rdev, &target_st->st_rdev);
6749 /* XXX: better use of kernel struct */
6750 __put_user(host_st->st_size, &target_st->st_size);
6751 __put_user(host_st->st_blksize, &target_st->st_blksize);
6752 __put_user(host_st->st_blocks, &target_st->st_blocks);
6753 __put_user(host_st->st_atime, &target_st->target_st_atime);
6754 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6755 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6756 unlock_user_struct(target_st, target_addr, 1);
6757 }
6758
6759 return 0;
6760}
balrog6a24a772008-09-20 02:23:36 +00006761
pbrookbd0c5662008-05-29 14:34:11 +00006762/* ??? Using host futex calls even when target atomic operations
6763 are not really atomic probably breaks things. However implementing
6764 futexes locally would make futexes shared between multiple processes
6765 tricky. However they're probably useless because guest atomic
6766 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006767static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6768 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006769{
6770 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006771 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006772
6773 /* ??? We assume FUTEX_* constants are the same on both host
6774 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006775#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006776 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006777#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006778 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006779#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006780 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006781 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006782 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006783 if (timeout) {
6784 pts = &ts;
6785 target_to_host_timespec(pts, timeout);
6786 } else {
6787 pts = NULL;
6788 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006789 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006790 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006791 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006792 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006793 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006794 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006795 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006796 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006797 case FUTEX_WAKE_OP:
6798 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6799 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6800 But the prototype takes a `struct timespec *'; insert casts
6801 to satisfy the compiler. We do not need to tswap TIMEOUT
6802 since it's not compared to guest memory. */
6803 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006804 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6805 g2h(uaddr2),
6806 (base_op == FUTEX_CMP_REQUEUE
6807 ? tswap32(val3)
6808 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006809 default:
6810 return -TARGET_ENOSYS;
6811 }
6812}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006813#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6814static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6815 abi_long handle, abi_long mount_id,
6816 abi_long flags)
6817{
6818 struct file_handle *target_fh;
6819 struct file_handle *fh;
6820 int mid = 0;
6821 abi_long ret;
6822 char *name;
6823 unsigned int size, total_size;
6824
6825 if (get_user_s32(size, handle)) {
6826 return -TARGET_EFAULT;
6827 }
6828
6829 name = lock_user_string(pathname);
6830 if (!name) {
6831 return -TARGET_EFAULT;
6832 }
6833
6834 total_size = sizeof(struct file_handle) + size;
6835 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6836 if (!target_fh) {
6837 unlock_user(name, pathname, 0);
6838 return -TARGET_EFAULT;
6839 }
6840
6841 fh = g_malloc0(total_size);
6842 fh->handle_bytes = size;
6843
6844 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6845 unlock_user(name, pathname, 0);
6846
6847 /* man name_to_handle_at(2):
6848 * Other than the use of the handle_bytes field, the caller should treat
6849 * the file_handle structure as an opaque data type
6850 */
6851
6852 memcpy(target_fh, fh, total_size);
6853 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6854 target_fh->handle_type = tswap32(fh->handle_type);
6855 g_free(fh);
6856 unlock_user(target_fh, handle, total_size);
6857
6858 if (put_user_s32(mid, mount_id)) {
6859 return -TARGET_EFAULT;
6860 }
6861
6862 return ret;
6863
6864}
6865#endif
6866
6867#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6868static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6869 abi_long flags)
6870{
6871 struct file_handle *target_fh;
6872 struct file_handle *fh;
6873 unsigned int size, total_size;
6874 abi_long ret;
6875
6876 if (get_user_s32(size, handle)) {
6877 return -TARGET_EFAULT;
6878 }
6879
6880 total_size = sizeof(struct file_handle) + size;
6881 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6882 if (!target_fh) {
6883 return -TARGET_EFAULT;
6884 }
6885
Thomas Huthe9d49d52015-10-09 17:56:38 +02006886 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006887 fh->handle_bytes = size;
6888 fh->handle_type = tswap32(target_fh->handle_type);
6889
6890 ret = get_errno(open_by_handle_at(mount_fd, fh,
6891 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6892
6893 g_free(fh);
6894
6895 unlock_user(target_fh, handle, total_size);
6896
6897 return ret;
6898}
6899#endif
pbrookbd0c5662008-05-29 14:34:11 +00006900
Laurent Viviere36800c2015-10-02 14:48:09 +02006901#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6902
6903/* signalfd siginfo conversion */
6904
6905static void
6906host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6907 const struct signalfd_siginfo *info)
6908{
6909 int sig = host_to_target_signal(info->ssi_signo);
6910
6911 /* linux/signalfd.h defines a ssi_addr_lsb
6912 * not defined in sys/signalfd.h but used by some kernels
6913 */
6914
6915#ifdef BUS_MCEERR_AO
6916 if (tinfo->ssi_signo == SIGBUS &&
6917 (tinfo->ssi_code == BUS_MCEERR_AR ||
6918 tinfo->ssi_code == BUS_MCEERR_AO)) {
6919 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6920 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6921 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6922 }
6923#endif
6924
6925 tinfo->ssi_signo = tswap32(sig);
6926 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6927 tinfo->ssi_code = tswap32(info->ssi_code);
6928 tinfo->ssi_pid = tswap32(info->ssi_pid);
6929 tinfo->ssi_uid = tswap32(info->ssi_uid);
6930 tinfo->ssi_fd = tswap32(info->ssi_fd);
6931 tinfo->ssi_tid = tswap32(info->ssi_tid);
6932 tinfo->ssi_band = tswap32(info->ssi_band);
6933 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6934 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6935 tinfo->ssi_status = tswap32(info->ssi_status);
6936 tinfo->ssi_int = tswap32(info->ssi_int);
6937 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6938 tinfo->ssi_utime = tswap64(info->ssi_utime);
6939 tinfo->ssi_stime = tswap64(info->ssi_stime);
6940 tinfo->ssi_addr = tswap64(info->ssi_addr);
6941}
6942
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006943static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006944{
6945 int i;
6946
6947 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6948 host_to_target_signalfd_siginfo(buf + i, buf + i);
6949 }
6950
6951 return len;
6952}
6953
6954static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006955 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006956};
6957
6958static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6959{
6960 int host_flags;
6961 target_sigset_t *target_mask;
6962 sigset_t host_mask;
6963 abi_long ret;
6964
6965 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6966 return -TARGET_EINVAL;
6967 }
6968 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6969 return -TARGET_EFAULT;
6970 }
6971
6972 target_to_host_sigset(&host_mask, target_mask);
6973
6974 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6975
6976 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6977 if (ret >= 0) {
6978 fd_trans_register(ret, &target_signalfd_trans);
6979 }
6980
6981 unlock_user_struct(target_mask, mask, 0);
6982
6983 return ret;
6984}
6985#endif
6986
pbrook1d9d8b52009-04-16 15:17:02 +00006987/* Map host to target signal numbers for the wait family of syscalls.
6988 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006989int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006990{
6991 if (WIFSIGNALED(status)) {
6992 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6993 }
6994 if (WIFSTOPPED(status)) {
6995 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6996 | (status & 0xff);
6997 }
6998 return status;
6999}
7000
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007001static int open_self_cmdline(void *cpu_env, int fd)
7002{
7003 int fd_orig = -1;
7004 bool word_skipped = false;
7005
7006 fd_orig = open("/proc/self/cmdline", O_RDONLY);
7007 if (fd_orig < 0) {
7008 return fd_orig;
7009 }
7010
7011 while (true) {
7012 ssize_t nb_read;
7013 char buf[128];
7014 char *cp_buf = buf;
7015
7016 nb_read = read(fd_orig, buf, sizeof(buf));
7017 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007018 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007019 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007020 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007021 return -1;
7022 } else if (nb_read == 0) {
7023 break;
7024 }
7025
7026 if (!word_skipped) {
7027 /* Skip the first string, which is the path to qemu-*-static
7028 instead of the actual command. */
Peter Maydellba4b3f62016-07-12 13:02:19 +01007029 cp_buf = memchr(buf, 0, nb_read);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007030 if (cp_buf) {
7031 /* Null byte found, skip one string */
7032 cp_buf++;
7033 nb_read -= cp_buf - buf;
7034 word_skipped = true;
7035 }
7036 }
7037
7038 if (word_skipped) {
7039 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007040 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08007041 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007042 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007043 return -1;
7044 }
7045 }
7046 }
7047
7048 return close(fd_orig);
7049}
7050
Alexander Graf36c08d42011-11-02 20:23:24 +01007051static int open_self_maps(void *cpu_env, int fd)
7052{
Andreas Färber0429a972013-08-26 18:14:44 +02007053 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7054 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007055 FILE *fp;
7056 char *line = NULL;
7057 size_t len = 0;
7058 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007059
Alexander Graf1a49ef22012-05-01 16:30:28 +01007060 fp = fopen("/proc/self/maps", "r");
7061 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007062 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007063 }
7064
7065 while ((read = getline(&line, &len, fp)) != -1) {
7066 int fields, dev_maj, dev_min, inode;
7067 uint64_t min, max, offset;
7068 char flag_r, flag_w, flag_x, flag_p;
7069 char path[512] = "";
7070 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7071 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7072 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7073
7074 if ((fields < 10) || (fields > 11)) {
7075 continue;
7076 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007077 if (h2g_valid(min)) {
7078 int flags = page_get_flags(h2g(min));
7079 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
7080 if (page_check_range(h2g(min), max - min, flags) == -1) {
7081 continue;
7082 }
7083 if (h2g(min) == ts->info->stack_limit) {
7084 pstrcpy(path, sizeof(path), " [stack]");
7085 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007086 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007087 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007088 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007089 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007090 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007091 }
7092 }
7093
7094 free(line);
7095 fclose(fp);
7096
Alexander Graf36c08d42011-11-02 20:23:24 +01007097 return 0;
7098}
7099
Alexander Graf480b8e72011-11-02 20:23:25 +01007100static int open_self_stat(void *cpu_env, int fd)
7101{
Andreas Färber0429a972013-08-26 18:14:44 +02007102 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7103 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007104 abi_ulong start_stack = ts->info->start_stack;
7105 int i;
7106
7107 for (i = 0; i < 44; i++) {
7108 char buf[128];
7109 int len;
7110 uint64_t val = 0;
7111
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007112 if (i == 0) {
7113 /* pid */
7114 val = getpid();
7115 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7116 } else if (i == 1) {
7117 /* app name */
7118 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7119 } else if (i == 27) {
7120 /* stack bottom */
7121 val = start_stack;
7122 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7123 } else {
7124 /* for the rest, there is MasterCard */
7125 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007126 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007127
Alexander Graf480b8e72011-11-02 20:23:25 +01007128 len = strlen(buf);
7129 if (write(fd, buf, len) != len) {
7130 return -1;
7131 }
7132 }
7133
7134 return 0;
7135}
7136
Alexander Graf257450e2011-11-02 20:23:26 +01007137static int open_self_auxv(void *cpu_env, int fd)
7138{
Andreas Färber0429a972013-08-26 18:14:44 +02007139 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7140 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007141 abi_ulong auxv = ts->info->saved_auxv;
7142 abi_ulong len = ts->info->auxv_len;
7143 char *ptr;
7144
7145 /*
7146 * Auxiliary vector is stored in target process stack.
7147 * read in whole auxv vector and copy it to file
7148 */
7149 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7150 if (ptr != NULL) {
7151 while (len > 0) {
7152 ssize_t r;
7153 r = write(fd, ptr, len);
7154 if (r <= 0) {
7155 break;
7156 }
7157 len -= r;
7158 ptr += r;
7159 }
7160 lseek(fd, 0, SEEK_SET);
7161 unlock_user(ptr, auxv, len);
7162 }
7163
7164 return 0;
7165}
7166
Andreas Schwab463d8e72013-07-02 14:04:12 +01007167static int is_proc_myself(const char *filename, const char *entry)
7168{
7169 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7170 filename += strlen("/proc/");
7171 if (!strncmp(filename, "self/", strlen("self/"))) {
7172 filename += strlen("self/");
7173 } else if (*filename >= '1' && *filename <= '9') {
7174 char myself[80];
7175 snprintf(myself, sizeof(myself), "%d/", getpid());
7176 if (!strncmp(filename, myself, strlen(myself))) {
7177 filename += strlen(myself);
7178 } else {
7179 return 0;
7180 }
7181 } else {
7182 return 0;
7183 }
7184 if (!strcmp(filename, entry)) {
7185 return 1;
7186 }
7187 }
7188 return 0;
7189}
7190
Laurent Vivierde6b9932013-08-30 01:46:40 +02007191#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7192static int is_proc(const char *filename, const char *entry)
7193{
7194 return strcmp(filename, entry) == 0;
7195}
7196
7197static int open_net_route(void *cpu_env, int fd)
7198{
7199 FILE *fp;
7200 char *line = NULL;
7201 size_t len = 0;
7202 ssize_t read;
7203
7204 fp = fopen("/proc/net/route", "r");
7205 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007206 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007207 }
7208
7209 /* read header */
7210
7211 read = getline(&line, &len, fp);
7212 dprintf(fd, "%s", line);
7213
7214 /* read routes */
7215
7216 while ((read = getline(&line, &len, fp)) != -1) {
7217 char iface[16];
7218 uint32_t dest, gw, mask;
7219 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7220 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7221 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7222 &mask, &mtu, &window, &irtt);
7223 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7224 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7225 metric, tswap32(mask), mtu, window, irtt);
7226 }
7227
7228 free(line);
7229 fclose(fp);
7230
7231 return 0;
7232}
7233#endif
7234
Riku Voipio0b2effd2014-08-06 10:36:37 +03007235static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007236{
7237 struct fake_open {
7238 const char *filename;
7239 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007240 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007241 };
7242 const struct fake_open *fake_open;
7243 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007244 { "maps", open_self_maps, is_proc_myself },
7245 { "stat", open_self_stat, is_proc_myself },
7246 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007247 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007248#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7249 { "/proc/net/route", open_net_route, is_proc },
7250#endif
7251 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007252 };
7253
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007254 if (is_proc_myself(pathname, "exe")) {
7255 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007256 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007257 }
7258
Alexander Graf3be14d02011-11-02 20:23:23 +01007259 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007260 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007261 break;
7262 }
7263 }
7264
7265 if (fake_open->filename) {
7266 const char *tmpdir;
7267 char filename[PATH_MAX];
7268 int fd, r;
7269
7270 /* create temporary file to map stat to */
7271 tmpdir = getenv("TMPDIR");
7272 if (!tmpdir)
7273 tmpdir = "/tmp";
7274 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7275 fd = mkstemp(filename);
7276 if (fd < 0) {
7277 return fd;
7278 }
7279 unlink(filename);
7280
7281 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007282 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007283 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007284 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007285 return r;
7286 }
7287 lseek(fd, 0, SEEK_SET);
7288
7289 return fd;
7290 }
7291
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007292 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007293}
7294
Alexander Grafaecc8862014-11-10 21:33:03 +01007295#define TIMER_MAGIC 0x0caf0000
7296#define TIMER_MAGIC_MASK 0xffff0000
7297
7298/* Convert QEMU provided timer ID back to internal 16bit index format */
7299static target_timer_t get_timer_id(abi_long arg)
7300{
7301 target_timer_t timerid = arg;
7302
7303 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7304 return -TARGET_EINVAL;
7305 }
7306
7307 timerid &= 0xffff;
7308
7309 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7310 return -TARGET_EINVAL;
7311 }
7312
7313 return timerid;
7314}
7315
ths0da46a62007-10-20 20:23:07 +00007316/* do_syscall() should always have a single exit point at the end so
7317 that actions, such as logging of syscall results, can be performed.
7318 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007319abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7320 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007321 abi_long arg5, abi_long arg6, abi_long arg7,
7322 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007323{
Andreas Färber182735e2013-05-29 22:29:20 +02007324 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007325 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007326 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007327 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007328 void *p;
ths3b46e622007-09-17 08:09:54 +00007329
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007330#if defined(DEBUG_ERESTARTSYS)
7331 /* Debug-only code for exercising the syscall-restart code paths
7332 * in the per-architecture cpu main loops: restart every syscall
7333 * the guest makes once before letting it through.
7334 */
7335 {
7336 static int flag;
7337
7338 flag = !flag;
7339 if (flag) {
7340 return -TARGET_ERESTARTSYS;
7341 }
7342 }
7343#endif
7344
bellard72f03902003-02-18 23:33:18 +00007345#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007346 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007347#endif
Lluís Vilanova9c15e702016-06-21 15:52:04 +02007348 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007349 if(do_strace)
7350 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7351
bellard31e31b82003-02-18 22:55:36 +00007352 switch(num) {
7353 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007354 /* In old applications this may be used to implement _exit(2).
7355 However in threaded applictions it is used for thread termination,
7356 and _exit_group is used for application termination.
7357 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007358
7359 if (block_signals()) {
7360 ret = -TARGET_ERESTARTSYS;
7361 break;
7362 }
7363
Andreas Färberbdc44642013-06-24 23:50:24 +02007364 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007365 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007366
Andreas Färber9b056fc2013-06-24 23:53:10 +02007367 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007368 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007369 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02007370 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02007371 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007372 if (ts->child_tidptr) {
7373 put_user_u32(0, ts->child_tidptr);
7374 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7375 NULL, NULL, 0);
7376 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007377 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007378 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007379 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007380 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007381 pthread_exit(NULL);
7382 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02007383#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007384 _mcleanup();
7385#endif
bellarde9009672005-04-26 20:42:36 +00007386 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007387 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007388 ret = 0; /* avoid warning */
7389 break;
7390 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007391 if (arg3 == 0)
7392 ret = 0;
7393 else {
7394 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7395 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007396 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007397 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007398 fd_trans_host_to_target_data(arg1)) {
7399 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007400 }
aurel3238d840e2009-01-30 19:48:17 +00007401 unlock_user(p, arg2, ret);
7402 }
bellard31e31b82003-02-18 22:55:36 +00007403 break;
7404 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007405 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7406 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007407 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00007408 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007409 break;
Chen Gang704eff62015-08-21 05:37:33 +08007410#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007411 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007412 if (!(p = lock_user_string(arg1)))
7413 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007414 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7415 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7416 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007417 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007418 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007419 break;
Chen Gang704eff62015-08-21 05:37:33 +08007420#endif
ths82424832007-09-24 09:21:55 +00007421 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007422 if (!(p = lock_user_string(arg2)))
7423 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007424 ret = get_errno(do_openat(cpu_env, arg1, p,
7425 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7426 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007427 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007428 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007429 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007430#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7431 case TARGET_NR_name_to_handle_at:
7432 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7433 break;
7434#endif
7435#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7436 case TARGET_NR_open_by_handle_at:
7437 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007438 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007439 break;
7440#endif
bellard31e31b82003-02-18 22:55:36 +00007441 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007442 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007443 ret = get_errno(close(arg1));
7444 break;
7445 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007446 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007447 break;
Chen Gang704eff62015-08-21 05:37:33 +08007448#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007449 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00007450 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007451 break;
Chen Gang704eff62015-08-21 05:37:33 +08007452#endif
thse5febef2007-04-01 18:31:35 +00007453#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007454 case TARGET_NR_waitpid:
7455 {
pbrook53a59602006-03-25 19:31:22 +00007456 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007457 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007458 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007459 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007460 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007461 }
7462 break;
thse5febef2007-04-01 18:31:35 +00007463#endif
pbrookf0cbb612008-05-30 18:20:05 +00007464#ifdef TARGET_NR_waitid
7465 case TARGET_NR_waitid:
7466 {
7467 siginfo_t info;
7468 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007469 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007470 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007471 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00007472 goto efault;
7473 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007474 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007475 }
7476 }
7477 break;
7478#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007479#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007480 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007481 if (!(p = lock_user_string(arg1)))
7482 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007483 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007484 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007485 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007486 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007487#endif
Chen Gang704eff62015-08-21 05:37:33 +08007488#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007489 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007490 {
7491 void * p2;
7492 p = lock_user_string(arg1);
7493 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007494 if (!p || !p2)
7495 ret = -TARGET_EFAULT;
7496 else
7497 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007498 unlock_user(p2, arg2, 0);
7499 unlock_user(p, arg1, 0);
7500 }
bellard31e31b82003-02-18 22:55:36 +00007501 break;
Chen Gang704eff62015-08-21 05:37:33 +08007502#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007503#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007504 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007505 {
7506 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007507 if (!arg2 || !arg4)
7508 goto efault;
ths64f0ce42007-09-24 09:25:06 +00007509 p = lock_user_string(arg2);
7510 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007511 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007512 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007513 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007514 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007515 unlock_user(p, arg2, 0);
7516 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007517 }
7518 break;
7519#endif
Chen Gang704eff62015-08-21 05:37:33 +08007520#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007521 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007522 if (!(p = lock_user_string(arg1)))
7523 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007524 ret = get_errno(unlink(p));
7525 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007526 break;
Chen Gang704eff62015-08-21 05:37:33 +08007527#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007528#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007529 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007530 if (!(p = lock_user_string(arg2)))
7531 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007532 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007533 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007534 break;
balrogb7d35e62007-12-12 00:40:24 +00007535#endif
bellard31e31b82003-02-18 22:55:36 +00007536 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007537 {
7538 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007539 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007540 abi_ulong gp;
7541 abi_ulong guest_argp;
7542 abi_ulong guest_envp;
7543 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007544 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007545 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007546
bellardf7341ff2003-03-30 21:00:25 +00007547 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007548 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007549 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007550 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007551 goto efault;
ths03aa1972007-12-02 06:28:08 +00007552 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007553 break;
bellard7854b052003-03-29 17:22:23 +00007554 argc++;
bellard2f619692007-11-16 10:46:05 +00007555 }
bellardf7341ff2003-03-30 21:00:25 +00007556 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007557 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007558 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007559 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007560 goto efault;
ths03aa1972007-12-02 06:28:08 +00007561 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007562 break;
bellard7854b052003-03-29 17:22:23 +00007563 envc++;
bellard2f619692007-11-16 10:46:05 +00007564 }
bellard7854b052003-03-29 17:22:23 +00007565
bellardf7341ff2003-03-30 21:00:25 +00007566 argp = alloca((argc + 1) * sizeof(void *));
7567 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007568
pbrookda94d262008-05-30 18:24:00 +00007569 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007570 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007571 if (get_user_ual(addr, gp))
7572 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007573 if (!addr)
7574 break;
bellard2f619692007-11-16 10:46:05 +00007575 if (!(*q = lock_user_string(addr)))
7576 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007577 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007578 }
bellardf7341ff2003-03-30 21:00:25 +00007579 *q = NULL;
7580
pbrookda94d262008-05-30 18:24:00 +00007581 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007582 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007583 if (get_user_ual(addr, gp))
7584 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007585 if (!addr)
7586 break;
bellard2f619692007-11-16 10:46:05 +00007587 if (!(*q = lock_user_string(addr)))
7588 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007589 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007590 }
bellardf7341ff2003-03-30 21:00:25 +00007591 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007592
bellard2f619692007-11-16 10:46:05 +00007593 if (!(p = lock_user_string(arg1)))
7594 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007595 /* Although execve() is not an interruptible syscall it is
7596 * a special case where we must use the safe_syscall wrapper:
7597 * if we allow a signal to happen before we make the host
7598 * syscall then we will 'lose' it, because at the point of
7599 * execve the process leaves QEMU's control. So we use the
7600 * safe syscall wrapper to ensure that we either take the
7601 * signal as a guest signal, or else it does not happen
7602 * before the execve completes and makes it the other
7603 * program's problem.
7604 */
7605 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007606 unlock_user(p, arg1, 0);
7607
bellard2f619692007-11-16 10:46:05 +00007608 goto execve_end;
7609
7610 execve_efault:
7611 ret = -TARGET_EFAULT;
7612
7613 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007614 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007615 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007616 if (get_user_ual(addr, gp)
7617 || !addr)
7618 break;
pbrook53a59602006-03-25 19:31:22 +00007619 unlock_user(*q, addr, 0);
7620 }
7621 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007622 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007623 if (get_user_ual(addr, gp)
7624 || !addr)
7625 break;
pbrook53a59602006-03-25 19:31:22 +00007626 unlock_user(*q, addr, 0);
7627 }
bellard7854b052003-03-29 17:22:23 +00007628 }
bellard31e31b82003-02-18 22:55:36 +00007629 break;
7630 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007631 if (!(p = lock_user_string(arg1)))
7632 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007633 ret = get_errno(chdir(p));
7634 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007635 break;
bellarda315a142005-01-30 22:59:18 +00007636#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007637 case TARGET_NR_time:
7638 {
pbrook53a59602006-03-25 19:31:22 +00007639 time_t host_time;
7640 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007641 if (!is_error(ret)
7642 && arg1
7643 && put_user_sal(host_time, arg1))
7644 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007645 }
7646 break;
bellarda315a142005-01-30 22:59:18 +00007647#endif
Chen Gang704eff62015-08-21 05:37:33 +08007648#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007649 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007650 if (!(p = lock_user_string(arg1)))
7651 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007652 ret = get_errno(mknod(p, arg2, arg3));
7653 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007654 break;
Chen Gang704eff62015-08-21 05:37:33 +08007655#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007656#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007657 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007658 if (!(p = lock_user_string(arg2)))
7659 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007660 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007661 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007662 break;
7663#endif
Chen Gang704eff62015-08-21 05:37:33 +08007664#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007665 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007666 if (!(p = lock_user_string(arg1)))
7667 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007668 ret = get_errno(chmod(p, arg2));
7669 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007670 break;
Chen Gang704eff62015-08-21 05:37:33 +08007671#endif
bellardebc05482003-09-30 21:08:41 +00007672#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007673 case TARGET_NR_break:
7674 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007675#endif
7676#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007677 case TARGET_NR_oldstat:
7678 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007679#endif
bellard31e31b82003-02-18 22:55:36 +00007680 case TARGET_NR_lseek:
7681 ret = get_errno(lseek(arg1, arg2, arg3));
7682 break;
Richard Henderson92317332010-05-03 10:07:53 -07007683#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7684 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007685 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007686 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007687 ret = get_errno(getpid());
7688 break;
Richard Henderson92317332010-05-03 10:07:53 -07007689#endif
7690#ifdef TARGET_NR_getpid
7691 case TARGET_NR_getpid:
7692 ret = get_errno(getpid());
7693 break;
7694#endif
bellard31e31b82003-02-18 22:55:36 +00007695 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007696 {
7697 /* need to look at the data field */
7698 void *p2, *p3;
7699
7700 if (arg1) {
7701 p = lock_user_string(arg1);
7702 if (!p) {
7703 goto efault;
7704 }
7705 } else {
7706 p = NULL;
7707 }
7708
7709 p2 = lock_user_string(arg2);
7710 if (!p2) {
7711 if (arg1) {
7712 unlock_user(p, arg1, 0);
7713 }
7714 goto efault;
7715 }
7716
7717 if (arg3) {
7718 p3 = lock_user_string(arg3);
7719 if (!p3) {
7720 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007721 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007722 }
7723 unlock_user(p2, arg2, 0);
7724 goto efault;
7725 }
7726 } else {
7727 p3 = NULL;
7728 }
7729
7730 /* FIXME - arg5 should be locked, but it isn't clear how to
7731 * do that since it's not guaranteed to be a NULL-terminated
7732 * string.
7733 */
7734 if (!arg5) {
7735 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7736 } else {
7737 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7738 }
7739 ret = get_errno(ret);
7740
7741 if (arg1) {
7742 unlock_user(p, arg1, 0);
7743 }
7744 unlock_user(p2, arg2, 0);
7745 if (arg3) {
7746 unlock_user(p3, arg3, 0);
7747 }
7748 }
7749 break;
thse5febef2007-04-01 18:31:35 +00007750#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007751 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007752 if (!(p = lock_user_string(arg1)))
7753 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007754 ret = get_errno(umount(p));
7755 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007756 break;
thse5febef2007-04-01 18:31:35 +00007757#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007758#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007759 case TARGET_NR_stime:
7760 {
pbrook53a59602006-03-25 19:31:22 +00007761 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007762 if (get_user_sal(host_time, arg1))
7763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007764 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007765 }
7766 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007767#endif
bellard31e31b82003-02-18 22:55:36 +00007768 case TARGET_NR_ptrace:
7769 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007770#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007771 case TARGET_NR_alarm:
7772 ret = alarm(arg1);
7773 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007774#endif
bellardebc05482003-09-30 21:08:41 +00007775#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007776 case TARGET_NR_oldfstat:
7777 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007778#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007779#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007780 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007781 if (!block_signals()) {
7782 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7783 }
7784 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007785 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007786#endif
thse5febef2007-04-01 18:31:35 +00007787#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007788 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007789 {
pbrook53a59602006-03-25 19:31:22 +00007790 struct utimbuf tbuf, *host_tbuf;
7791 struct target_utimbuf *target_tbuf;
7792 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007793 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7794 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007795 tbuf.actime = tswapal(target_tbuf->actime);
7796 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007797 unlock_user_struct(target_tbuf, arg2, 0);
7798 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007799 } else {
pbrook53a59602006-03-25 19:31:22 +00007800 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007801 }
bellard579a97f2007-11-11 14:26:47 +00007802 if (!(p = lock_user_string(arg1)))
7803 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007804 ret = get_errno(utime(p, host_tbuf));
7805 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007806 }
7807 break;
thse5febef2007-04-01 18:31:35 +00007808#endif
Chen Gang704eff62015-08-21 05:37:33 +08007809#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007810 case TARGET_NR_utimes:
7811 {
bellard978a66f2004-12-06 22:58:05 +00007812 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007813 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007814 if (copy_from_user_timeval(&tv[0], arg2)
7815 || copy_from_user_timeval(&tv[1],
7816 arg2 + sizeof(struct target_timeval)))
7817 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007818 tvp = tv;
7819 } else {
7820 tvp = NULL;
7821 }
bellard579a97f2007-11-11 14:26:47 +00007822 if (!(p = lock_user_string(arg1)))
7823 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007824 ret = get_errno(utimes(p, tvp));
7825 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007826 }
7827 break;
Chen Gang704eff62015-08-21 05:37:33 +08007828#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007829#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007830 case TARGET_NR_futimesat:
7831 {
7832 struct timeval *tvp, tv[2];
7833 if (arg3) {
7834 if (copy_from_user_timeval(&tv[0], arg3)
7835 || copy_from_user_timeval(&tv[1],
7836 arg3 + sizeof(struct target_timeval)))
7837 goto efault;
7838 tvp = tv;
7839 } else {
7840 tvp = NULL;
7841 }
7842 if (!(p = lock_user_string(arg2)))
7843 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007844 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007845 unlock_user(p, arg2, 0);
7846 }
7847 break;
7848#endif
bellardebc05482003-09-30 21:08:41 +00007849#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007850 case TARGET_NR_stty:
7851 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007852#endif
7853#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007854 case TARGET_NR_gtty:
7855 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007856#endif
Chen Gang704eff62015-08-21 05:37:33 +08007857#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007858 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007859 if (!(p = lock_user_string(arg1)))
7860 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007861 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007862 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007863 break;
Chen Gang704eff62015-08-21 05:37:33 +08007864#endif
ths92a34c12007-09-24 09:27:49 +00007865#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7866 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007867 if (!(p = lock_user_string(arg2)))
7868 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007869 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007870 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007871 break;
7872#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007873#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007874 case TARGET_NR_nice:
7875 ret = get_errno(nice(arg1));
7876 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007877#endif
bellardebc05482003-09-30 21:08:41 +00007878#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007879 case TARGET_NR_ftime:
7880 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007881#endif
bellard31e31b82003-02-18 22:55:36 +00007882 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007883 sync();
7884 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007885 break;
7886 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007887 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007888 break;
Chen Gang704eff62015-08-21 05:37:33 +08007889#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007890 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007891 {
7892 void *p2;
7893 p = lock_user_string(arg1);
7894 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007895 if (!p || !p2)
7896 ret = -TARGET_EFAULT;
7897 else
7898 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007899 unlock_user(p2, arg2, 0);
7900 unlock_user(p, arg1, 0);
7901 }
bellard31e31b82003-02-18 22:55:36 +00007902 break;
Chen Gang704eff62015-08-21 05:37:33 +08007903#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007904#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007905 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007906 {
bellard579a97f2007-11-11 14:26:47 +00007907 void *p2;
ths722183f2007-09-24 09:24:37 +00007908 p = lock_user_string(arg2);
7909 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007910 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007911 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007912 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007913 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007914 unlock_user(p2, arg4, 0);
7915 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007916 }
7917 break;
7918#endif
Chen Gang704eff62015-08-21 05:37:33 +08007919#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007920 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007921 if (!(p = lock_user_string(arg1)))
7922 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007923 ret = get_errno(mkdir(p, arg2));
7924 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007925 break;
Chen Gang704eff62015-08-21 05:37:33 +08007926#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007927#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007928 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007929 if (!(p = lock_user_string(arg2)))
7930 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007931 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007932 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007933 break;
7934#endif
Chen Gang704eff62015-08-21 05:37:33 +08007935#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007936 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007937 if (!(p = lock_user_string(arg1)))
7938 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007939 ret = get_errno(rmdir(p));
7940 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007941 break;
Chen Gang704eff62015-08-21 05:37:33 +08007942#endif
bellard31e31b82003-02-18 22:55:36 +00007943 case TARGET_NR_dup:
7944 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007945 if (ret >= 0) {
7946 fd_trans_dup(arg1, ret);
7947 }
bellard31e31b82003-02-18 22:55:36 +00007948 break;
Chen Gang704eff62015-08-21 05:37:33 +08007949#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007950 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007951 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007952 break;
Chen Gang704eff62015-08-21 05:37:33 +08007953#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007954#ifdef TARGET_NR_pipe2
7955 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007956 ret = do_pipe(cpu_env, arg1,
7957 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007958 break;
7959#endif
bellard31e31b82003-02-18 22:55:36 +00007960 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007961 {
pbrook53a59602006-03-25 19:31:22 +00007962 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007963 struct tms tms;
7964 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007965 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007966 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7967 if (!tmsp)
7968 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007969 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7970 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7971 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7972 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007973 }
bellardc596ed12003-07-13 17:32:31 +00007974 if (!is_error(ret))
7975 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007976 }
7977 break;
bellardebc05482003-09-30 21:08:41 +00007978#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007979 case TARGET_NR_prof:
7980 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007981#endif
thse5febef2007-04-01 18:31:35 +00007982#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007983 case TARGET_NR_signal:
7984 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007985#endif
bellard31e31b82003-02-18 22:55:36 +00007986 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007987 if (arg1 == 0) {
7988 ret = get_errno(acct(NULL));
7989 } else {
7990 if (!(p = lock_user_string(arg1)))
7991 goto efault;
7992 ret = get_errno(acct(path(p)));
7993 unlock_user(p, arg1, 0);
7994 }
pbrook24836682006-04-16 14:14:53 +00007995 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007996#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007997 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007998 if (!(p = lock_user_string(arg1)))
7999 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008000 ret = get_errno(umount2(p, arg2));
8001 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008002 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008003#endif
bellardebc05482003-09-30 21:08:41 +00008004#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008005 case TARGET_NR_lock:
8006 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008007#endif
bellard31e31b82003-02-18 22:55:36 +00008008 case TARGET_NR_ioctl:
8009 ret = do_ioctl(arg1, arg2, arg3);
8010 break;
8011 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008012 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008013 break;
bellardebc05482003-09-30 21:08:41 +00008014#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008015 case TARGET_NR_mpx:
8016 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008017#endif
bellard31e31b82003-02-18 22:55:36 +00008018 case TARGET_NR_setpgid:
8019 ret = get_errno(setpgid(arg1, arg2));
8020 break;
bellardebc05482003-09-30 21:08:41 +00008021#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008022 case TARGET_NR_ulimit:
8023 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008024#endif
8025#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008026 case TARGET_NR_oldolduname:
8027 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008028#endif
bellard31e31b82003-02-18 22:55:36 +00008029 case TARGET_NR_umask:
8030 ret = get_errno(umask(arg1));
8031 break;
8032 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008033 if (!(p = lock_user_string(arg1)))
8034 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008035 ret = get_errno(chroot(p));
8036 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008037 break;
Chen Gang704eff62015-08-21 05:37:33 +08008038#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008039 case TARGET_NR_ustat:
8040 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008041#endif
8042#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008043 case TARGET_NR_dup2:
8044 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008045 if (ret >= 0) {
8046 fd_trans_dup(arg1, arg2);
8047 }
bellard31e31b82003-02-18 22:55:36 +00008048 break;
Chen Gang704eff62015-08-21 05:37:33 +08008049#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008050#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8051 case TARGET_NR_dup3:
8052 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008053 if (ret >= 0) {
8054 fd_trans_dup(arg1, arg2);
8055 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008056 break;
8057#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008058#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008059 case TARGET_NR_getppid:
8060 ret = get_errno(getppid());
8061 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008062#endif
Chen Gang704eff62015-08-21 05:37:33 +08008063#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008064 case TARGET_NR_getpgrp:
8065 ret = get_errno(getpgrp());
8066 break;
Chen Gang704eff62015-08-21 05:37:33 +08008067#endif
bellard31e31b82003-02-18 22:55:36 +00008068 case TARGET_NR_setsid:
8069 ret = get_errno(setsid());
8070 break;
thse5febef2007-04-01 18:31:35 +00008071#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008072 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008073 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008074#if defined(TARGET_ALPHA)
8075 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008076 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008077 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008078 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8079 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008080 act._sa_handler = old_act->_sa_handler;
8081 target_siginitset(&act.sa_mask, old_act->sa_mask);
8082 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008083 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008084 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008085 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008086 }
8087 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008088 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008089 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8090 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008091 old_act->_sa_handler = oact._sa_handler;
8092 old_act->sa_mask = oact.sa_mask.sig[0];
8093 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008094 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008095 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008096#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008097 struct target_sigaction act, oact, *pact, *old_act;
8098
8099 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008100 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8101 goto efault;
bellard106ec872006-06-27 21:08:10 +00008102 act._sa_handler = old_act->_sa_handler;
8103 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8104 act.sa_flags = old_act->sa_flags;
8105 unlock_user_struct(old_act, arg2, 0);
8106 pact = &act;
8107 } else {
8108 pact = NULL;
8109 }
8110
8111 ret = get_errno(do_sigaction(arg1, pact, &oact));
8112
8113 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008114 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8115 goto efault;
bellard106ec872006-06-27 21:08:10 +00008116 old_act->_sa_handler = oact._sa_handler;
8117 old_act->sa_flags = oact.sa_flags;
8118 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8119 old_act->sa_mask.sig[1] = 0;
8120 old_act->sa_mask.sig[2] = 0;
8121 old_act->sa_mask.sig[3] = 0;
8122 unlock_user_struct(old_act, arg3, 1);
8123 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008124#else
8125 struct target_old_sigaction *old_act;
8126 struct target_sigaction act, oact, *pact;
8127 if (arg2) {
8128 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8129 goto efault;
8130 act._sa_handler = old_act->_sa_handler;
8131 target_siginitset(&act.sa_mask, old_act->sa_mask);
8132 act.sa_flags = old_act->sa_flags;
8133 act.sa_restorer = old_act->sa_restorer;
8134 unlock_user_struct(old_act, arg2, 0);
8135 pact = &act;
8136 } else {
8137 pact = NULL;
8138 }
8139 ret = get_errno(do_sigaction(arg1, pact, &oact));
8140 if (!is_error(ret) && arg3) {
8141 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8142 goto efault;
8143 old_act->_sa_handler = oact._sa_handler;
8144 old_act->sa_mask = oact.sa_mask.sig[0];
8145 old_act->sa_flags = oact.sa_flags;
8146 old_act->sa_restorer = oact.sa_restorer;
8147 unlock_user_struct(old_act, arg3, 1);
8148 }
ths388bb212007-05-13 13:58:00 +00008149#endif
bellard31e31b82003-02-18 22:55:36 +00008150 }
8151 break;
thse5febef2007-04-01 18:31:35 +00008152#endif
bellard66fb9762003-03-23 01:06:05 +00008153 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008154 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008155#if defined(TARGET_ALPHA)
8156 struct target_sigaction act, oact, *pact = 0;
8157 struct target_rt_sigaction *rt_act;
Peter Maydellc8157012016-06-30 14:23:24 +01008158
8159 if (arg4 != sizeof(target_sigset_t)) {
8160 ret = -TARGET_EINVAL;
8161 break;
8162 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008163 if (arg2) {
8164 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8165 goto efault;
8166 act._sa_handler = rt_act->_sa_handler;
8167 act.sa_mask = rt_act->sa_mask;
8168 act.sa_flags = rt_act->sa_flags;
8169 act.sa_restorer = arg5;
8170 unlock_user_struct(rt_act, arg2, 0);
8171 pact = &act;
8172 }
8173 ret = get_errno(do_sigaction(arg1, pact, &oact));
8174 if (!is_error(ret) && arg3) {
8175 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8176 goto efault;
8177 rt_act->_sa_handler = oact._sa_handler;
8178 rt_act->sa_mask = oact.sa_mask;
8179 rt_act->sa_flags = oact.sa_flags;
8180 unlock_user_struct(rt_act, arg3, 1);
8181 }
8182#else
pbrook53a59602006-03-25 19:31:22 +00008183 struct target_sigaction *act;
8184 struct target_sigaction *oact;
8185
Peter Maydellc8157012016-06-30 14:23:24 +01008186 if (arg4 != sizeof(target_sigset_t)) {
8187 ret = -TARGET_EINVAL;
8188 break;
8189 }
bellard579a97f2007-11-11 14:26:47 +00008190 if (arg2) {
8191 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
8192 goto efault;
8193 } else
pbrook53a59602006-03-25 19:31:22 +00008194 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00008195 if (arg3) {
8196 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8197 ret = -TARGET_EFAULT;
8198 goto rt_sigaction_fail;
8199 }
8200 } else
pbrook53a59602006-03-25 19:31:22 +00008201 oact = NULL;
8202 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008203 rt_sigaction_fail:
8204 if (act)
pbrook53a59602006-03-25 19:31:22 +00008205 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008206 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008207 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008208#endif
pbrook53a59602006-03-25 19:31:22 +00008209 }
bellard66fb9762003-03-23 01:06:05 +00008210 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008211#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008212 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008213 {
8214 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008215 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008216 ret = do_sigprocmask(0, NULL, &cur_set);
8217 if (!ret) {
8218 host_to_target_old_sigset(&target_set, &cur_set);
8219 ret = target_set;
8220 }
bellard66fb9762003-03-23 01:06:05 +00008221 }
8222 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008223#endif
8224#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008225 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008226 {
8227 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008228 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008229 /* We only have one word of the new mask so we must read
8230 * the rest of it with do_sigprocmask() and OR in this word.
8231 * We are guaranteed that a do_sigprocmask() that only queries
8232 * the signal mask will not fail.
8233 */
8234 ret = do_sigprocmask(0, NULL, &cur_set);
8235 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00008236 target_to_host_old_sigset(&set, &target_set);
8237 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008238 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8239 if (!ret) {
8240 host_to_target_old_sigset(&target_set, &oset);
8241 ret = target_set;
8242 }
bellard66fb9762003-03-23 01:06:05 +00008243 }
8244 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008245#endif
thse5febef2007-04-01 18:31:35 +00008246#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008247 case TARGET_NR_sigprocmask:
8248 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008249#if defined(TARGET_ALPHA)
8250 sigset_t set, oldset;
8251 abi_ulong mask;
8252 int how;
8253
8254 switch (arg1) {
8255 case TARGET_SIG_BLOCK:
8256 how = SIG_BLOCK;
8257 break;
8258 case TARGET_SIG_UNBLOCK:
8259 how = SIG_UNBLOCK;
8260 break;
8261 case TARGET_SIG_SETMASK:
8262 how = SIG_SETMASK;
8263 break;
8264 default:
8265 ret = -TARGET_EINVAL;
8266 goto fail;
8267 }
8268 mask = arg2;
8269 target_to_host_old_sigset(&set, &mask);
8270
Peter Maydell3d3efba2016-05-27 15:51:49 +01008271 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008272 if (!is_error(ret)) {
8273 host_to_target_old_sigset(&mask, &oldset);
8274 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008275 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008276 }
8277#else
bellard66fb9762003-03-23 01:06:05 +00008278 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008279 int how;
ths3b46e622007-09-17 08:09:54 +00008280
pbrook53a59602006-03-25 19:31:22 +00008281 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008282 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008283 case TARGET_SIG_BLOCK:
8284 how = SIG_BLOCK;
8285 break;
8286 case TARGET_SIG_UNBLOCK:
8287 how = SIG_UNBLOCK;
8288 break;
8289 case TARGET_SIG_SETMASK:
8290 how = SIG_SETMASK;
8291 break;
8292 default:
ths0da46a62007-10-20 20:23:07 +00008293 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008294 goto fail;
8295 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008296 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008297 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008298 target_to_host_old_sigset(&set, p);
8299 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008300 set_ptr = &set;
8301 } else {
8302 how = 0;
8303 set_ptr = NULL;
8304 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008305 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008306 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008307 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008308 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008309 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008310 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008311 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008312#endif
bellard66fb9762003-03-23 01:06:05 +00008313 }
8314 break;
thse5febef2007-04-01 18:31:35 +00008315#endif
bellard66fb9762003-03-23 01:06:05 +00008316 case TARGET_NR_rt_sigprocmask:
8317 {
8318 int how = arg1;
8319 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008320
Peter Maydellc8157012016-06-30 14:23:24 +01008321 if (arg4 != sizeof(target_sigset_t)) {
8322 ret = -TARGET_EINVAL;
8323 break;
8324 }
8325
pbrook53a59602006-03-25 19:31:22 +00008326 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008327 switch(how) {
8328 case TARGET_SIG_BLOCK:
8329 how = SIG_BLOCK;
8330 break;
8331 case TARGET_SIG_UNBLOCK:
8332 how = SIG_UNBLOCK;
8333 break;
8334 case TARGET_SIG_SETMASK:
8335 how = SIG_SETMASK;
8336 break;
8337 default:
ths0da46a62007-10-20 20:23:07 +00008338 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008339 goto fail;
8340 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008341 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008342 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008343 target_to_host_sigset(&set, p);
8344 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008345 set_ptr = &set;
8346 } else {
8347 how = 0;
8348 set_ptr = NULL;
8349 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008350 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008351 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008352 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008353 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008354 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008355 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008356 }
8357 }
8358 break;
thse5febef2007-04-01 18:31:35 +00008359#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008360 case TARGET_NR_sigpending:
8361 {
8362 sigset_t set;
8363 ret = get_errno(sigpending(&set));
8364 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008365 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008366 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008367 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008368 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008369 }
8370 }
8371 break;
thse5febef2007-04-01 18:31:35 +00008372#endif
bellard66fb9762003-03-23 01:06:05 +00008373 case TARGET_NR_rt_sigpending:
8374 {
8375 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008376
8377 /* Yes, this check is >, not != like most. We follow the kernel's
8378 * logic and it does it like this because it implements
8379 * NR_sigpending through the same code path, and in that case
8380 * the old_sigset_t is smaller in size.
8381 */
8382 if (arg2 > sizeof(target_sigset_t)) {
8383 ret = -TARGET_EINVAL;
8384 break;
8385 }
8386
bellard66fb9762003-03-23 01:06:05 +00008387 ret = get_errno(sigpending(&set));
8388 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008389 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008390 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008391 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008392 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008393 }
8394 }
8395 break;
thse5febef2007-04-01 18:31:35 +00008396#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008397 case TARGET_NR_sigsuspend:
8398 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008399 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008400#if defined(TARGET_ALPHA)
8401 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008402 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008403#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008404 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008405 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008406 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008407 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008408#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008409 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8410 SIGSET_T_SIZE));
8411 if (ret != -TARGET_ERESTARTSYS) {
8412 ts->in_sigsuspend = 1;
8413 }
bellard66fb9762003-03-23 01:06:05 +00008414 }
8415 break;
thse5febef2007-04-01 18:31:35 +00008416#endif
bellard66fb9762003-03-23 01:06:05 +00008417 case TARGET_NR_rt_sigsuspend:
8418 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008419 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008420
8421 if (arg2 != sizeof(target_sigset_t)) {
8422 ret = -TARGET_EINVAL;
8423 break;
8424 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008425 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008426 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008427 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008428 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008429 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8430 SIGSET_T_SIZE));
8431 if (ret != -TARGET_ERESTARTSYS) {
8432 ts->in_sigsuspend = 1;
8433 }
bellard66fb9762003-03-23 01:06:05 +00008434 }
8435 break;
8436 case TARGET_NR_rt_sigtimedwait:
8437 {
bellard66fb9762003-03-23 01:06:05 +00008438 sigset_t set;
8439 struct timespec uts, *puts;
8440 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008441
Peter Maydellc8157012016-06-30 14:23:24 +01008442 if (arg4 != sizeof(target_sigset_t)) {
8443 ret = -TARGET_EINVAL;
8444 break;
8445 }
8446
Anthony Liguoric227f092009-10-01 16:12:16 -05008447 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008448 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008449 target_to_host_sigset(&set, p);
8450 unlock_user(p, arg1, 0);
8451 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008452 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008453 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008454 } else {
8455 puts = NULL;
8456 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008457 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8458 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008459 if (!is_error(ret)) {
8460 if (arg2) {
8461 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8462 0);
8463 if (!p) {
8464 goto efault;
8465 }
8466 host_to_target_siginfo(p, &uinfo);
8467 unlock_user(p, arg2, sizeof(target_siginfo_t));
8468 }
8469 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008470 }
8471 }
8472 break;
8473 case TARGET_NR_rt_sigqueueinfo:
8474 {
8475 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01008476
8477 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
8478 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00008479 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01008480 }
pbrook53a59602006-03-25 19:31:22 +00008481 target_to_host_siginfo(&uinfo, p);
8482 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00008483 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
8484 }
8485 break;
thse5febef2007-04-01 18:31:35 +00008486#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00008487 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008488 if (block_signals()) {
8489 ret = -TARGET_ERESTARTSYS;
8490 } else {
8491 ret = do_sigreturn(cpu_env);
8492 }
bellard66fb9762003-03-23 01:06:05 +00008493 break;
thse5febef2007-04-01 18:31:35 +00008494#endif
bellard66fb9762003-03-23 01:06:05 +00008495 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008496 if (block_signals()) {
8497 ret = -TARGET_ERESTARTSYS;
8498 } else {
8499 ret = do_rt_sigreturn(cpu_env);
8500 }
bellard66fb9762003-03-23 01:06:05 +00008501 break;
bellard31e31b82003-02-18 22:55:36 +00008502 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00008503 if (!(p = lock_user_string(arg1)))
8504 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008505 ret = get_errno(sethostname(p, arg2));
8506 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008507 break;
8508 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00008509 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008510 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008511 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008512 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00008513 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
8514 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008515 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
8516 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008517 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00008518 ret = get_errno(setrlimit(resource, &rlim));
8519 }
8520 break;
bellard31e31b82003-02-18 22:55:36 +00008521 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00008522 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008523 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008524 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008525 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008526
bellard9de5e442003-03-23 16:49:39 +00008527 ret = get_errno(getrlimit(resource, &rlim));
8528 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008529 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8530 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008531 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8532 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008533 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008534 }
8535 }
8536 break;
bellard31e31b82003-02-18 22:55:36 +00008537 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008538 {
8539 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008540 ret = get_errno(getrusage(arg1, &rusage));
8541 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008542 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008543 }
8544 }
8545 break;
bellard31e31b82003-02-18 22:55:36 +00008546 case TARGET_NR_gettimeofday:
8547 {
bellard31e31b82003-02-18 22:55:36 +00008548 struct timeval tv;
8549 ret = get_errno(gettimeofday(&tv, NULL));
8550 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008551 if (copy_to_user_timeval(arg1, &tv))
8552 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008553 }
8554 }
8555 break;
8556 case TARGET_NR_settimeofday:
8557 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008558 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008559 struct timezone tz, *ptz = NULL;
8560
Paul Burtonb67d8032014-06-22 11:25:41 +01008561 if (arg1) {
8562 if (copy_from_user_timeval(&tv, arg1)) {
8563 goto efault;
8564 }
8565 ptv = &tv;
8566 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008567
8568 if (arg2) {
8569 if (copy_from_user_timezone(&tz, arg2)) {
8570 goto efault;
8571 }
8572 ptz = &tz;
8573 }
8574
Paul Burtonb67d8032014-06-22 11:25:41 +01008575 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008576 }
8577 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008578#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008579 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008580#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
8581 ret = do_select(arg1, arg2, arg3, arg4, arg5);
8582#else
bellardf2674e32003-07-09 12:26:09 +00008583 {
pbrook53a59602006-03-25 19:31:22 +00008584 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00008585 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00008586 long nsel;
8587
bellard579a97f2007-11-11 14:26:47 +00008588 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
8589 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008590 nsel = tswapal(sel->n);
8591 inp = tswapal(sel->inp);
8592 outp = tswapal(sel->outp);
8593 exp = tswapal(sel->exp);
8594 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00008595 unlock_user_struct(sel, arg1, 0);
8596 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00008597 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008598#endif
bellardf2674e32003-07-09 12:26:09 +00008599 break;
bellard048f6b42005-11-26 18:47:20 +00008600#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008601#ifdef TARGET_NR_pselect6
8602 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008603 {
8604 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8605 fd_set rfds, wfds, efds;
8606 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8607 struct timespec ts, *ts_ptr;
8608
8609 /*
8610 * The 6th arg is actually two args smashed together,
8611 * so we cannot use the C library.
8612 */
8613 sigset_t set;
8614 struct {
8615 sigset_t *set;
8616 size_t size;
8617 } sig, *sig_ptr;
8618
8619 abi_ulong arg_sigset, arg_sigsize, *arg7;
8620 target_sigset_t *target_sigset;
8621
8622 n = arg1;
8623 rfd_addr = arg2;
8624 wfd_addr = arg3;
8625 efd_addr = arg4;
8626 ts_addr = arg5;
8627
8628 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8629 if (ret) {
8630 goto fail;
8631 }
8632 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8633 if (ret) {
8634 goto fail;
8635 }
8636 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8637 if (ret) {
8638 goto fail;
8639 }
8640
8641 /*
8642 * This takes a timespec, and not a timeval, so we cannot
8643 * use the do_select() helper ...
8644 */
8645 if (ts_addr) {
8646 if (target_to_host_timespec(&ts, ts_addr)) {
8647 goto efault;
8648 }
8649 ts_ptr = &ts;
8650 } else {
8651 ts_ptr = NULL;
8652 }
8653
8654 /* Extract the two packed args for the sigset */
8655 if (arg6) {
8656 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008657 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008658
8659 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8660 if (!arg7) {
8661 goto efault;
8662 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008663 arg_sigset = tswapal(arg7[0]);
8664 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008665 unlock_user(arg7, arg6, 0);
8666
8667 if (arg_sigset) {
8668 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008669 if (arg_sigsize != sizeof(*target_sigset)) {
8670 /* Like the kernel, we enforce correct size sigsets */
8671 ret = -TARGET_EINVAL;
8672 goto fail;
8673 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008674 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8675 sizeof(*target_sigset), 1);
8676 if (!target_sigset) {
8677 goto efault;
8678 }
8679 target_to_host_sigset(&set, target_sigset);
8680 unlock_user(target_sigset, arg_sigset, 0);
8681 } else {
8682 sig.set = NULL;
8683 }
8684 } else {
8685 sig_ptr = NULL;
8686 }
8687
Peter Maydell6df9d382016-05-12 18:47:51 +01008688 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8689 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008690
8691 if (!is_error(ret)) {
8692 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8693 goto efault;
8694 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8695 goto efault;
8696 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8697 goto efault;
8698
8699 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8700 goto efault;
8701 }
8702 }
8703 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008704#endif
Chen Gang704eff62015-08-21 05:37:33 +08008705#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008706 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008707 {
8708 void *p2;
8709 p = lock_user_string(arg1);
8710 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008711 if (!p || !p2)
8712 ret = -TARGET_EFAULT;
8713 else
8714 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008715 unlock_user(p2, arg2, 0);
8716 unlock_user(p, arg1, 0);
8717 }
bellard31e31b82003-02-18 22:55:36 +00008718 break;
Chen Gang704eff62015-08-21 05:37:33 +08008719#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008720#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008721 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008722 {
bellard579a97f2007-11-11 14:26:47 +00008723 void *p2;
thsf0b62432007-09-24 09:25:40 +00008724 p = lock_user_string(arg1);
8725 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008726 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008727 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008728 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008729 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008730 unlock_user(p2, arg3, 0);
8731 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008732 }
8733 break;
8734#endif
bellardebc05482003-09-30 21:08:41 +00008735#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008736 case TARGET_NR_oldlstat:
8737 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008738#endif
Chen Gang704eff62015-08-21 05:37:33 +08008739#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008740 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008741 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008742 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008743 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008744 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008745 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008746 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008747 } else if (!arg3) {
8748 /* Short circuit this for the magic exe check. */
8749 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008750 } else if (is_proc_myself((const char *)p, "exe")) {
8751 char real[PATH_MAX], *temp;
8752 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008753 /* Return value is # of bytes that we wrote to the buffer. */
8754 if (temp == NULL) {
8755 ret = get_errno(-1);
8756 } else {
8757 /* Don't worry about sign mismatch as earlier mapping
8758 * logic would have thrown a bad address error. */
8759 ret = MIN(strlen(real), arg3);
8760 /* We cannot NUL terminate the string. */
8761 memcpy(p2, real, ret);
8762 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008763 } else {
8764 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008765 }
pbrook53a59602006-03-25 19:31:22 +00008766 unlock_user(p2, arg2, ret);
8767 unlock_user(p, arg1, 0);
8768 }
bellard31e31b82003-02-18 22:55:36 +00008769 break;
Chen Gang704eff62015-08-21 05:37:33 +08008770#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008771#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008772 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008773 {
bellard579a97f2007-11-11 14:26:47 +00008774 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008775 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008776 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008777 if (!p || !p2) {
8778 ret = -TARGET_EFAULT;
8779 } else if (is_proc_myself((const char *)p, "exe")) {
8780 char real[PATH_MAX], *temp;
8781 temp = realpath(exec_path, real);
8782 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8783 snprintf((char *)p2, arg4, "%s", real);
8784 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008785 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008786 }
bellard579a97f2007-11-11 14:26:47 +00008787 unlock_user(p2, arg3, ret);
8788 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008789 }
8790 break;
8791#endif
thse5febef2007-04-01 18:31:35 +00008792#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008793 case TARGET_NR_uselib:
8794 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008795#endif
8796#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008797 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008798 if (!(p = lock_user_string(arg1)))
8799 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008800 ret = get_errno(swapon(p, arg2));
8801 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008802 break;
thse5febef2007-04-01 18:31:35 +00008803#endif
bellard31e31b82003-02-18 22:55:36 +00008804 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008805 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8806 /* arg4 must be ignored in all other cases */
8807 p = lock_user_string(arg4);
8808 if (!p) {
8809 goto efault;
8810 }
8811 ret = get_errno(reboot(arg1, arg2, arg3, p));
8812 unlock_user(p, arg4, 0);
8813 } else {
8814 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8815 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008816 break;
thse5febef2007-04-01 18:31:35 +00008817#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008818 case TARGET_NR_readdir:
8819 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008820#endif
8821#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008822 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008823#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8824 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008825 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8826 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008827 {
blueswir1992f48a2007-10-14 16:27:31 +00008828 abi_ulong *v;
8829 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008830 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8831 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008832 v1 = tswapal(v[0]);
8833 v2 = tswapal(v[1]);
8834 v3 = tswapal(v[2]);
8835 v4 = tswapal(v[3]);
8836 v5 = tswapal(v[4]);
8837 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008838 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008839 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008840 target_to_host_bitmask(v4, mmap_flags_tbl),
8841 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008842 }
bellard31e31b82003-02-18 22:55:36 +00008843#else
ths5fafdf22007-09-16 21:08:06 +00008844 ret = get_errno(target_mmap(arg1, arg2, arg3,
8845 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008846 arg5,
8847 arg6));
bellard31e31b82003-02-18 22:55:36 +00008848#endif
bellard6fb883e2003-07-09 17:12:39 +00008849 break;
thse5febef2007-04-01 18:31:35 +00008850#endif
bellarda315a142005-01-30 22:59:18 +00008851#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008852 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008853#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008854#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008855#endif
ths5fafdf22007-09-16 21:08:06 +00008856 ret = get_errno(target_mmap(arg1, arg2, arg3,
8857 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008858 arg5,
bellardc573ff62004-01-04 15:51:36 +00008859 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008860 break;
bellarda315a142005-01-30 22:59:18 +00008861#endif
bellard31e31b82003-02-18 22:55:36 +00008862 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008863 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008864 break;
bellard9de5e442003-03-23 16:49:39 +00008865 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008866 {
Andreas Färber0429a972013-08-26 18:14:44 +02008867 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008868 /* Special hack to detect libc making the stack executable. */
8869 if ((arg3 & PROT_GROWSDOWN)
8870 && arg1 >= ts->info->stack_limit
8871 && arg1 <= ts->info->start_stack) {
8872 arg3 &= ~PROT_GROWSDOWN;
8873 arg2 = arg2 + arg1 - ts->info->stack_limit;
8874 arg1 = ts->info->stack_limit;
8875 }
8876 }
bellard54936002003-05-13 00:25:15 +00008877 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008878 break;
thse5febef2007-04-01 18:31:35 +00008879#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008880 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008881 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008882 break;
thse5febef2007-04-01 18:31:35 +00008883#endif
pbrook53a59602006-03-25 19:31:22 +00008884 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008885#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008886 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008887 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008888 break;
thse5febef2007-04-01 18:31:35 +00008889#endif
8890#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008891 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008892 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008893 break;
thse5febef2007-04-01 18:31:35 +00008894#endif
8895#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008896 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008897 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008898 break;
thse5febef2007-04-01 18:31:35 +00008899#endif
8900#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008901 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008902 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008903 break;
thse5febef2007-04-01 18:31:35 +00008904#endif
8905#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008906 case TARGET_NR_munlockall:
8907 ret = get_errno(munlockall());
8908 break;
thse5febef2007-04-01 18:31:35 +00008909#endif
bellard31e31b82003-02-18 22:55:36 +00008910 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008911 if (!(p = lock_user_string(arg1)))
8912 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008913 ret = get_errno(truncate(p, arg2));
8914 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008915 break;
8916 case TARGET_NR_ftruncate:
8917 ret = get_errno(ftruncate(arg1, arg2));
8918 break;
8919 case TARGET_NR_fchmod:
8920 ret = get_errno(fchmod(arg1, arg2));
8921 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008922#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008923 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008924 if (!(p = lock_user_string(arg2)))
8925 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008926 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008927 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008928 break;
8929#endif
bellard31e31b82003-02-18 22:55:36 +00008930 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008931 /* Note that negative values are valid for getpriority, so we must
8932 differentiate based on errno settings. */
8933 errno = 0;
8934 ret = getpriority(arg1, arg2);
8935 if (ret == -1 && errno != 0) {
8936 ret = -host_to_target_errno(errno);
8937 break;
8938 }
8939#ifdef TARGET_ALPHA
8940 /* Return value is the unbiased priority. Signal no error. */
8941 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8942#else
8943 /* Return value is a biased priority to avoid negative numbers. */
8944 ret = 20 - ret;
8945#endif
bellard31e31b82003-02-18 22:55:36 +00008946 break;
8947 case TARGET_NR_setpriority:
8948 ret = get_errno(setpriority(arg1, arg2, arg3));
8949 break;
bellardebc05482003-09-30 21:08:41 +00008950#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008951 case TARGET_NR_profil:
8952 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008953#endif
bellard31e31b82003-02-18 22:55:36 +00008954 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008955 if (!(p = lock_user_string(arg1)))
8956 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008957 ret = get_errno(statfs(path(p), &stfs));
8958 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008959 convert_statfs:
8960 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008961 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008962
bellard579a97f2007-11-11 14:26:47 +00008963 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8964 goto efault;
8965 __put_user(stfs.f_type, &target_stfs->f_type);
8966 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8967 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8968 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8969 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8970 __put_user(stfs.f_files, &target_stfs->f_files);
8971 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8972 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8973 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8974 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008975 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8976 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008977 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008978 }
8979 break;
8980 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008981 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008982 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008983#ifdef TARGET_NR_statfs64
8984 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008985 if (!(p = lock_user_string(arg1)))
8986 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008987 ret = get_errno(statfs(path(p), &stfs));
8988 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008989 convert_statfs64:
8990 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008991 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008992
bellard579a97f2007-11-11 14:26:47 +00008993 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8994 goto efault;
8995 __put_user(stfs.f_type, &target_stfs->f_type);
8996 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8997 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8998 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8999 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9000 __put_user(stfs.f_files, &target_stfs->f_files);
9001 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9002 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9003 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9004 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009005 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9006 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009007 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009008 }
9009 break;
9010 case TARGET_NR_fstatfs64:
9011 ret = get_errno(fstatfs(arg1, &stfs));
9012 goto convert_statfs64;
9013#endif
bellardebc05482003-09-30 21:08:41 +00009014#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009015 case TARGET_NR_ioperm:
9016 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009017#endif
thse5febef2007-04-01 18:31:35 +00009018#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009019 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009020 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009021 break;
thse5febef2007-04-01 18:31:35 +00009022#endif
bellard3532fa72006-06-24 15:06:03 +00009023#ifdef TARGET_NR_accept
9024 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009025 ret = do_accept4(arg1, arg2, arg3, 0);
9026 break;
9027#endif
9028#ifdef TARGET_NR_accept4
9029 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009030 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009031 break;
9032#endif
9033#ifdef TARGET_NR_bind
9034 case TARGET_NR_bind:
9035 ret = do_bind(arg1, arg2, arg3);
9036 break;
9037#endif
9038#ifdef TARGET_NR_connect
9039 case TARGET_NR_connect:
9040 ret = do_connect(arg1, arg2, arg3);
9041 break;
9042#endif
9043#ifdef TARGET_NR_getpeername
9044 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009045 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009046 break;
9047#endif
9048#ifdef TARGET_NR_getsockname
9049 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009050 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009051 break;
9052#endif
9053#ifdef TARGET_NR_getsockopt
9054 case TARGET_NR_getsockopt:
9055 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9056 break;
9057#endif
9058#ifdef TARGET_NR_listen
9059 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009060 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009061 break;
9062#endif
9063#ifdef TARGET_NR_recv
9064 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009065 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009066 break;
9067#endif
9068#ifdef TARGET_NR_recvfrom
9069 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009070 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009071 break;
9072#endif
9073#ifdef TARGET_NR_recvmsg
9074 case TARGET_NR_recvmsg:
9075 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9076 break;
9077#endif
9078#ifdef TARGET_NR_send
9079 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009080 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009081 break;
9082#endif
9083#ifdef TARGET_NR_sendmsg
9084 case TARGET_NR_sendmsg:
9085 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9086 break;
9087#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009088#ifdef TARGET_NR_sendmmsg
9089 case TARGET_NR_sendmmsg:
9090 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9091 break;
9092 case TARGET_NR_recvmmsg:
9093 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9094 break;
9095#endif
bellard3532fa72006-06-24 15:06:03 +00009096#ifdef TARGET_NR_sendto
9097 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009098 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009099 break;
9100#endif
9101#ifdef TARGET_NR_shutdown
9102 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009103 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009104 break;
9105#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009106#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9107 case TARGET_NR_getrandom:
9108 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9109 if (!p) {
9110 goto efault;
9111 }
9112 ret = get_errno(getrandom(p, arg2, arg3));
9113 unlock_user(p, arg1, ret);
9114 break;
9115#endif
bellard3532fa72006-06-24 15:06:03 +00009116#ifdef TARGET_NR_socket
9117 case TARGET_NR_socket:
9118 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02009119 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00009120 break;
9121#endif
9122#ifdef TARGET_NR_socketpair
9123 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009124 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009125 break;
9126#endif
9127#ifdef TARGET_NR_setsockopt
9128 case TARGET_NR_setsockopt:
9129 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9130 break;
9131#endif
ths7494b0f2007-02-11 18:26:53 +00009132
bellard31e31b82003-02-18 22:55:36 +00009133 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00009134 if (!(p = lock_user_string(arg2)))
9135 goto efault;
thse5574482007-02-11 20:03:13 +00009136 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9137 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00009138 break;
9139
bellard31e31b82003-02-18 22:55:36 +00009140 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009141 {
bellard66fb9762003-03-23 01:06:05 +00009142 struct itimerval value, ovalue, *pvalue;
9143
pbrook53a59602006-03-25 19:31:22 +00009144 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009145 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009146 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9147 || copy_from_user_timeval(&pvalue->it_value,
9148 arg2 + sizeof(struct target_timeval)))
9149 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009150 } else {
9151 pvalue = NULL;
9152 }
9153 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009154 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009155 if (copy_to_user_timeval(arg3,
9156 &ovalue.it_interval)
9157 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9158 &ovalue.it_value))
9159 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009160 }
9161 }
9162 break;
bellard31e31b82003-02-18 22:55:36 +00009163 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009164 {
bellard66fb9762003-03-23 01:06:05 +00009165 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009166
bellard66fb9762003-03-23 01:06:05 +00009167 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009168 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009169 if (copy_to_user_timeval(arg2,
9170 &value.it_interval)
9171 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9172 &value.it_value))
9173 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009174 }
9175 }
9176 break;
Chen Gang704eff62015-08-21 05:37:33 +08009177#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009178 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009179 if (!(p = lock_user_string(arg1)))
9180 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009181 ret = get_errno(stat(path(p), &st));
9182 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009183 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009184#endif
9185#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009186 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009187 if (!(p = lock_user_string(arg1)))
9188 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009189 ret = get_errno(lstat(path(p), &st));
9190 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009191 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009192#endif
bellard31e31b82003-02-18 22:55:36 +00009193 case TARGET_NR_fstat:
9194 {
9195 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009196#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009197 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009198#endif
bellard31e31b82003-02-18 22:55:36 +00009199 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009200 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009201
bellard579a97f2007-11-11 14:26:47 +00009202 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9203 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009204 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009205 __put_user(st.st_dev, &target_st->st_dev);
9206 __put_user(st.st_ino, &target_st->st_ino);
9207 __put_user(st.st_mode, &target_st->st_mode);
9208 __put_user(st.st_uid, &target_st->st_uid);
9209 __put_user(st.st_gid, &target_st->st_gid);
9210 __put_user(st.st_nlink, &target_st->st_nlink);
9211 __put_user(st.st_rdev, &target_st->st_rdev);
9212 __put_user(st.st_size, &target_st->st_size);
9213 __put_user(st.st_blksize, &target_st->st_blksize);
9214 __put_user(st.st_blocks, &target_st->st_blocks);
9215 __put_user(st.st_atime, &target_st->target_st_atime);
9216 __put_user(st.st_mtime, &target_st->target_st_mtime);
9217 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009218 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009219 }
9220 }
9221 break;
bellardebc05482003-09-30 21:08:41 +00009222#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009223 case TARGET_NR_olduname:
9224 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009225#endif
9226#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009227 case TARGET_NR_iopl:
9228 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009229#endif
bellard31e31b82003-02-18 22:55:36 +00009230 case TARGET_NR_vhangup:
9231 ret = get_errno(vhangup());
9232 break;
bellardebc05482003-09-30 21:08:41 +00009233#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009234 case TARGET_NR_idle:
9235 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009236#endif
bellard42ad6ae2005-01-03 22:48:11 +00009237#ifdef TARGET_NR_syscall
9238 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009239 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9240 arg6, arg7, arg8, 0);
9241 break;
bellard42ad6ae2005-01-03 22:48:11 +00009242#endif
bellard31e31b82003-02-18 22:55:36 +00009243 case TARGET_NR_wait4:
9244 {
9245 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009246 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009247 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009248 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009249 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009250 if (target_rusage)
9251 rusage_ptr = &rusage;
9252 else
9253 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009254 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009255 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009256 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009257 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009258 if (put_user_s32(status, status_ptr))
9259 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009260 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009261 if (target_rusage) {
9262 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9263 if (rusage_err) {
9264 ret = rusage_err;
9265 }
9266 }
bellard31e31b82003-02-18 22:55:36 +00009267 }
9268 }
9269 break;
thse5febef2007-04-01 18:31:35 +00009270#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009271 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009272 if (!(p = lock_user_string(arg1)))
9273 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009274 ret = get_errno(swapoff(p));
9275 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009276 break;
thse5febef2007-04-01 18:31:35 +00009277#endif
bellard31e31b82003-02-18 22:55:36 +00009278 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009279 {
pbrook53a59602006-03-25 19:31:22 +00009280 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009281 struct sysinfo value;
9282 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009283 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009284 {
bellard579a97f2007-11-11 14:26:47 +00009285 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9286 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009287 __put_user(value.uptime, &target_value->uptime);
9288 __put_user(value.loads[0], &target_value->loads[0]);
9289 __put_user(value.loads[1], &target_value->loads[1]);
9290 __put_user(value.loads[2], &target_value->loads[2]);
9291 __put_user(value.totalram, &target_value->totalram);
9292 __put_user(value.freeram, &target_value->freeram);
9293 __put_user(value.sharedram, &target_value->sharedram);
9294 __put_user(value.bufferram, &target_value->bufferram);
9295 __put_user(value.totalswap, &target_value->totalswap);
9296 __put_user(value.freeswap, &target_value->freeswap);
9297 __put_user(value.procs, &target_value->procs);
9298 __put_user(value.totalhigh, &target_value->totalhigh);
9299 __put_user(value.freehigh, &target_value->freehigh);
9300 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009301 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009302 }
9303 }
9304 break;
thse5febef2007-04-01 18:31:35 +00009305#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009306 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00009307 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
9308 break;
thse5febef2007-04-01 18:31:35 +00009309#endif
aurel32e5289082009-04-18 16:16:12 +00009310#ifdef TARGET_NR_semget
9311 case TARGET_NR_semget:
9312 ret = get_errno(semget(arg1, arg2, arg3));
9313 break;
9314#endif
9315#ifdef TARGET_NR_semop
9316 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009317 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009318 break;
9319#endif
9320#ifdef TARGET_NR_semctl
9321 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009322 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009323 break;
9324#endif
aurel32eeb438c2008-10-13 21:08:55 +00009325#ifdef TARGET_NR_msgctl
9326 case TARGET_NR_msgctl:
9327 ret = do_msgctl(arg1, arg2, arg3);
9328 break;
9329#endif
9330#ifdef TARGET_NR_msgget
9331 case TARGET_NR_msgget:
9332 ret = get_errno(msgget(arg1, arg2));
9333 break;
9334#endif
9335#ifdef TARGET_NR_msgrcv
9336 case TARGET_NR_msgrcv:
9337 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9338 break;
9339#endif
9340#ifdef TARGET_NR_msgsnd
9341 case TARGET_NR_msgsnd:
9342 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9343 break;
9344#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009345#ifdef TARGET_NR_shmget
9346 case TARGET_NR_shmget:
9347 ret = get_errno(shmget(arg1, arg2, arg3));
9348 break;
9349#endif
9350#ifdef TARGET_NR_shmctl
9351 case TARGET_NR_shmctl:
9352 ret = do_shmctl(arg1, arg2, arg3);
9353 break;
9354#endif
9355#ifdef TARGET_NR_shmat
9356 case TARGET_NR_shmat:
9357 ret = do_shmat(arg1, arg2, arg3);
9358 break;
9359#endif
9360#ifdef TARGET_NR_shmdt
9361 case TARGET_NR_shmdt:
9362 ret = do_shmdt(arg1);
9363 break;
9364#endif
bellard31e31b82003-02-18 22:55:36 +00009365 case TARGET_NR_fsync:
9366 ret = get_errno(fsync(arg1));
9367 break;
bellard31e31b82003-02-18 22:55:36 +00009368 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009369 /* Linux manages to have three different orderings for its
9370 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9371 * match the kernel's CONFIG_CLONE_* settings.
9372 * Microblaze is further special in that it uses a sixth
9373 * implicit argument to clone for the TLS pointer.
9374 */
9375#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009376 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009377#elif defined(TARGET_CLONE_BACKWARDS)
9378 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9379#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009380 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009381#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009382 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009383#endif
bellard1b6b0292003-03-22 17:31:38 +00009384 break;
bellardec86b0f2003-04-11 00:15:04 +00009385#ifdef __NR_exit_group
9386 /* new thread calls */
9387 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02009388#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00009389 _mcleanup();
9390#endif
bellarde9009672005-04-26 20:42:36 +00009391 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00009392 ret = get_errno(exit_group(arg1));
9393 break;
9394#endif
bellard31e31b82003-02-18 22:55:36 +00009395 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009396 if (!(p = lock_user_string(arg1)))
9397 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009398 ret = get_errno(setdomainname(p, arg2));
9399 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009400 break;
9401 case TARGET_NR_uname:
9402 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009403 {
9404 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009405
bellard579a97f2007-11-11 14:26:47 +00009406 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
9407 goto efault;
bellard29e619b2004-09-13 21:41:04 +00009408 ret = get_errno(sys_uname(buf));
9409 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009410 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009411 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01009412 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00009413 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009414 if (qemu_uname_release && *qemu_uname_release) {
9415 g_strlcpy(buf->release, qemu_uname_release,
9416 sizeof(buf->release));
9417 }
bellard29e619b2004-09-13 21:41:04 +00009418 }
pbrook53a59602006-03-25 19:31:22 +00009419 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009420 }
bellard31e31b82003-02-18 22:55:36 +00009421 break;
bellard6dbad632003-03-16 18:05:05 +00009422#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009423 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00009424 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00009425 break;
j_mayer84409dd2007-04-06 08:56:50 +00009426#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009427 case TARGET_NR_vm86old:
9428 goto unimplemented;
9429 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00009430 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009431 break;
9432#endif
j_mayer84409dd2007-04-06 08:56:50 +00009433#endif
bellard31e31b82003-02-18 22:55:36 +00009434 case TARGET_NR_adjtimex:
9435 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009436#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00009437 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00009438#endif
bellard31e31b82003-02-18 22:55:36 +00009439 case TARGET_NR_init_module:
9440 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00009441#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00009442 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00009443#endif
bellard31e31b82003-02-18 22:55:36 +00009444 goto unimplemented;
9445 case TARGET_NR_quotactl:
9446 goto unimplemented;
9447 case TARGET_NR_getpgid:
9448 ret = get_errno(getpgid(arg1));
9449 break;
9450 case TARGET_NR_fchdir:
9451 ret = get_errno(fchdir(arg1));
9452 break;
j_mayer84409dd2007-04-06 08:56:50 +00009453#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00009454 case TARGET_NR_bdflush:
9455 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00009456#endif
thse5febef2007-04-01 18:31:35 +00009457#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00009458 case TARGET_NR_sysfs:
9459 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009460#endif
bellard31e31b82003-02-18 22:55:36 +00009461 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00009462 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00009463 break;
thse5febef2007-04-01 18:31:35 +00009464#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00009465 case TARGET_NR_afs_syscall:
9466 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009467#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009468#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009469 case TARGET_NR__llseek:
9470 {
9471 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009472#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +01009473 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +00009474 if (res == -1) {
9475 ret = get_errno(res);
9476 } else {
9477 ret = 0;
9478 }
9479#else
bellard31e31b82003-02-18 22:55:36 +00009480 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00009481#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00009482 if ((ret == 0) && put_user_s64(res, arg4)) {
9483 goto efault;
9484 }
bellard31e31b82003-02-18 22:55:36 +00009485 }
9486 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009487#endif
Chen Gang704eff62015-08-21 05:37:33 +08009488#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00009489 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01009490#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02009491#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00009492 {
pbrook53a59602006-03-25 19:31:22 +00009493 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00009494 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009495 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00009496
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309497 dirp = g_try_malloc(count);
9498 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00009499 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00009500 goto fail;
9501 }
ths3b46e622007-09-17 08:09:54 +00009502
bellard4add45b2003-06-05 01:52:59 +00009503 ret = get_errno(sys_getdents(arg1, dirp, count));
9504 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009505 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00009506 struct target_dirent *tde;
9507 int len = ret;
9508 int reclen, treclen;
9509 int count1, tnamelen;
9510
9511 count1 = 0;
9512 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00009513 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9514 goto efault;
bellard4add45b2003-06-05 01:52:59 +00009515 tde = target_dirp;
9516 while (len > 0) {
9517 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009518 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
9519 assert(tnamelen >= 0);
9520 treclen = tnamelen + offsetof(struct target_dirent, d_name);
9521 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00009522 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009523 tde->d_ino = tswapal(de->d_ino);
9524 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009525 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009526 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009527 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009528 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009529 count1 += treclen;
9530 }
9531 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009532 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009533 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309534 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009535 }
9536#else
bellard31e31b82003-02-18 22:55:36 +00009537 {
aurel326556a832008-10-13 21:08:17 +00009538 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009539 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009540
bellard579a97f2007-11-11 14:26:47 +00009541 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9542 goto efault;
bellard72f03902003-02-18 23:33:18 +00009543 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009544 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009545 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00009546 int len = ret;
9547 int reclen;
9548 de = dirp;
9549 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009550 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009551 if (reclen > len)
9552 break;
bellard8083a3e2003-03-24 23:12:16 +00009553 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009554 tswapls(&de->d_ino);
9555 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009556 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009557 len -= reclen;
9558 }
9559 }
pbrook53a59602006-03-25 19:31:22 +00009560 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009561 }
bellard4add45b2003-06-05 01:52:59 +00009562#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009563#else
9564 /* Implement getdents in terms of getdents64 */
9565 {
9566 struct linux_dirent64 *dirp;
9567 abi_long count = arg3;
9568
9569 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9570 if (!dirp) {
9571 goto efault;
9572 }
9573 ret = get_errno(sys_getdents64(arg1, dirp, count));
9574 if (!is_error(ret)) {
9575 /* Convert the dirent64 structs to target dirent. We do this
9576 * in-place, since we can guarantee that a target_dirent is no
9577 * larger than a dirent64; however this means we have to be
9578 * careful to read everything before writing in the new format.
9579 */
9580 struct linux_dirent64 *de;
9581 struct target_dirent *tde;
9582 int len = ret;
9583 int tlen = 0;
9584
9585 de = dirp;
9586 tde = (struct target_dirent *)dirp;
9587 while (len > 0) {
9588 int namelen, treclen;
9589 int reclen = de->d_reclen;
9590 uint64_t ino = de->d_ino;
9591 int64_t off = de->d_off;
9592 uint8_t type = de->d_type;
9593
9594 namelen = strlen(de->d_name);
9595 treclen = offsetof(struct target_dirent, d_name)
9596 + namelen + 2;
9597 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9598
9599 memmove(tde->d_name, de->d_name, namelen + 1);
9600 tde->d_ino = tswapal(ino);
9601 tde->d_off = tswapal(off);
9602 tde->d_reclen = tswap16(treclen);
9603 /* The target_dirent type is in what was formerly a padding
9604 * byte at the end of the structure:
9605 */
9606 *(((char *)tde) + treclen - 1) = type;
9607
9608 de = (struct linux_dirent64 *)((char *)de + reclen);
9609 tde = (struct target_dirent *)((char *)tde + treclen);
9610 len -= reclen;
9611 tlen += treclen;
9612 }
9613 ret = tlen;
9614 }
9615 unlock_user(dirp, arg2, ret);
9616 }
9617#endif
bellard31e31b82003-02-18 22:55:36 +00009618 break;
Chen Gang704eff62015-08-21 05:37:33 +08009619#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009620#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009621 case TARGET_NR_getdents64:
9622 {
aurel326556a832008-10-13 21:08:17 +00009623 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009624 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009625 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9626 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009627 ret = get_errno(sys_getdents64(arg1, dirp, count));
9628 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009629 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009630 int len = ret;
9631 int reclen;
9632 de = dirp;
9633 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009634 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009635 if (reclen > len)
9636 break;
bellard8083a3e2003-03-24 23:12:16 +00009637 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009638 tswap64s((uint64_t *)&de->d_ino);
9639 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009640 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009641 len -= reclen;
9642 }
9643 }
pbrook53a59602006-03-25 19:31:22 +00009644 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009645 }
9646 break;
bellarda541f292004-04-12 20:39:29 +00009647#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009648#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009649 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009650 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009651 break;
thse5febef2007-04-01 18:31:35 +00009652#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009653#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9654# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009655 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009656# endif
9657# ifdef TARGET_NR_ppoll
9658 case TARGET_NR_ppoll:
9659# endif
bellard9de5e442003-03-23 16:49:39 +00009660 {
pbrook53a59602006-03-25 19:31:22 +00009661 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009662 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009663 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009664 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009665
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009666 pfd = NULL;
9667 target_pfd = NULL;
9668 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +01009669 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
9670 ret = -TARGET_EINVAL;
9671 break;
9672 }
9673
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009674 target_pfd = lock_user(VERIFY_WRITE, arg1,
9675 sizeof(struct target_pollfd) * nfds, 1);
9676 if (!target_pfd) {
9677 goto efault;
9678 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009679
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009680 pfd = alloca(sizeof(struct pollfd) * nfds);
9681 for (i = 0; i < nfds; i++) {
9682 pfd[i].fd = tswap32(target_pfd[i].fd);
9683 pfd[i].events = tswap16(target_pfd[i].events);
9684 }
bellard9de5e442003-03-23 16:49:39 +00009685 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009686
Peter Maydella6130232016-06-06 19:58:10 +01009687 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009688# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009689 case TARGET_NR_ppoll:
9690 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009691 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9692 target_sigset_t *target_set;
9693 sigset_t _set, *set = &_set;
9694
9695 if (arg3) {
9696 if (target_to_host_timespec(timeout_ts, arg3)) {
9697 unlock_user(target_pfd, arg1, 0);
9698 goto efault;
9699 }
9700 } else {
9701 timeout_ts = NULL;
9702 }
9703
9704 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +01009705 if (arg5 != sizeof(target_sigset_t)) {
9706 unlock_user(target_pfd, arg1, 0);
9707 ret = -TARGET_EINVAL;
9708 break;
9709 }
9710
Mike Frysingerd8035d42011-02-07 01:05:51 -05009711 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9712 if (!target_set) {
9713 unlock_user(target_pfd, arg1, 0);
9714 goto efault;
9715 }
9716 target_to_host_sigset(set, target_set);
9717 } else {
9718 set = NULL;
9719 }
9720
Peter Maydella6130232016-06-06 19:58:10 +01009721 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9722 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009723
9724 if (!is_error(ret) && arg3) {
9725 host_to_target_timespec(arg3, timeout_ts);
9726 }
9727 if (arg4) {
9728 unlock_user(target_set, arg4, 0);
9729 }
Peter Maydella6130232016-06-06 19:58:10 +01009730 break;
9731 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009732# endif
Peter Maydella6130232016-06-06 19:58:10 +01009733# ifdef TARGET_NR_poll
9734 case TARGET_NR_poll:
9735 {
9736 struct timespec ts, *pts;
9737
9738 if (arg3 >= 0) {
9739 /* Convert ms to secs, ns */
9740 ts.tv_sec = arg3 / 1000;
9741 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9742 pts = &ts;
9743 } else {
9744 /* -ve poll() timeout means "infinite" */
9745 pts = NULL;
9746 }
9747 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9748 break;
9749 }
9750# endif
9751 default:
9752 g_assert_not_reached();
9753 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009754
bellard9de5e442003-03-23 16:49:39 +00009755 if (!is_error(ret)) {
9756 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009757 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009758 }
9759 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009760 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009761 }
9762 break;
thse5febef2007-04-01 18:31:35 +00009763#endif
bellard31e31b82003-02-18 22:55:36 +00009764 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009765 /* NOTE: the flock constant seems to be the same for every
9766 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009767 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009768 break;
9769 case TARGET_NR_readv:
9770 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009771 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9772 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009773 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009774 unlock_iovec(vec, arg2, arg3, 1);
9775 } else {
9776 ret = -host_to_target_errno(errno);
9777 }
bellard31e31b82003-02-18 22:55:36 +00009778 }
9779 break;
9780 case TARGET_NR_writev:
9781 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009782 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9783 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009784 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009785 unlock_iovec(vec, arg2, arg3, 0);
9786 } else {
9787 ret = -host_to_target_errno(errno);
9788 }
bellard31e31b82003-02-18 22:55:36 +00009789 }
9790 break;
9791 case TARGET_NR_getsid:
9792 ret = get_errno(getsid(arg1));
9793 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009794#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009795 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009796 ret = get_errno(fdatasync(arg1));
9797 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009798#endif
Chen Gang704eff62015-08-21 05:37:33 +08009799#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009800 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009801 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009802 return value. */
ths0da46a62007-10-20 20:23:07 +00009803 ret = -TARGET_ENOTDIR;
9804 break;
Chen Gang704eff62015-08-21 05:37:33 +08009805#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009806 case TARGET_NR_sched_getaffinity:
9807 {
9808 unsigned int mask_size;
9809 unsigned long *mask;
9810
9811 /*
9812 * sched_getaffinity needs multiples of ulong, so need to take
9813 * care of mismatches between target ulong and host ulong sizes.
9814 */
9815 if (arg2 & (sizeof(abi_ulong) - 1)) {
9816 ret = -TARGET_EINVAL;
9817 break;
9818 }
9819 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9820
9821 mask = alloca(mask_size);
9822 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9823
9824 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009825 if (ret > arg2) {
9826 /* More data returned than the caller's buffer will fit.
9827 * This only happens if sizeof(abi_long) < sizeof(long)
9828 * and the caller passed us a buffer holding an odd number
9829 * of abi_longs. If the host kernel is actually using the
9830 * extra 4 bytes then fail EINVAL; otherwise we can just
9831 * ignore them and only copy the interesting part.
9832 */
9833 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9834 if (numcpus > arg2 * 8) {
9835 ret = -TARGET_EINVAL;
9836 break;
9837 }
9838 ret = arg2;
9839 }
9840
Mike McCormackcd18f052011-04-18 14:43:36 +09009841 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009842 goto efault;
9843 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009844 }
9845 }
9846 break;
9847 case TARGET_NR_sched_setaffinity:
9848 {
9849 unsigned int mask_size;
9850 unsigned long *mask;
9851
9852 /*
9853 * sched_setaffinity needs multiples of ulong, so need to take
9854 * care of mismatches between target ulong and host ulong sizes.
9855 */
9856 if (arg2 & (sizeof(abi_ulong) - 1)) {
9857 ret = -TARGET_EINVAL;
9858 break;
9859 }
9860 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9861
9862 mask = alloca(mask_size);
9863 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9864 goto efault;
9865 }
9866 memcpy(mask, p, arg2);
9867 unlock_user_struct(p, arg2, 0);
9868
9869 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9870 }
9871 break;
bellard31e31b82003-02-18 22:55:36 +00009872 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009873 {
pbrook53a59602006-03-25 19:31:22 +00009874 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009875 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009876
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009877 if (arg2 == 0) {
9878 return -TARGET_EINVAL;
9879 }
bellard579a97f2007-11-11 14:26:47 +00009880 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9881 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009882 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009883 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009884 ret = get_errno(sched_setparam(arg1, &schp));
9885 }
9886 break;
bellard31e31b82003-02-18 22:55:36 +00009887 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009888 {
pbrook53a59602006-03-25 19:31:22 +00009889 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009890 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009891
9892 if (arg2 == 0) {
9893 return -TARGET_EINVAL;
9894 }
bellard5cd43932003-03-29 16:54:36 +00009895 ret = get_errno(sched_getparam(arg1, &schp));
9896 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009897 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9898 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009899 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009900 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009901 }
9902 }
9903 break;
bellard31e31b82003-02-18 22:55:36 +00009904 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009905 {
pbrook53a59602006-03-25 19:31:22 +00009906 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009907 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009908 if (arg3 == 0) {
9909 return -TARGET_EINVAL;
9910 }
bellard579a97f2007-11-11 14:26:47 +00009911 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9912 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009913 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009914 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009915 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9916 }
9917 break;
bellard31e31b82003-02-18 22:55:36 +00009918 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009919 ret = get_errno(sched_getscheduler(arg1));
9920 break;
bellard31e31b82003-02-18 22:55:36 +00009921 case TARGET_NR_sched_yield:
9922 ret = get_errno(sched_yield());
9923 break;
9924 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009925 ret = get_errno(sched_get_priority_max(arg1));
9926 break;
bellard31e31b82003-02-18 22:55:36 +00009927 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009928 ret = get_errno(sched_get_priority_min(arg1));
9929 break;
bellard31e31b82003-02-18 22:55:36 +00009930 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009931 {
bellard5cd43932003-03-29 16:54:36 +00009932 struct timespec ts;
9933 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9934 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009935 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009936 }
9937 }
9938 break;
bellard31e31b82003-02-18 22:55:36 +00009939 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009940 {
bellard1b6b0292003-03-22 17:31:38 +00009941 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009942 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009943 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009944 if (is_error(ret) && arg2) {
9945 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009946 }
9947 }
9948 break;
thse5febef2007-04-01 18:31:35 +00009949#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009950 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009951 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009952#endif
9953#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009954 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009955 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009956#endif
bellard31e31b82003-02-18 22:55:36 +00009957 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009958 switch (arg1) {
9959 case PR_GET_PDEATHSIG:
9960 {
9961 int deathsig;
9962 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9963 if (!is_error(ret) && arg2
9964 && put_user_ual(deathsig, arg2)) {
9965 goto efault;
thse5574482007-02-11 20:03:13 +00009966 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009967 break;
9968 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009969#ifdef PR_GET_NAME
9970 case PR_GET_NAME:
9971 {
9972 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9973 if (!name) {
9974 goto efault;
9975 }
9976 ret = get_errno(prctl(arg1, (unsigned long)name,
9977 arg3, arg4, arg5));
9978 unlock_user(name, arg2, 16);
9979 break;
9980 }
9981 case PR_SET_NAME:
9982 {
9983 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9984 if (!name) {
9985 goto efault;
9986 }
9987 ret = get_errno(prctl(arg1, (unsigned long)name,
9988 arg3, arg4, arg5));
9989 unlock_user(name, arg2, 0);
9990 break;
9991 }
9992#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009993 default:
9994 /* Most prctl options have no pointer arguments */
9995 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9996 break;
9997 }
ths39b9aae2007-02-11 18:36:44 +00009998 break;
bellardd2fd1af2007-11-14 18:08:56 +00009999#ifdef TARGET_NR_arch_prctl
10000 case TARGET_NR_arch_prctl:
10001#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10002 ret = do_arch_prctl(cpu_env, arg1, arg2);
10003 break;
10004#else
10005 goto unimplemented;
10006#endif
10007#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010008#ifdef TARGET_NR_pread64
10009 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +000010010 if (regpairs_aligned(cpu_env)) {
10011 arg4 = arg5;
10012 arg5 = arg6;
10013 }
aurel32f2c7ba12008-03-28 22:32:06 +000010014 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10015 goto efault;
10016 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10017 unlock_user(p, arg2, ret);
10018 break;
10019 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +000010020 if (regpairs_aligned(cpu_env)) {
10021 arg4 = arg5;
10022 arg5 = arg6;
10023 }
aurel32f2c7ba12008-03-28 22:32:06 +000010024 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10025 goto efault;
10026 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10027 unlock_user(p, arg2, 0);
10028 break;
10029#endif
bellard31e31b82003-02-18 22:55:36 +000010030 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010031 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10032 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010033 ret = get_errno(sys_getcwd1(p, arg2));
10034 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010035 break;
10036 case TARGET_NR_capget:
10037 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010038 {
10039 struct target_user_cap_header *target_header;
10040 struct target_user_cap_data *target_data = NULL;
10041 struct __user_cap_header_struct header;
10042 struct __user_cap_data_struct data[2];
10043 struct __user_cap_data_struct *dataptr = NULL;
10044 int i, target_datalen;
10045 int data_items = 1;
10046
10047 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10048 goto efault;
10049 }
10050 header.version = tswap32(target_header->version);
10051 header.pid = tswap32(target_header->pid);
10052
Peter Maydellec864872014-03-19 16:07:30 +000010053 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010054 /* Version 2 and up takes pointer to two user_data structs */
10055 data_items = 2;
10056 }
10057
10058 target_datalen = sizeof(*target_data) * data_items;
10059
10060 if (arg2) {
10061 if (num == TARGET_NR_capget) {
10062 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10063 } else {
10064 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10065 }
10066 if (!target_data) {
10067 unlock_user_struct(target_header, arg1, 0);
10068 goto efault;
10069 }
10070
10071 if (num == TARGET_NR_capset) {
10072 for (i = 0; i < data_items; i++) {
10073 data[i].effective = tswap32(target_data[i].effective);
10074 data[i].permitted = tswap32(target_data[i].permitted);
10075 data[i].inheritable = tswap32(target_data[i].inheritable);
10076 }
10077 }
10078
10079 dataptr = data;
10080 }
10081
10082 if (num == TARGET_NR_capget) {
10083 ret = get_errno(capget(&header, dataptr));
10084 } else {
10085 ret = get_errno(capset(&header, dataptr));
10086 }
10087
10088 /* The kernel always updates version for both capget and capset */
10089 target_header->version = tswap32(header.version);
10090 unlock_user_struct(target_header, arg1, 1);
10091
10092 if (arg2) {
10093 if (num == TARGET_NR_capget) {
10094 for (i = 0; i < data_items; i++) {
10095 target_data[i].effective = tswap32(data[i].effective);
10096 target_data[i].permitted = tswap32(data[i].permitted);
10097 target_data[i].inheritable = tswap32(data[i].inheritable);
10098 }
10099 unlock_user(target_data, arg2, target_datalen);
10100 } else {
10101 unlock_user(target_data, arg2, 0);
10102 }
10103 }
10104 break;
10105 }
bellard31e31b82003-02-18 22:55:36 +000010106 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010107 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010108 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010109
10110#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010111 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010112 {
10113 off_t *offp = NULL;
10114 off_t off;
10115 if (arg3) {
10116 ret = get_user_sal(off, arg3);
10117 if (is_error(ret)) {
10118 break;
10119 }
10120 offp = &off;
10121 }
10122 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10123 if (!is_error(ret) && arg3) {
10124 abi_long ret2 = put_user_sal(off, arg3);
10125 if (is_error(ret2)) {
10126 ret = ret2;
10127 }
10128 }
10129 break;
10130 }
10131#ifdef TARGET_NR_sendfile64
10132 case TARGET_NR_sendfile64:
10133 {
10134 off_t *offp = NULL;
10135 off_t off;
10136 if (arg3) {
10137 ret = get_user_s64(off, arg3);
10138 if (is_error(ret)) {
10139 break;
10140 }
10141 offp = &off;
10142 }
10143 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10144 if (!is_error(ret) && arg3) {
10145 abi_long ret2 = put_user_s64(off, arg3);
10146 if (is_error(ret2)) {
10147 ret = ret2;
10148 }
10149 }
10150 break;
10151 }
10152#endif
10153#else
10154 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010155#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010156 case TARGET_NR_sendfile64:
10157#endif
bellard5cd43932003-03-29 16:54:36 +000010158 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010159#endif
10160
bellardebc05482003-09-30 21:08:41 +000010161#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010162 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010163 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010164#endif
10165#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010166 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010167 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010168#endif
bellard048f6b42005-11-26 18:47:20 +000010169#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010170 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +000010171 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
10172 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010173 break;
bellard048f6b42005-11-26 18:47:20 +000010174#endif
bellardebc05482003-09-30 21:08:41 +000010175#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010176 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010177 {
10178 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010179 int resource = target_to_host_resource(arg1);
10180 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010181 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010182 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010183 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10184 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010185 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10186 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010187 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010188 }
10189 break;
10190 }
bellardebc05482003-09-30 21:08:41 +000010191#endif
bellarda315a142005-01-30 22:59:18 +000010192#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010193 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010194 if (!(p = lock_user_string(arg1)))
10195 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010196 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10197 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010198 break;
bellarda315a142005-01-30 22:59:18 +000010199#endif
10200#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010201 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010202 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010203 break;
bellarda315a142005-01-30 22:59:18 +000010204#endif
10205#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010206 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010207 if (!(p = lock_user_string(arg1)))
10208 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010209 ret = get_errno(stat(path(p), &st));
10210 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010211 if (!is_error(ret))
10212 ret = host_to_target_stat64(cpu_env, arg2, &st);
10213 break;
bellarda315a142005-01-30 22:59:18 +000010214#endif
10215#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010216 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010217 if (!(p = lock_user_string(arg1)))
10218 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010219 ret = get_errno(lstat(path(p), &st));
10220 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010221 if (!is_error(ret))
10222 ret = host_to_target_stat64(cpu_env, arg2, &st);
10223 break;
bellarda315a142005-01-30 22:59:18 +000010224#endif
10225#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010226 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010227 ret = get_errno(fstat(arg1, &st));
10228 if (!is_error(ret))
10229 ret = host_to_target_stat64(cpu_env, arg2, &st);
10230 break;
bellardec86b0f2003-04-11 00:15:04 +000010231#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010232#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010233#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010234 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010235#endif
10236#ifdef TARGET_NR_newfstatat
10237 case TARGET_NR_newfstatat:
10238#endif
balrog6a24a772008-09-20 02:23:36 +000010239 if (!(p = lock_user_string(arg2)))
10240 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010241 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010242 if (!is_error(ret))
10243 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010244 break;
bellarda315a142005-01-30 22:59:18 +000010245#endif
Chen Gang704eff62015-08-21 05:37:33 +080010246#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010247 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010248 if (!(p = lock_user_string(arg1)))
10249 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010250 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10251 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010252 break;
Chen Gang704eff62015-08-21 05:37:33 +080010253#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010254#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010255 case TARGET_NR_getuid:
10256 ret = get_errno(high2lowuid(getuid()));
10257 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010258#endif
10259#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010260 case TARGET_NR_getgid:
10261 ret = get_errno(high2lowgid(getgid()));
10262 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010263#endif
10264#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010265 case TARGET_NR_geteuid:
10266 ret = get_errno(high2lowuid(geteuid()));
10267 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010268#endif
10269#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010270 case TARGET_NR_getegid:
10271 ret = get_errno(high2lowgid(getegid()));
10272 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010273#endif
bellard67867302003-11-23 17:05:30 +000010274 case TARGET_NR_setreuid:
10275 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
10276 break;
10277 case TARGET_NR_setregid:
10278 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
10279 break;
10280 case TARGET_NR_getgroups:
10281 {
10282 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010283 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010284 gid_t *grouplist;
10285 int i;
10286
10287 grouplist = alloca(gidsetsize * sizeof(gid_t));
10288 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010289 if (gidsetsize == 0)
10290 break;
bellard67867302003-11-23 17:05:30 +000010291 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010292 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010293 if (!target_grouplist)
10294 goto efault;
balroga2155fc2008-09-20 02:12:08 +000010295 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010296 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010297 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010298 }
10299 }
10300 break;
10301 case TARGET_NR_setgroups:
10302 {
10303 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010304 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010305 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010306 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010307 if (gidsetsize) {
10308 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010309 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010310 if (!target_grouplist) {
10311 ret = -TARGET_EFAULT;
10312 goto fail;
10313 }
10314 for (i = 0; i < gidsetsize; i++) {
10315 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10316 }
10317 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010318 }
bellard67867302003-11-23 17:05:30 +000010319 ret = get_errno(setgroups(gidsetsize, grouplist));
10320 }
10321 break;
10322 case TARGET_NR_fchown:
10323 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
10324 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010325#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010326 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010327 if (!(p = lock_user_string(arg2)))
10328 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010329 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10330 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010331 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000010332 break;
10333#endif
bellard67867302003-11-23 17:05:30 +000010334#ifdef TARGET_NR_setresuid
10335 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010336 ret = get_errno(sys_setresuid(low2highuid(arg1),
10337 low2highuid(arg2),
10338 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010339 break;
10340#endif
10341#ifdef TARGET_NR_getresuid
10342 case TARGET_NR_getresuid:
10343 {
pbrook53a59602006-03-25 19:31:22 +000010344 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010345 ret = get_errno(getresuid(&ruid, &euid, &suid));
10346 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010347 if (put_user_id(high2lowuid(ruid), arg1)
10348 || put_user_id(high2lowuid(euid), arg2)
10349 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000010350 goto efault;
bellard67867302003-11-23 17:05:30 +000010351 }
10352 }
10353 break;
10354#endif
10355#ifdef TARGET_NR_getresgid
10356 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010357 ret = get_errno(sys_setresgid(low2highgid(arg1),
10358 low2highgid(arg2),
10359 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010360 break;
10361#endif
10362#ifdef TARGET_NR_getresgid
10363 case TARGET_NR_getresgid:
10364 {
pbrook53a59602006-03-25 19:31:22 +000010365 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010366 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10367 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010368 if (put_user_id(high2lowgid(rgid), arg1)
10369 || put_user_id(high2lowgid(egid), arg2)
10370 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000010371 goto efault;
bellard67867302003-11-23 17:05:30 +000010372 }
10373 }
10374 break;
10375#endif
Chen Gang704eff62015-08-21 05:37:33 +080010376#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000010377 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000010378 if (!(p = lock_user_string(arg1)))
10379 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010380 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
10381 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010382 break;
Chen Gang704eff62015-08-21 05:37:33 +080010383#endif
bellard67867302003-11-23 17:05:30 +000010384 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010385 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000010386 break;
10387 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010388 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000010389 break;
10390 case TARGET_NR_setfsuid:
10391 ret = get_errno(setfsuid(arg1));
10392 break;
10393 case TARGET_NR_setfsgid:
10394 ret = get_errno(setfsgid(arg1));
10395 break;
bellard67867302003-11-23 17:05:30 +000010396
bellarda315a142005-01-30 22:59:18 +000010397#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000010398 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000010399 if (!(p = lock_user_string(arg1)))
10400 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010401 ret = get_errno(lchown(p, arg2, arg3));
10402 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010403 break;
bellarda315a142005-01-30 22:59:18 +000010404#endif
10405#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000010406 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000010407 ret = get_errno(getuid());
10408 break;
bellarda315a142005-01-30 22:59:18 +000010409#endif
aurel3264b4d282008-11-14 17:20:15 +000010410
10411#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
10412 /* Alpha specific */
10413 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010414 {
10415 uid_t euid;
10416 euid=geteuid();
10417 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
10418 }
aurel3264b4d282008-11-14 17:20:15 +000010419 ret = get_errno(getuid());
10420 break;
10421#endif
10422#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
10423 /* Alpha specific */
10424 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010425 {
10426 uid_t egid;
10427 egid=getegid();
10428 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
10429 }
aurel3264b4d282008-11-14 17:20:15 +000010430 ret = get_errno(getgid());
10431 break;
10432#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080010433#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
10434 /* Alpha specific */
10435 case TARGET_NR_osf_getsysinfo:
10436 ret = -TARGET_EOPNOTSUPP;
10437 switch (arg1) {
10438 case TARGET_GSI_IEEE_FP_CONTROL:
10439 {
10440 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
10441
10442 /* Copied from linux ieee_fpcr_to_swcr. */
10443 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
10444 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
10445 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
10446 | SWCR_TRAP_ENABLE_DZE
10447 | SWCR_TRAP_ENABLE_OVF);
10448 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
10449 | SWCR_TRAP_ENABLE_INE);
10450 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
10451 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
10452
10453 if (put_user_u64 (swcr, arg2))
10454 goto efault;
10455 ret = 0;
10456 }
10457 break;
10458
10459 /* case GSI_IEEE_STATE_AT_SIGNAL:
10460 -- Not implemented in linux kernel.
10461 case GSI_UACPROC:
10462 -- Retrieves current unaligned access state; not much used.
10463 case GSI_PROC_TYPE:
10464 -- Retrieves implver information; surely not used.
10465 case GSI_GET_HWRPB:
10466 -- Grabs a copy of the HWRPB; surely not used.
10467 */
10468 }
10469 break;
10470#endif
10471#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
10472 /* Alpha specific */
10473 case TARGET_NR_osf_setsysinfo:
10474 ret = -TARGET_EOPNOTSUPP;
10475 switch (arg1) {
10476 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010477 {
10478 uint64_t swcr, fpcr, orig_fpcr;
10479
Richard Henderson6e06d512012-06-01 09:08:21 -070010480 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080010481 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070010482 }
10483 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010484 fpcr = orig_fpcr & FPCR_DYN_MASK;
10485
10486 /* Copied from linux ieee_swcr_to_fpcr. */
10487 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
10488 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
10489 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
10490 | SWCR_TRAP_ENABLE_DZE
10491 | SWCR_TRAP_ENABLE_OVF)) << 48;
10492 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
10493 | SWCR_TRAP_ENABLE_INE)) << 57;
10494 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
10495 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
10496
Richard Henderson6e06d512012-06-01 09:08:21 -070010497 cpu_alpha_store_fpcr(cpu_env, fpcr);
10498 ret = 0;
10499 }
10500 break;
10501
10502 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
10503 {
10504 uint64_t exc, fpcr, orig_fpcr;
10505 int si_code;
10506
10507 if (get_user_u64(exc, arg2)) {
10508 goto efault;
10509 }
10510
10511 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
10512
10513 /* We only add to the exception status here. */
10514 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
10515
10516 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010517 ret = 0;
10518
Richard Henderson6e06d512012-06-01 09:08:21 -070010519 /* Old exceptions are not signaled. */
10520 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010521
Richard Henderson6e06d512012-06-01 09:08:21 -070010522 /* If any exceptions set by this call,
10523 and are unmasked, send a signal. */
10524 si_code = 0;
10525 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
10526 si_code = TARGET_FPE_FLTRES;
10527 }
10528 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
10529 si_code = TARGET_FPE_FLTUND;
10530 }
10531 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
10532 si_code = TARGET_FPE_FLTOVF;
10533 }
10534 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
10535 si_code = TARGET_FPE_FLTDIV;
10536 }
10537 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
10538 si_code = TARGET_FPE_FLTINV;
10539 }
10540 if (si_code != 0) {
10541 target_siginfo_t info;
10542 info.si_signo = SIGFPE;
10543 info.si_errno = 0;
10544 info.si_code = si_code;
10545 info._sifields._sigfault._addr
10546 = ((CPUArchState *)cpu_env)->pc;
10547 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010548 }
10549 }
10550 break;
10551
10552 /* case SSI_NVPAIRS:
10553 -- Used with SSIN_UACPROC to enable unaligned accesses.
10554 case SSI_IEEE_STATE_AT_SIGNAL:
10555 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
10556 -- Not implemented in linux kernel
10557 */
10558 }
10559 break;
10560#endif
10561#ifdef TARGET_NR_osf_sigprocmask
10562 /* Alpha specific. */
10563 case TARGET_NR_osf_sigprocmask:
10564 {
10565 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010566 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010567 sigset_t set, oldset;
10568
10569 switch(arg1) {
10570 case TARGET_SIG_BLOCK:
10571 how = SIG_BLOCK;
10572 break;
10573 case TARGET_SIG_UNBLOCK:
10574 how = SIG_UNBLOCK;
10575 break;
10576 case TARGET_SIG_SETMASK:
10577 how = SIG_SETMASK;
10578 break;
10579 default:
10580 ret = -TARGET_EINVAL;
10581 goto fail;
10582 }
10583 mask = arg2;
10584 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010585 ret = do_sigprocmask(how, &set, &oldset);
10586 if (!ret) {
10587 host_to_target_old_sigset(&mask, &oldset);
10588 ret = mask;
10589 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010590 }
10591 break;
10592#endif
aurel3264b4d282008-11-14 17:20:15 +000010593
bellarda315a142005-01-30 22:59:18 +000010594#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010595 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000010596 ret = get_errno(getgid());
10597 break;
bellarda315a142005-01-30 22:59:18 +000010598#endif
10599#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010600 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000010601 ret = get_errno(geteuid());
10602 break;
bellarda315a142005-01-30 22:59:18 +000010603#endif
10604#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010605 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010606 ret = get_errno(getegid());
10607 break;
bellarda315a142005-01-30 22:59:18 +000010608#endif
10609#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010610 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010611 ret = get_errno(setreuid(arg1, arg2));
10612 break;
bellarda315a142005-01-30 22:59:18 +000010613#endif
10614#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010615 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010616 ret = get_errno(setregid(arg1, arg2));
10617 break;
bellarda315a142005-01-30 22:59:18 +000010618#endif
10619#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010620 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010621 {
10622 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010623 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010624 gid_t *grouplist;
10625 int i;
10626
10627 grouplist = alloca(gidsetsize * sizeof(gid_t));
10628 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010629 if (gidsetsize == 0)
10630 break;
bellard99c475a2005-01-31 20:45:13 +000010631 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010632 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10633 if (!target_grouplist) {
10634 ret = -TARGET_EFAULT;
10635 goto fail;
10636 }
balroga2155fc2008-09-20 02:12:08 +000010637 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010638 target_grouplist[i] = tswap32(grouplist[i]);
10639 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010640 }
10641 }
10642 break;
bellarda315a142005-01-30 22:59:18 +000010643#endif
10644#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010645 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010646 {
10647 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010648 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010649 gid_t *grouplist;
10650 int i;
ths3b46e622007-09-17 08:09:54 +000010651
bellard99c475a2005-01-31 20:45:13 +000010652 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010653 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10654 if (!target_grouplist) {
10655 ret = -TARGET_EFAULT;
10656 goto fail;
10657 }
bellard99c475a2005-01-31 20:45:13 +000010658 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010659 grouplist[i] = tswap32(target_grouplist[i]);
10660 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010661 ret = get_errno(setgroups(gidsetsize, grouplist));
10662 }
10663 break;
bellarda315a142005-01-30 22:59:18 +000010664#endif
10665#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010666 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010667 ret = get_errno(fchown(arg1, arg2, arg3));
10668 break;
bellarda315a142005-01-30 22:59:18 +000010669#endif
10670#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010671 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010672 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010673 break;
bellarda315a142005-01-30 22:59:18 +000010674#endif
10675#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010676 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010677 {
pbrook53a59602006-03-25 19:31:22 +000010678 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010679 ret = get_errno(getresuid(&ruid, &euid, &suid));
10680 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010681 if (put_user_u32(ruid, arg1)
10682 || put_user_u32(euid, arg2)
10683 || put_user_u32(suid, arg3))
10684 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010685 }
10686 }
10687 break;
bellarda315a142005-01-30 22:59:18 +000010688#endif
10689#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010690 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010691 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010692 break;
bellarda315a142005-01-30 22:59:18 +000010693#endif
10694#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010695 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010696 {
pbrook53a59602006-03-25 19:31:22 +000010697 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010698 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10699 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010700 if (put_user_u32(rgid, arg1)
10701 || put_user_u32(egid, arg2)
10702 || put_user_u32(sgid, arg3))
10703 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010704 }
10705 }
10706 break;
bellarda315a142005-01-30 22:59:18 +000010707#endif
10708#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010709 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010710 if (!(p = lock_user_string(arg1)))
10711 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010712 ret = get_errno(chown(p, arg2, arg3));
10713 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010714 break;
bellarda315a142005-01-30 22:59:18 +000010715#endif
10716#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010717 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010718 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010719 break;
bellarda315a142005-01-30 22:59:18 +000010720#endif
10721#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010722 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010723 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010724 break;
bellarda315a142005-01-30 22:59:18 +000010725#endif
10726#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010727 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010728 ret = get_errno(setfsuid(arg1));
10729 break;
bellarda315a142005-01-30 22:59:18 +000010730#endif
10731#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010732 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010733 ret = get_errno(setfsgid(arg1));
10734 break;
bellarda315a142005-01-30 22:59:18 +000010735#endif
bellard67867302003-11-23 17:05:30 +000010736
bellard31e31b82003-02-18 22:55:36 +000010737 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010738 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010739#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010740 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010741 {
10742 void *a;
10743 ret = -TARGET_EFAULT;
10744 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10745 goto efault;
10746 if (!(p = lock_user_string(arg3)))
10747 goto mincore_fail;
10748 ret = get_errno(mincore(a, arg2, p));
10749 unlock_user(p, arg3, ret);
10750 mincore_fail:
10751 unlock_user(a, arg1, 0);
10752 }
10753 break;
bellardffa65c32004-01-04 23:57:22 +000010754#endif
aurel32408321b2008-10-01 21:46:32 +000010755#ifdef TARGET_NR_arm_fadvise64_64
10756 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010757 /* arm_fadvise64_64 looks like fadvise64_64 but
10758 * with different argument order: fd, advice, offset, len
10759 * rather than the usual fd, offset, len, advice.
10760 * Note that offset and len are both 64-bit so appear as
10761 * pairs of 32-bit registers.
10762 */
10763 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10764 target_offset64(arg5, arg6), arg2);
10765 ret = -host_to_target_errno(ret);
10766 break;
aurel32408321b2008-10-01 21:46:32 +000010767#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010768
10769#if TARGET_ABI_BITS == 32
10770
10771#ifdef TARGET_NR_fadvise64_64
10772 case TARGET_NR_fadvise64_64:
10773 /* 6 args: fd, offset (high, low), len (high, low), advice */
10774 if (regpairs_aligned(cpu_env)) {
10775 /* offset is in (3,4), len in (5,6) and advice in 7 */
10776 arg2 = arg3;
10777 arg3 = arg4;
10778 arg4 = arg5;
10779 arg5 = arg6;
10780 arg6 = arg7;
10781 }
10782 ret = -host_to_target_errno(posix_fadvise(arg1,
10783 target_offset64(arg2, arg3),
10784 target_offset64(arg4, arg5),
10785 arg6));
10786 break;
10787#endif
10788
10789#ifdef TARGET_NR_fadvise64
10790 case TARGET_NR_fadvise64:
10791 /* 5 args: fd, offset (high, low), len, advice */
10792 if (regpairs_aligned(cpu_env)) {
10793 /* offset is in (3,4), len in 5 and advice in 6 */
10794 arg2 = arg3;
10795 arg3 = arg4;
10796 arg4 = arg5;
10797 arg5 = arg6;
10798 }
10799 ret = -host_to_target_errno(posix_fadvise(arg1,
10800 target_offset64(arg2, arg3),
10801 arg4, arg5));
10802 break;
10803#endif
10804
10805#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010806#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010807#ifdef TARGET_NR_fadvise64_64
10808 case TARGET_NR_fadvise64_64:
10809#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010810#ifdef TARGET_NR_fadvise64
10811 case TARGET_NR_fadvise64:
10812#endif
10813#ifdef TARGET_S390X
10814 switch (arg4) {
10815 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10816 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10817 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10818 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10819 default: break;
10820 }
10821#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010822 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10823 break;
aurel32408321b2008-10-01 21:46:32 +000010824#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010825#endif /* end of 64-bit ABI fadvise handling */
10826
bellardffa65c32004-01-04 23:57:22 +000010827#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010828 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010829 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010830 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010831 This will break MADV_DONTNEED.
10832 This is a hint, so ignoring and returning success is ok. */
10833 ret = get_errno(0);
10834 break;
bellardffa65c32004-01-04 23:57:22 +000010835#endif
blueswir1992f48a2007-10-14 16:27:31 +000010836#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010837 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010838 {
thsb1e341e2007-03-20 21:50:52 +000010839 int cmd;
bellard77e46722003-04-29 20:39:06 +000010840 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010841 from_flock64_fn *copyfrom = copy_from_user_flock64;
10842 to_flock64_fn *copyto = copy_to_user_flock64;
10843
pbrookce4defa2006-02-09 16:49:55 +000010844#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010845 if (((CPUARMState *)cpu_env)->eabi) {
10846 copyfrom = copy_from_user_eabi_flock64;
10847 copyto = copy_to_user_eabi_flock64;
10848 }
pbrookce4defa2006-02-09 16:49:55 +000010849#endif
bellard77e46722003-04-29 20:39:06 +000010850
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010851 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010852 if (cmd == -TARGET_EINVAL) {
10853 ret = cmd;
10854 break;
10855 }
thsb1e341e2007-03-20 21:50:52 +000010856
bellard60cd49d2003-03-16 22:53:56 +000010857 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010858 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010859 ret = copyfrom(&fl, arg3);
10860 if (ret) {
10861 break;
ths58134272007-03-31 18:59:32 +000010862 }
thsb1e341e2007-03-20 21:50:52 +000010863 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010864 if (ret == 0) {
10865 ret = copyto(arg3, &fl);
10866 }
bellard77e46722003-04-29 20:39:06 +000010867 break;
10868
thsb1e341e2007-03-20 21:50:52 +000010869 case TARGET_F_SETLK64:
10870 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010871 ret = copyfrom(&fl, arg3);
10872 if (ret) {
10873 break;
pbrookce4defa2006-02-09 16:49:55 +000010874 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010875 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010876 break;
bellard60cd49d2003-03-16 22:53:56 +000010877 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010878 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010879 break;
10880 }
bellard77e46722003-04-29 20:39:06 +000010881 break;
10882 }
bellard60cd49d2003-03-16 22:53:56 +000010883#endif
ths7d600c82006-12-08 01:32:58 +000010884#ifdef TARGET_NR_cacheflush
10885 case TARGET_NR_cacheflush:
10886 /* self-modifying code is handled automatically, so nothing needed */
10887 ret = 0;
10888 break;
10889#endif
bellardebc05482003-09-30 21:08:41 +000010890#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010891 case TARGET_NR_security:
10892 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010893#endif
bellardc573ff62004-01-04 15:51:36 +000010894#ifdef TARGET_NR_getpagesize
10895 case TARGET_NR_getpagesize:
10896 ret = TARGET_PAGE_SIZE;
10897 break;
10898#endif
bellard31e31b82003-02-18 22:55:36 +000010899 case TARGET_NR_gettid:
10900 ret = get_errno(gettid());
10901 break;
thse5febef2007-04-01 18:31:35 +000010902#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010903 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010904#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010905 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010906 arg2 = arg3;
10907 arg3 = arg4;
10908 arg4 = arg5;
10909 }
aurel322054ac92008-10-13 21:08:07 +000010910 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10911#else
10912 ret = get_errno(readahead(arg1, arg2, arg3));
10913#endif
10914 break;
thse5febef2007-04-01 18:31:35 +000010915#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010916#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010917#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010918 case TARGET_NR_listxattr:
10919 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010920 {
10921 void *p, *b = 0;
10922 if (arg2) {
10923 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10924 if (!b) {
10925 ret = -TARGET_EFAULT;
10926 break;
10927 }
10928 }
10929 p = lock_user_string(arg1);
10930 if (p) {
10931 if (num == TARGET_NR_listxattr) {
10932 ret = get_errno(listxattr(p, b, arg3));
10933 } else {
10934 ret = get_errno(llistxattr(p, b, arg3));
10935 }
10936 } else {
10937 ret = -TARGET_EFAULT;
10938 }
10939 unlock_user(p, arg1, 0);
10940 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010941 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010942 }
10943 case TARGET_NR_flistxattr:
10944 {
10945 void *b = 0;
10946 if (arg2) {
10947 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10948 if (!b) {
10949 ret = -TARGET_EFAULT;
10950 break;
10951 }
10952 }
10953 ret = get_errno(flistxattr(arg1, b, arg3));
10954 unlock_user(b, arg2, arg3);
10955 break;
10956 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010957 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010958 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010959 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010960 void *p, *n, *v = 0;
10961 if (arg3) {
10962 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10963 if (!v) {
10964 ret = -TARGET_EFAULT;
10965 break;
10966 }
10967 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010968 p = lock_user_string(arg1);
10969 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010970 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010971 if (num == TARGET_NR_setxattr) {
10972 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10973 } else {
10974 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10975 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010976 } else {
10977 ret = -TARGET_EFAULT;
10978 }
10979 unlock_user(p, arg1, 0);
10980 unlock_user(n, arg2, 0);
10981 unlock_user(v, arg3, 0);
10982 }
10983 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010984 case TARGET_NR_fsetxattr:
10985 {
10986 void *n, *v = 0;
10987 if (arg3) {
10988 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10989 if (!v) {
10990 ret = -TARGET_EFAULT;
10991 break;
10992 }
10993 }
10994 n = lock_user_string(arg2);
10995 if (n) {
10996 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10997 } else {
10998 ret = -TARGET_EFAULT;
10999 }
11000 unlock_user(n, arg2, 0);
11001 unlock_user(v, arg3, 0);
11002 }
11003 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011004 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011005 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011006 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011007 void *p, *n, *v = 0;
11008 if (arg3) {
11009 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11010 if (!v) {
11011 ret = -TARGET_EFAULT;
11012 break;
11013 }
11014 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011015 p = lock_user_string(arg1);
11016 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011017 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011018 if (num == TARGET_NR_getxattr) {
11019 ret = get_errno(getxattr(p, n, v, arg4));
11020 } else {
11021 ret = get_errno(lgetxattr(p, n, v, arg4));
11022 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011023 } else {
11024 ret = -TARGET_EFAULT;
11025 }
11026 unlock_user(p, arg1, 0);
11027 unlock_user(n, arg2, 0);
11028 unlock_user(v, arg3, arg4);
11029 }
11030 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011031 case TARGET_NR_fgetxattr:
11032 {
11033 void *n, *v = 0;
11034 if (arg3) {
11035 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11036 if (!v) {
11037 ret = -TARGET_EFAULT;
11038 break;
11039 }
11040 }
11041 n = lock_user_string(arg2);
11042 if (n) {
11043 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11044 } else {
11045 ret = -TARGET_EFAULT;
11046 }
11047 unlock_user(n, arg2, 0);
11048 unlock_user(v, arg3, arg4);
11049 }
11050 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011051 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011052 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011053 {
11054 void *p, *n;
11055 p = lock_user_string(arg1);
11056 n = lock_user_string(arg2);
11057 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011058 if (num == TARGET_NR_removexattr) {
11059 ret = get_errno(removexattr(p, n));
11060 } else {
11061 ret = get_errno(lremovexattr(p, n));
11062 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011063 } else {
11064 ret = -TARGET_EFAULT;
11065 }
11066 unlock_user(p, arg1, 0);
11067 unlock_user(n, arg2, 0);
11068 }
11069 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011070 case TARGET_NR_fremovexattr:
11071 {
11072 void *n;
11073 n = lock_user_string(arg2);
11074 if (n) {
11075 ret = get_errno(fremovexattr(arg1, n));
11076 } else {
11077 ret = -TARGET_EFAULT;
11078 }
11079 unlock_user(n, arg2, 0);
11080 }
11081 break;
bellardebc05482003-09-30 21:08:41 +000011082#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011083#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011084#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011085 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011086#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011087 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011088 ret = 0;
11089 break;
edgar_iglef967792009-01-07 14:19:38 +000011090#elif defined(TARGET_CRIS)
11091 if (arg1 & 0xff)
11092 ret = -TARGET_EINVAL;
11093 else {
11094 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11095 ret = 0;
11096 }
11097 break;
bellard8d18e892007-11-14 15:18:40 +000011098#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11099 ret = do_set_thread_area(cpu_env, arg1);
11100 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011101#elif defined(TARGET_M68K)
11102 {
Andreas Färber0429a972013-08-26 18:14:44 +020011103 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011104 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011105 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011106 break;
11107 }
ths6f5b89a2007-03-02 20:48:00 +000011108#else
11109 goto unimplemented_nowarn;
11110#endif
11111#endif
11112#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011113 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011114#if defined(TARGET_I386) && defined(TARGET_ABI32)
11115 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011116 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011117#elif defined(TARGET_M68K)
11118 {
Andreas Färber0429a972013-08-26 18:14:44 +020011119 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011120 ret = ts->tp_value;
11121 break;
11122 }
bellard8d18e892007-11-14 15:18:40 +000011123#else
bellard5cd43932003-03-29 16:54:36 +000011124 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011125#endif
bellard8d18e892007-11-14 15:18:40 +000011126#endif
bellard48dc41e2006-06-21 18:15:50 +000011127#ifdef TARGET_NR_getdomainname
11128 case TARGET_NR_getdomainname:
11129 goto unimplemented_nowarn;
11130#endif
ths6f5b89a2007-03-02 20:48:00 +000011131
thsb5906f92007-03-19 13:32:45 +000011132#ifdef TARGET_NR_clock_gettime
11133 case TARGET_NR_clock_gettime:
11134 {
11135 struct timespec ts;
11136 ret = get_errno(clock_gettime(arg1, &ts));
11137 if (!is_error(ret)) {
11138 host_to_target_timespec(arg2, &ts);
11139 }
11140 break;
11141 }
11142#endif
11143#ifdef TARGET_NR_clock_getres
11144 case TARGET_NR_clock_getres:
11145 {
11146 struct timespec ts;
11147 ret = get_errno(clock_getres(arg1, &ts));
11148 if (!is_error(ret)) {
11149 host_to_target_timespec(arg2, &ts);
11150 }
11151 break;
11152 }
11153#endif
pbrook63d76512008-05-29 13:43:29 +000011154#ifdef TARGET_NR_clock_nanosleep
11155 case TARGET_NR_clock_nanosleep:
11156 {
11157 struct timespec ts;
11158 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011159 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11160 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011161 if (arg4)
11162 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011163
11164#if defined(TARGET_PPC)
11165 /* clock_nanosleep is odd in that it returns positive errno values.
11166 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011167 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011168 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11169 }
11170#endif
pbrook63d76512008-05-29 13:43:29 +000011171 break;
11172 }
11173#endif
thsb5906f92007-03-19 13:32:45 +000011174
ths6f5b89a2007-03-02 20:48:00 +000011175#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11176 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011177 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11178 break;
ths6f5b89a2007-03-02 20:48:00 +000011179#endif
11180
ths4cae1d12007-07-12 11:06:53 +000011181 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011182 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011183 break;
ths4cae1d12007-07-12 11:06:53 +000011184
ths71455572007-06-21 21:45:30 +000011185 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011186 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011187 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011188 break;
ths71455572007-06-21 21:45:30 +000011189
ths4f2b1fe2007-06-21 21:57:12 +000011190#ifdef TARGET_NR_set_robust_list
11191 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011192 case TARGET_NR_get_robust_list:
11193 /* The ABI for supporting robust futexes has userspace pass
11194 * the kernel a pointer to a linked list which is updated by
11195 * userspace after the syscall; the list is walked by the kernel
11196 * when the thread exits. Since the linked list in QEMU guest
11197 * memory isn't a valid linked list for the host and we have
11198 * no way to reliably intercept the thread-death event, we can't
11199 * support these. Silently return ENOSYS so that guest userspace
11200 * falls back to a non-robust futex implementation (which should
11201 * be OK except in the corner case of the guest crashing while
11202 * holding a mutex that is shared with another process via
11203 * shared memory).
11204 */
11205 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011206#endif
11207
Peter Maydell1acae9f2013-07-02 14:04:12 +010011208#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011209 case TARGET_NR_utimensat:
11210 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011211 struct timespec *tsp, ts[2];
11212 if (!arg3) {
11213 tsp = NULL;
11214 } else {
11215 target_to_host_timespec(ts, arg3);
11216 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11217 tsp = ts;
11218 }
ths9007f0e2007-09-25 17:50:37 +000011219 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011220 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011221 else {
bellard579a97f2007-11-11 14:26:47 +000011222 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011223 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011224 goto fail;
11225 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011226 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011227 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011228 }
11229 }
11230 break;
11231#endif
pbrookbd0c5662008-05-29 14:34:11 +000011232 case TARGET_NR_futex:
11233 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11234 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011235#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011236 case TARGET_NR_inotify_init:
11237 ret = get_errno(sys_inotify_init());
11238 break;
11239#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011240#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011241#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11242 case TARGET_NR_inotify_init1:
11243 ret = get_errno(sys_inotify_init1(arg1));
11244 break;
11245#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011246#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011247#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011248 case TARGET_NR_inotify_add_watch:
11249 p = lock_user_string(arg2);
11250 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11251 unlock_user(p, arg2, 0);
11252 break;
11253#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011254#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011255 case TARGET_NR_inotify_rm_watch:
11256 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
11257 break;
11258#endif
ths9007f0e2007-09-25 17:50:37 +000011259
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011260#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011261 case TARGET_NR_mq_open:
11262 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050011263 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000011264
11265 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050011266 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000011267 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050011268 attrp = &posix_mq_attr;
11269 } else {
11270 attrp = 0;
11271 }
11272 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000011273 unlock_user (p, arg1, 0);
11274 }
11275 break;
11276
11277 case TARGET_NR_mq_unlink:
11278 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010011279 if (!p) {
11280 ret = -TARGET_EFAULT;
11281 break;
11282 }
aurel3224e10032009-04-15 16:11:43 +000011283 ret = get_errno(mq_unlink(p));
11284 unlock_user (p, arg1, 0);
11285 break;
11286
11287 case TARGET_NR_mq_timedsend:
11288 {
11289 struct timespec ts;
11290
11291 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11292 if (arg5 != 0) {
11293 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011294 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011295 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011296 } else {
11297 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011298 }
aurel3224e10032009-04-15 16:11:43 +000011299 unlock_user (p, arg2, arg3);
11300 }
11301 break;
11302
11303 case TARGET_NR_mq_timedreceive:
11304 {
11305 struct timespec ts;
11306 unsigned int prio;
11307
11308 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11309 if (arg5 != 0) {
11310 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011311 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11312 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011313 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011314 } else {
11315 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11316 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011317 }
aurel3224e10032009-04-15 16:11:43 +000011318 unlock_user (p, arg2, arg3);
11319 if (arg4 != 0)
11320 put_user_u32(prio, arg4);
11321 }
11322 break;
11323
11324 /* Not implemented for now... */
11325/* case TARGET_NR_mq_notify: */
11326/* break; */
11327
11328 case TARGET_NR_mq_getsetattr:
11329 {
11330 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11331 ret = 0;
11332 if (arg3 != 0) {
11333 ret = mq_getattr(arg1, &posix_mq_attr_out);
11334 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11335 }
11336 if (arg2 != 0) {
11337 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
11338 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
11339 }
11340
11341 }
11342 break;
11343#endif
11344
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011345#ifdef CONFIG_SPLICE
11346#ifdef TARGET_NR_tee
11347 case TARGET_NR_tee:
11348 {
11349 ret = get_errno(tee(arg1,arg2,arg3,arg4));
11350 }
11351 break;
11352#endif
11353#ifdef TARGET_NR_splice
11354 case TARGET_NR_splice:
11355 {
11356 loff_t loff_in, loff_out;
11357 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010011358 if (arg2) {
11359 if (get_user_u64(loff_in, arg2)) {
11360 goto efault;
11361 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011362 ploff_in = &loff_in;
11363 }
Andreas Schwab17644b32015-03-10 17:11:35 +010011364 if (arg4) {
11365 if (get_user_u64(loff_out, arg4)) {
11366 goto efault;
11367 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011368 ploff_out = &loff_out;
11369 }
11370 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010011371 if (arg2) {
11372 if (put_user_u64(loff_in, arg2)) {
11373 goto efault;
11374 }
11375 }
11376 if (arg4) {
11377 if (put_user_u64(loff_out, arg4)) {
11378 goto efault;
11379 }
11380 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011381 }
11382 break;
11383#endif
11384#ifdef TARGET_NR_vmsplice
11385 case TARGET_NR_vmsplice:
11386 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011387 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11388 if (vec != NULL) {
11389 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
11390 unlock_iovec(vec, arg2, arg3, 0);
11391 } else {
11392 ret = -host_to_target_errno(errno);
11393 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011394 }
11395 break;
11396#endif
11397#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030011398#ifdef CONFIG_EVENTFD
11399#if defined(TARGET_NR_eventfd)
11400 case TARGET_NR_eventfd:
11401 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020011402 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011403 break;
11404#endif
11405#if defined(TARGET_NR_eventfd2)
11406 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020011407 {
11408 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
11409 if (arg2 & TARGET_O_NONBLOCK) {
11410 host_flags |= O_NONBLOCK;
11411 }
11412 if (arg2 & TARGET_O_CLOEXEC) {
11413 host_flags |= O_CLOEXEC;
11414 }
11415 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020011416 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011417 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020011418 }
Riku Voipioc2882b92009-08-12 15:08:24 +030011419#endif
11420#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030011421#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
11422 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010011423#if TARGET_ABI_BITS == 32
11424 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
11425 target_offset64(arg5, arg6)));
11426#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030011427 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010011428#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030011429 break;
11430#endif
Peter Maydellc727f472011-01-06 11:05:10 +000011431#if defined(CONFIG_SYNC_FILE_RANGE)
11432#if defined(TARGET_NR_sync_file_range)
11433 case TARGET_NR_sync_file_range:
11434#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030011435#if defined(TARGET_MIPS)
11436 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11437 target_offset64(arg5, arg6), arg7));
11438#else
Peter Maydellc727f472011-01-06 11:05:10 +000011439 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
11440 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030011441#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000011442#else
11443 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
11444#endif
11445 break;
11446#endif
11447#if defined(TARGET_NR_sync_file_range2)
11448 case TARGET_NR_sync_file_range2:
11449 /* This is like sync_file_range but the arguments are reordered */
11450#if TARGET_ABI_BITS == 32
11451 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11452 target_offset64(arg5, arg6), arg2));
11453#else
11454 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
11455#endif
11456 break;
11457#endif
11458#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020011459#if defined(TARGET_NR_signalfd4)
11460 case TARGET_NR_signalfd4:
11461 ret = do_signalfd4(arg1, arg2, arg4);
11462 break;
11463#endif
11464#if defined(TARGET_NR_signalfd)
11465 case TARGET_NR_signalfd:
11466 ret = do_signalfd4(arg1, arg2, 0);
11467 break;
11468#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000011469#if defined(CONFIG_EPOLL)
11470#if defined(TARGET_NR_epoll_create)
11471 case TARGET_NR_epoll_create:
11472 ret = get_errno(epoll_create(arg1));
11473 break;
11474#endif
11475#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
11476 case TARGET_NR_epoll_create1:
11477 ret = get_errno(epoll_create1(arg1));
11478 break;
11479#endif
11480#if defined(TARGET_NR_epoll_ctl)
11481 case TARGET_NR_epoll_ctl:
11482 {
11483 struct epoll_event ep;
11484 struct epoll_event *epp = 0;
11485 if (arg4) {
11486 struct target_epoll_event *target_ep;
11487 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
11488 goto efault;
11489 }
11490 ep.events = tswap32(target_ep->events);
11491 /* The epoll_data_t union is just opaque data to the kernel,
11492 * so we transfer all 64 bits across and need not worry what
11493 * actual data type it is.
11494 */
11495 ep.data.u64 = tswap64(target_ep->data.u64);
11496 unlock_user_struct(target_ep, arg4, 0);
11497 epp = &ep;
11498 }
11499 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
11500 break;
11501 }
11502#endif
11503
Peter Maydell227f0212016-06-06 19:58:11 +010011504#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011505#if defined(TARGET_NR_epoll_wait)
11506 case TARGET_NR_epoll_wait:
11507#endif
Peter Maydell227f0212016-06-06 19:58:11 +010011508#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011509 case TARGET_NR_epoll_pwait:
11510#endif
11511 {
11512 struct target_epoll_event *target_ep;
11513 struct epoll_event *ep;
11514 int epfd = arg1;
11515 int maxevents = arg3;
11516 int timeout = arg4;
11517
Peter Maydell2ba7fae32016-07-18 15:35:59 +010011518 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
11519 ret = -TARGET_EINVAL;
11520 break;
11521 }
11522
Peter Maydell3b6edd12011-02-15 18:35:05 +000011523 target_ep = lock_user(VERIFY_WRITE, arg2,
11524 maxevents * sizeof(struct target_epoll_event), 1);
11525 if (!target_ep) {
11526 goto efault;
11527 }
11528
11529 ep = alloca(maxevents * sizeof(struct epoll_event));
11530
11531 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010011532#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011533 case TARGET_NR_epoll_pwait:
11534 {
11535 target_sigset_t *target_set;
11536 sigset_t _set, *set = &_set;
11537
11538 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010011539 if (arg6 != sizeof(target_sigset_t)) {
11540 ret = -TARGET_EINVAL;
11541 break;
11542 }
11543
Peter Maydell3b6edd12011-02-15 18:35:05 +000011544 target_set = lock_user(VERIFY_READ, arg5,
11545 sizeof(target_sigset_t), 1);
11546 if (!target_set) {
11547 unlock_user(target_ep, arg2, 0);
11548 goto efault;
11549 }
11550 target_to_host_sigset(set, target_set);
11551 unlock_user(target_set, arg5, 0);
11552 } else {
11553 set = NULL;
11554 }
11555
Peter Maydell227f0212016-06-06 19:58:11 +010011556 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11557 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011558 break;
11559 }
11560#endif
11561#if defined(TARGET_NR_epoll_wait)
11562 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010011563 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11564 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011565 break;
11566#endif
11567 default:
11568 ret = -TARGET_ENOSYS;
11569 }
11570 if (!is_error(ret)) {
11571 int i;
11572 for (i = 0; i < ret; i++) {
11573 target_ep[i].events = tswap32(ep[i].events);
11574 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11575 }
11576 }
11577 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
11578 break;
11579 }
11580#endif
11581#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011582#ifdef TARGET_NR_prlimit64
11583 case TARGET_NR_prlimit64:
11584 {
11585 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11586 struct target_rlimit64 *target_rnew, *target_rold;
11587 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011588 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011589 if (arg3) {
11590 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
11591 goto efault;
11592 }
11593 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11594 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11595 unlock_user_struct(target_rnew, arg3, 0);
11596 rnewp = &rnew;
11597 }
11598
Felix Janda95018012014-12-02 22:11:17 +010011599 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011600 if (!is_error(ret) && arg4) {
11601 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
11602 goto efault;
11603 }
11604 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11605 target_rold->rlim_max = tswap64(rold.rlim_max);
11606 unlock_user_struct(target_rold, arg4, 1);
11607 }
11608 break;
11609 }
11610#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011611#ifdef TARGET_NR_gethostname
11612 case TARGET_NR_gethostname:
11613 {
11614 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11615 if (name) {
11616 ret = get_errno(gethostname(name, arg2));
11617 unlock_user(name, arg1, arg2);
11618 } else {
11619 ret = -TARGET_EFAULT;
11620 }
11621 break;
11622 }
11623#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011624#ifdef TARGET_NR_atomic_cmpxchg_32
11625 case TARGET_NR_atomic_cmpxchg_32:
11626 {
11627 /* should use start_exclusive from main.c */
11628 abi_ulong mem_value;
11629 if (get_user_u32(mem_value, arg6)) {
11630 target_siginfo_t info;
11631 info.si_signo = SIGSEGV;
11632 info.si_errno = 0;
11633 info.si_code = TARGET_SEGV_MAPERR;
11634 info._sifields._sigfault._addr = arg6;
11635 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11636 ret = 0xdeadbeef;
11637
11638 }
11639 if (mem_value == arg2)
11640 put_user_u32(arg1, arg6);
11641 ret = mem_value;
11642 break;
11643 }
11644#endif
11645#ifdef TARGET_NR_atomic_barrier
11646 case TARGET_NR_atomic_barrier:
11647 {
11648 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011649 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011650 break;
11651 }
11652#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011653
11654#ifdef TARGET_NR_timer_create
11655 case TARGET_NR_timer_create:
11656 {
11657 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11658
11659 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011660
11661 int clkid = arg1;
11662 int timer_index = next_free_host_timer();
11663
11664 if (timer_index < 0) {
11665 ret = -TARGET_EAGAIN;
11666 } else {
11667 timer_t *phtimer = g_posix_timers + timer_index;
11668
11669 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011670 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011671 ret = target_to_host_sigevent(phost_sevp, arg2);
11672 if (ret != 0) {
11673 break;
11674 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011675 }
11676
11677 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11678 if (ret) {
11679 phtimer = NULL;
11680 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011681 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011682 goto efault;
11683 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011684 }
11685 }
11686 break;
11687 }
11688#endif
11689
11690#ifdef TARGET_NR_timer_settime
11691 case TARGET_NR_timer_settime:
11692 {
11693 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11694 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011695 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011696
Alexander Grafaecc8862014-11-10 21:33:03 +010011697 if (timerid < 0) {
11698 ret = timerid;
11699 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011700 ret = -TARGET_EINVAL;
11701 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011702 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011703 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11704
11705 target_to_host_itimerspec(&hspec_new, arg3);
11706 ret = get_errno(
11707 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11708 host_to_target_itimerspec(arg2, &hspec_old);
11709 }
11710 break;
11711 }
11712#endif
11713
11714#ifdef TARGET_NR_timer_gettime
11715 case TARGET_NR_timer_gettime:
11716 {
11717 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011718 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011719
Alexander Grafaecc8862014-11-10 21:33:03 +010011720 if (timerid < 0) {
11721 ret = timerid;
11722 } else if (!arg2) {
11723 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011724 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011725 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011726 struct itimerspec hspec;
11727 ret = get_errno(timer_gettime(htimer, &hspec));
11728
11729 if (host_to_target_itimerspec(arg2, &hspec)) {
11730 ret = -TARGET_EFAULT;
11731 }
11732 }
11733 break;
11734 }
11735#endif
11736
11737#ifdef TARGET_NR_timer_getoverrun
11738 case TARGET_NR_timer_getoverrun:
11739 {
11740 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011741 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011742
Alexander Grafaecc8862014-11-10 21:33:03 +010011743 if (timerid < 0) {
11744 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011745 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011746 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011747 ret = get_errno(timer_getoverrun(htimer));
11748 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011749 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011750 break;
11751 }
11752#endif
11753
11754#ifdef TARGET_NR_timer_delete
11755 case TARGET_NR_timer_delete:
11756 {
11757 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011758 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011759
Alexander Grafaecc8862014-11-10 21:33:03 +010011760 if (timerid < 0) {
11761 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011762 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011763 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011764 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011765 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011766 }
11767 break;
11768 }
11769#endif
11770
Riku Voipio51834342014-06-22 11:25:42 +010011771#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11772 case TARGET_NR_timerfd_create:
11773 ret = get_errno(timerfd_create(arg1,
11774 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11775 break;
11776#endif
11777
11778#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11779 case TARGET_NR_timerfd_gettime:
11780 {
11781 struct itimerspec its_curr;
11782
11783 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11784
11785 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11786 goto efault;
11787 }
11788 }
11789 break;
11790#endif
11791
11792#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11793 case TARGET_NR_timerfd_settime:
11794 {
11795 struct itimerspec its_new, its_old, *p_new;
11796
11797 if (arg3) {
11798 if (target_to_host_itimerspec(&its_new, arg3)) {
11799 goto efault;
11800 }
11801 p_new = &its_new;
11802 } else {
11803 p_new = NULL;
11804 }
11805
11806 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11807
11808 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11809 goto efault;
11810 }
11811 }
11812 break;
11813#endif
11814
Paul Burtonab31cda2014-06-22 11:25:43 +010011815#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11816 case TARGET_NR_ioprio_get:
11817 ret = get_errno(ioprio_get(arg1, arg2));
11818 break;
11819#endif
11820
11821#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11822 case TARGET_NR_ioprio_set:
11823 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11824 break;
11825#endif
11826
Riku Voipio9af5c902014-08-12 15:58:57 +030011827#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11828 case TARGET_NR_setns:
11829 ret = get_errno(setns(arg1, arg2));
11830 break;
11831#endif
11832#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11833 case TARGET_NR_unshare:
11834 ret = get_errno(unshare(arg1));
11835 break;
11836#endif
11837
bellard31e31b82003-02-18 22:55:36 +000011838 default:
11839 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011840 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011841#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 +000011842 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011843#endif
ths0da46a62007-10-20 20:23:07 +000011844 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011845 break;
11846 }
bellard579a97f2007-11-11 14:26:47 +000011847fail:
bellardc573ff62004-01-04 15:51:36 +000011848#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011849 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011850#endif
thsb92c47c2007-11-01 00:07:38 +000011851 if(do_strace)
11852 print_syscall_ret(num, ret);
Lluís Vilanova9c15e702016-06-21 15:52:04 +020011853 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000011854 return ret;
bellard579a97f2007-11-11 14:26:47 +000011855efault:
11856 ret = -TARGET_EFAULT;
11857 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011858}