blob: ca06943f3b286dd6fa7a72c67cbdcc3e51cb1cf1 [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
Riku Voipioebc996f2009-04-21 15:01:51 +0300523#ifdef CONFIG_UTIMENSAT
524static int sys_utimensat(int dirfd, const char *pathname,
525 const struct timespec times[2], int flags)
526{
527 if (pathname == NULL)
528 return futimens(dirfd, times);
529 else
530 return utimensat(dirfd, pathname, times, flags);
531}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100532#elif defined(__NR_utimensat)
533#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000534_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
535 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100536#else
537static int sys_utimensat(int dirfd, const char *pathname,
538 const struct timespec times[2], int flags)
539{
540 errno = ENOSYS;
541 return -1;
542}
ths9007f0e2007-09-25 17:50:37 +0000543#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100544#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000545
546#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000547#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000548
aurel3239b59762008-10-01 21:46:50 +0000549#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000550static int sys_inotify_init(void)
551{
552 return (inotify_init());
553}
aurel3239b59762008-10-01 21:46:50 +0000554#endif
555#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000556static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
557{
558 return (inotify_add_watch(fd, pathname, mask));
559}
aurel3239b59762008-10-01 21:46:50 +0000560#endif
561#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000562static int sys_inotify_rm_watch(int fd, int32_t wd)
563{
aurel328690e422009-04-17 13:50:32 +0000564 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000565}
aurel3239b59762008-10-01 21:46:50 +0000566#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000567#ifdef CONFIG_INOTIFY1
568#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
569static int sys_inotify_init1(int flags)
570{
571 return (inotify_init1(flags));
572}
573#endif
574#endif
aurel323b3f24a2009-04-15 16:12:13 +0000575#else
576/* Userspace can usually survive runtime without inotify */
577#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000578#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000579#undef TARGET_NR_inotify_add_watch
580#undef TARGET_NR_inotify_rm_watch
581#endif /* CONFIG_INOTIFY */
582
Peter Maydell163a05a2011-06-27 17:44:52 +0100583#if defined(TARGET_NR_prlimit64)
584#ifndef __NR_prlimit64
585# define __NR_prlimit64 -1
586#endif
587#define __NR_sys_prlimit64 __NR_prlimit64
588/* The glibc rlimit structure may not be that used by the underlying syscall */
589struct host_rlimit64 {
590 uint64_t rlim_cur;
591 uint64_t rlim_max;
592};
593_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
594 const struct host_rlimit64 *, new_limit,
595 struct host_rlimit64 *, old_limit)
596#endif
597
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100598
599#if defined(TARGET_NR_timer_create)
600/* Maxiumum of 32 active POSIX timers allowed at any one time. */
601static timer_t g_posix_timers[32] = { 0, } ;
602
603static inline int next_free_host_timer(void)
604{
605 int k ;
606 /* FIXME: Does finding the next free slot require a lock? */
607 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
608 if (g_posix_timers[k] == 0) {
609 g_posix_timers[k] = (timer_t) 1;
610 return k;
611 }
612 }
613 return -1;
614}
615#endif
616
Riku Voipio48e515d2011-07-12 15:40:51 +0300617/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000618#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300619static inline int regpairs_aligned(void *cpu_env) {
620 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
621}
622#elif defined(TARGET_MIPS)
623static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000624#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
625/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
626 * of registers which translates to the same as ARM/MIPS, because we start with
627 * r3 as arg1 */
628static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300629#else
630static inline int regpairs_aligned(void *cpu_env) { return 0; }
631#endif
632
thsb92c47c2007-11-01 00:07:38 +0000633#define ERRNO_TABLE_SIZE 1200
634
635/* target_to_host_errno_table[] is initialized from
636 * host_to_target_errno_table[] in syscall_init(). */
637static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
638};
639
ths637947f2007-06-01 12:09:19 +0000640/*
thsfe8f0962007-07-12 10:59:21 +0000641 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000642 * minus the errnos that are not actually generic to all archs.
643 */
thsb92c47c2007-11-01 00:07:38 +0000644static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800645 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000646 [EIDRM] = TARGET_EIDRM,
647 [ECHRNG] = TARGET_ECHRNG,
648 [EL2NSYNC] = TARGET_EL2NSYNC,
649 [EL3HLT] = TARGET_EL3HLT,
650 [EL3RST] = TARGET_EL3RST,
651 [ELNRNG] = TARGET_ELNRNG,
652 [EUNATCH] = TARGET_EUNATCH,
653 [ENOCSI] = TARGET_ENOCSI,
654 [EL2HLT] = TARGET_EL2HLT,
655 [EDEADLK] = TARGET_EDEADLK,
656 [ENOLCK] = TARGET_ENOLCK,
657 [EBADE] = TARGET_EBADE,
658 [EBADR] = TARGET_EBADR,
659 [EXFULL] = TARGET_EXFULL,
660 [ENOANO] = TARGET_ENOANO,
661 [EBADRQC] = TARGET_EBADRQC,
662 [EBADSLT] = TARGET_EBADSLT,
663 [EBFONT] = TARGET_EBFONT,
664 [ENOSTR] = TARGET_ENOSTR,
665 [ENODATA] = TARGET_ENODATA,
666 [ETIME] = TARGET_ETIME,
667 [ENOSR] = TARGET_ENOSR,
668 [ENONET] = TARGET_ENONET,
669 [ENOPKG] = TARGET_ENOPKG,
670 [EREMOTE] = TARGET_EREMOTE,
671 [ENOLINK] = TARGET_ENOLINK,
672 [EADV] = TARGET_EADV,
673 [ESRMNT] = TARGET_ESRMNT,
674 [ECOMM] = TARGET_ECOMM,
675 [EPROTO] = TARGET_EPROTO,
676 [EDOTDOT] = TARGET_EDOTDOT,
677 [EMULTIHOP] = TARGET_EMULTIHOP,
678 [EBADMSG] = TARGET_EBADMSG,
679 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
680 [EOVERFLOW] = TARGET_EOVERFLOW,
681 [ENOTUNIQ] = TARGET_ENOTUNIQ,
682 [EBADFD] = TARGET_EBADFD,
683 [EREMCHG] = TARGET_EREMCHG,
684 [ELIBACC] = TARGET_ELIBACC,
685 [ELIBBAD] = TARGET_ELIBBAD,
686 [ELIBSCN] = TARGET_ELIBSCN,
687 [ELIBMAX] = TARGET_ELIBMAX,
688 [ELIBEXEC] = TARGET_ELIBEXEC,
689 [EILSEQ] = TARGET_EILSEQ,
690 [ENOSYS] = TARGET_ENOSYS,
691 [ELOOP] = TARGET_ELOOP,
692 [ERESTART] = TARGET_ERESTART,
693 [ESTRPIPE] = TARGET_ESTRPIPE,
694 [ENOTEMPTY] = TARGET_ENOTEMPTY,
695 [EUSERS] = TARGET_EUSERS,
696 [ENOTSOCK] = TARGET_ENOTSOCK,
697 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
698 [EMSGSIZE] = TARGET_EMSGSIZE,
699 [EPROTOTYPE] = TARGET_EPROTOTYPE,
700 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
701 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
702 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
703 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
704 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
705 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
706 [EADDRINUSE] = TARGET_EADDRINUSE,
707 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
708 [ENETDOWN] = TARGET_ENETDOWN,
709 [ENETUNREACH] = TARGET_ENETUNREACH,
710 [ENETRESET] = TARGET_ENETRESET,
711 [ECONNABORTED] = TARGET_ECONNABORTED,
712 [ECONNRESET] = TARGET_ECONNRESET,
713 [ENOBUFS] = TARGET_ENOBUFS,
714 [EISCONN] = TARGET_EISCONN,
715 [ENOTCONN] = TARGET_ENOTCONN,
716 [EUCLEAN] = TARGET_EUCLEAN,
717 [ENOTNAM] = TARGET_ENOTNAM,
718 [ENAVAIL] = TARGET_ENAVAIL,
719 [EISNAM] = TARGET_EISNAM,
720 [EREMOTEIO] = TARGET_EREMOTEIO,
721 [ESHUTDOWN] = TARGET_ESHUTDOWN,
722 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
723 [ETIMEDOUT] = TARGET_ETIMEDOUT,
724 [ECONNREFUSED] = TARGET_ECONNREFUSED,
725 [EHOSTDOWN] = TARGET_EHOSTDOWN,
726 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
727 [EALREADY] = TARGET_EALREADY,
728 [EINPROGRESS] = TARGET_EINPROGRESS,
729 [ESTALE] = TARGET_ESTALE,
730 [ECANCELED] = TARGET_ECANCELED,
731 [ENOMEDIUM] = TARGET_ENOMEDIUM,
732 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000733#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000734 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000735#endif
736#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000737 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000738#endif
739#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000740 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000741#endif
742#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000743 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000744#endif
745#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000746 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000747#endif
748#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000749 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000750#endif
thsb92c47c2007-11-01 00:07:38 +0000751};
ths637947f2007-06-01 12:09:19 +0000752
753static inline int host_to_target_errno(int err)
754{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100755 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
756 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000757 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100758 }
ths637947f2007-06-01 12:09:19 +0000759 return err;
760}
761
thsb92c47c2007-11-01 00:07:38 +0000762static inline int target_to_host_errno(int err)
763{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100764 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
765 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000766 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100767 }
thsb92c47c2007-11-01 00:07:38 +0000768 return err;
769}
770
blueswir1992f48a2007-10-14 16:27:31 +0000771static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000772{
773 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000774 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000775 else
776 return ret;
777}
778
blueswir1992f48a2007-10-14 16:27:31 +0000779static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000780{
blueswir1992f48a2007-10-14 16:27:31 +0000781 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000782}
783
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100784const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000785{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100786 if (err == TARGET_ERESTARTSYS) {
787 return "To be restarted";
788 }
789 if (err == TARGET_QEMU_ESIGRETURN) {
790 return "Successful exit from sigreturn";
791 }
792
Alexander Graf962b2892011-11-21 12:04:07 +0100793 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
794 return NULL;
795 }
thsb92c47c2007-11-01 00:07:38 +0000796 return strerror(target_to_host_errno(err));
797}
798
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100799#define safe_syscall0(type, name) \
800static type safe_##name(void) \
801{ \
802 return safe_syscall(__NR_##name); \
803}
804
805#define safe_syscall1(type, name, type1, arg1) \
806static type safe_##name(type1 arg1) \
807{ \
808 return safe_syscall(__NR_##name, arg1); \
809}
810
811#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
812static type safe_##name(type1 arg1, type2 arg2) \
813{ \
814 return safe_syscall(__NR_##name, arg1, arg2); \
815}
816
817#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
818static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
819{ \
820 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
821}
822
823#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
824 type4, arg4) \
825static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
826{ \
827 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
828}
829
830#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
831 type4, arg4, type5, arg5) \
832static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
833 type5 arg5) \
834{ \
835 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
836}
837
838#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
839 type4, arg4, type5, arg5, type6, arg6) \
840static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
841 type5 arg5, type6 arg6) \
842{ \
843 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
844}
845
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100846safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
847safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100848safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
849 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100850safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
851 struct rusage *, rusage)
852safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
853 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100854safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100855safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
856 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100857safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
858 struct timespec *, tsp, const sigset_t *, sigmask,
859 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100860safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
861 int, maxevents, int, timeout, const sigset_t *, sigmask,
862 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100863safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
864 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100865safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100866safe_syscall2(int, kill, pid_t, pid, int, sig)
867safe_syscall2(int, tkill, int, tid, int, sig)
868safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100869safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
870safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100871safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
872 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100873safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
874 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
875safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
876 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
877safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
878safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100879safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100880safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
881 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100882safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
883 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100884safe_syscall2(int, nanosleep, const struct timespec *, req,
885 struct timespec *, rem)
886#ifdef TARGET_NR_clock_nanosleep
887safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
888 const struct timespec *, req, struct timespec *, rem)
889#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100890#ifdef __NR_msgsnd
891safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
892 int, flags)
893safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
894 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100895safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
896 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100897#else
898/* This host kernel architecture uses a single ipc syscall; fake up
899 * wrappers for the sub-operations to hide this implementation detail.
900 * Annoyingly we can't include linux/ipc.h to get the constant definitions
901 * for the call parameter because some structs in there conflict with the
902 * sys/ipc.h ones. So we just define them here, and rely on them being
903 * the same for all host architectures.
904 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100905#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100906#define Q_MSGSND 11
907#define Q_MSGRCV 12
908#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
909
910safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
911 void *, ptr, long, fifth)
912static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
913{
914 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
915}
916static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
917{
918 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
919}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100920static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
921 const struct timespec *timeout)
922{
923 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
924 (long)timeout);
925}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100926#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100927#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
928safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
929 size_t, len, unsigned, prio, const struct timespec *, timeout)
930safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
931 size_t, len, unsigned *, prio, const struct timespec *, timeout)
932#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100933/* We do ioctl like this rather than via safe_syscall3 to preserve the
934 * "third argument might be integer or pointer or not present" behaviour of
935 * the libc function.
936 */
937#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100938/* Similarly for fcntl. Note that callers must always:
939 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
940 * use the flock64 struct rather than unsuffixed flock
941 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
942 */
943#ifdef __NR_fcntl64
944#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
945#else
946#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
947#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100948
Paul Burton8289d112014-06-22 11:25:33 +0100949static inline int host_to_target_sock_type(int host_type)
950{
951 int target_type;
952
953 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
954 case SOCK_DGRAM:
955 target_type = TARGET_SOCK_DGRAM;
956 break;
957 case SOCK_STREAM:
958 target_type = TARGET_SOCK_STREAM;
959 break;
960 default:
961 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
962 break;
963 }
964
965#if defined(SOCK_CLOEXEC)
966 if (host_type & SOCK_CLOEXEC) {
967 target_type |= TARGET_SOCK_CLOEXEC;
968 }
969#endif
970
971#if defined(SOCK_NONBLOCK)
972 if (host_type & SOCK_NONBLOCK) {
973 target_type |= TARGET_SOCK_NONBLOCK;
974 }
975#endif
976
977 return target_type;
978}
979
blueswir1992f48a2007-10-14 16:27:31 +0000980static abi_ulong target_brk;
981static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000982static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000983
blueswir1992f48a2007-10-14 16:27:31 +0000984void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000985{
blueswir14c1de732007-07-07 20:45:44 +0000986 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000987 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000988}
989
vincent4d1de872011-06-14 21:56:33 +0000990//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
991#define DEBUGF_BRK(message, args...)
992
ths0da46a62007-10-20 20:23:07 +0000993/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000994abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000995{
blueswir1992f48a2007-10-14 16:27:31 +0000996 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +0100997 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +0000998
Paul Brook3a0c6c42012-02-09 19:04:27 +0000999 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001000
vincent4d1de872011-06-14 21:56:33 +00001001 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001002 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001003 return target_brk;
1004 }
1005 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001006 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1007 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001008 return target_brk;
1009 }
bellard31e31b82003-02-18 22:55:36 +00001010
vincent4d1de872011-06-14 21:56:33 +00001011 /* If the new brk is less than the highest page reserved to the
1012 * target heap allocation, set it and we're almost done... */
1013 if (new_brk <= brk_page) {
1014 /* Heap contents are initialized to zero, as for anonymous
1015 * mapped pages. */
1016 if (new_brk > target_brk) {
1017 memset(g2h(target_brk), 0, new_brk - target_brk);
1018 }
bellard31e31b82003-02-18 22:55:36 +00001019 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001020 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001021 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001022 }
1023
Peter Maydell00faf082011-04-18 16:34:24 +01001024 /* We need to allocate more memory after the brk... Note that
1025 * we don't use MAP_FIXED because that will map over the top of
1026 * any existing mapping (like the one with the host libc or qemu
1027 * itself); instead we treat "mapped but at wrong address" as
1028 * a failure and unmap again.
1029 */
vincent4d1de872011-06-14 21:56:33 +00001030 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001031 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001032 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001033 MAP_ANON|MAP_PRIVATE, 0, 0));
1034
1035 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001036 /* Heap contents are initialized to zero, as for anonymous
1037 * mapped pages. Technically the new pages are already
1038 * initialized to zero since they *are* anonymous mapped
1039 * pages, however we have to take care with the contents that
1040 * come from the remaining part of the previous page: it may
1041 * contains garbage data due to a previous heap usage (grown
1042 * then shrunken). */
1043 memset(g2h(target_brk), 0, brk_page - target_brk);
1044
Peter Maydell00faf082011-04-18 16:34:24 +01001045 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001046 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001047 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1048 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001049 return target_brk;
1050 } else if (mapped_addr != -1) {
1051 /* Mapped but at wrong address, meaning there wasn't actually
1052 * enough space for this brk.
1053 */
1054 target_munmap(mapped_addr, new_alloc_size);
1055 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001056 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001057 }
1058 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001059 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001060 }
balrog7ab240a2008-04-26 12:17:34 +00001061
Richard Henderson7dd46c02010-05-03 10:07:49 -07001062#if defined(TARGET_ALPHA)
1063 /* We (partially) emulate OSF/1 on Alpha, which requires we
1064 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001065 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001066#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001067 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001068 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001069}
1070
ths26edcf42007-12-09 02:25:24 +00001071static inline abi_long copy_from_user_fdset(fd_set *fds,
1072 abi_ulong target_fds_addr,
1073 int n)
bellard31e31b82003-02-18 22:55:36 +00001074{
ths26edcf42007-12-09 02:25:24 +00001075 int i, nw, j, k;
1076 abi_ulong b, *target_fds;
1077
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001078 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001079 if (!(target_fds = lock_user(VERIFY_READ,
1080 target_fds_addr,
1081 sizeof(abi_ulong) * nw,
1082 1)))
1083 return -TARGET_EFAULT;
1084
1085 FD_ZERO(fds);
1086 k = 0;
1087 for (i = 0; i < nw; i++) {
1088 /* grab the abi_ulong */
1089 __get_user(b, &target_fds[i]);
1090 for (j = 0; j < TARGET_ABI_BITS; j++) {
1091 /* check the bit inside the abi_ulong */
1092 if ((b >> j) & 1)
1093 FD_SET(k, fds);
1094 k++;
bellard31e31b82003-02-18 22:55:36 +00001095 }
bellard31e31b82003-02-18 22:55:36 +00001096 }
ths26edcf42007-12-09 02:25:24 +00001097
1098 unlock_user(target_fds, target_fds_addr, 0);
1099
1100 return 0;
bellard31e31b82003-02-18 22:55:36 +00001101}
1102
Mike Frysinger055e0902011-06-03 17:01:49 -04001103static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1104 abi_ulong target_fds_addr,
1105 int n)
1106{
1107 if (target_fds_addr) {
1108 if (copy_from_user_fdset(fds, target_fds_addr, n))
1109 return -TARGET_EFAULT;
1110 *fds_ptr = fds;
1111 } else {
1112 *fds_ptr = NULL;
1113 }
1114 return 0;
1115}
1116
ths26edcf42007-12-09 02:25:24 +00001117static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1118 const fd_set *fds,
1119 int n)
bellard31e31b82003-02-18 22:55:36 +00001120{
bellard31e31b82003-02-18 22:55:36 +00001121 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001122 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001123 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001124
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001125 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001126 if (!(target_fds = lock_user(VERIFY_WRITE,
1127 target_fds_addr,
1128 sizeof(abi_ulong) * nw,
1129 0)))
1130 return -TARGET_EFAULT;
1131
1132 k = 0;
1133 for (i = 0; i < nw; i++) {
1134 v = 0;
1135 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001136 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001137 k++;
bellard31e31b82003-02-18 22:55:36 +00001138 }
ths26edcf42007-12-09 02:25:24 +00001139 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001140 }
ths26edcf42007-12-09 02:25:24 +00001141
1142 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1143
1144 return 0;
bellard31e31b82003-02-18 22:55:36 +00001145}
1146
bellardc596ed12003-07-13 17:32:31 +00001147#if defined(__alpha__)
1148#define HOST_HZ 1024
1149#else
1150#define HOST_HZ 100
1151#endif
1152
blueswir1992f48a2007-10-14 16:27:31 +00001153static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001154{
1155#if HOST_HZ == TARGET_HZ
1156 return ticks;
1157#else
1158 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1159#endif
1160}
1161
bellard579a97f2007-11-11 14:26:47 +00001162static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1163 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001164{
pbrook53a59602006-03-25 19:31:22 +00001165 struct target_rusage *target_rusage;
1166
bellard579a97f2007-11-11 14:26:47 +00001167 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1168 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001169 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1170 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1171 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1172 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1173 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1174 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1175 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1176 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1177 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1178 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1179 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1180 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1181 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1182 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1183 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1184 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1185 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1186 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001187 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001188
1189 return 0;
bellardb4091862003-05-16 15:39:34 +00001190}
1191
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001192static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001193{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001194 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001195 rlim_t result;
1196
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001197 target_rlim_swap = tswapal(target_rlim);
1198 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1199 return RLIM_INFINITY;
1200
1201 result = target_rlim_swap;
1202 if (target_rlim_swap != (rlim_t)result)
1203 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001204
1205 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001206}
1207
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001208static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001209{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001210 abi_ulong target_rlim_swap;
1211 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001212
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001213 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001214 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001215 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001216 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001217 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001218
1219 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001220}
1221
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001222static inline int target_to_host_resource(int code)
1223{
1224 switch (code) {
1225 case TARGET_RLIMIT_AS:
1226 return RLIMIT_AS;
1227 case TARGET_RLIMIT_CORE:
1228 return RLIMIT_CORE;
1229 case TARGET_RLIMIT_CPU:
1230 return RLIMIT_CPU;
1231 case TARGET_RLIMIT_DATA:
1232 return RLIMIT_DATA;
1233 case TARGET_RLIMIT_FSIZE:
1234 return RLIMIT_FSIZE;
1235 case TARGET_RLIMIT_LOCKS:
1236 return RLIMIT_LOCKS;
1237 case TARGET_RLIMIT_MEMLOCK:
1238 return RLIMIT_MEMLOCK;
1239 case TARGET_RLIMIT_MSGQUEUE:
1240 return RLIMIT_MSGQUEUE;
1241 case TARGET_RLIMIT_NICE:
1242 return RLIMIT_NICE;
1243 case TARGET_RLIMIT_NOFILE:
1244 return RLIMIT_NOFILE;
1245 case TARGET_RLIMIT_NPROC:
1246 return RLIMIT_NPROC;
1247 case TARGET_RLIMIT_RSS:
1248 return RLIMIT_RSS;
1249 case TARGET_RLIMIT_RTPRIO:
1250 return RLIMIT_RTPRIO;
1251 case TARGET_RLIMIT_SIGPENDING:
1252 return RLIMIT_SIGPENDING;
1253 case TARGET_RLIMIT_STACK:
1254 return RLIMIT_STACK;
1255 default:
1256 return code;
1257 }
1258}
1259
ths788f5ec2007-12-09 02:37:05 +00001260static inline abi_long copy_from_user_timeval(struct timeval *tv,
1261 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001262{
pbrook53a59602006-03-25 19:31:22 +00001263 struct target_timeval *target_tv;
1264
ths788f5ec2007-12-09 02:37:05 +00001265 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001266 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001267
1268 __get_user(tv->tv_sec, &target_tv->tv_sec);
1269 __get_user(tv->tv_usec, &target_tv->tv_usec);
1270
1271 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001272
1273 return 0;
bellard31e31b82003-02-18 22:55:36 +00001274}
1275
ths788f5ec2007-12-09 02:37:05 +00001276static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1277 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001278{
pbrook53a59602006-03-25 19:31:22 +00001279 struct target_timeval *target_tv;
1280
ths788f5ec2007-12-09 02:37:05 +00001281 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001282 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001283
1284 __put_user(tv->tv_sec, &target_tv->tv_sec);
1285 __put_user(tv->tv_usec, &target_tv->tv_usec);
1286
1287 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001288
1289 return 0;
bellard31e31b82003-02-18 22:55:36 +00001290}
1291
Paul Burtonef4467e2014-06-22 11:25:40 +01001292static inline abi_long copy_from_user_timezone(struct timezone *tz,
1293 abi_ulong target_tz_addr)
1294{
1295 struct target_timezone *target_tz;
1296
1297 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1298 return -TARGET_EFAULT;
1299 }
1300
1301 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1302 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1303
1304 unlock_user_struct(target_tz, target_tz_addr, 0);
1305
1306 return 0;
1307}
1308
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001309#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1310#include <mqueue.h>
1311
aurel3224e10032009-04-15 16:11:43 +00001312static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1313 abi_ulong target_mq_attr_addr)
1314{
1315 struct target_mq_attr *target_mq_attr;
1316
1317 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1318 target_mq_attr_addr, 1))
1319 return -TARGET_EFAULT;
1320
1321 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1322 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1323 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1324 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1325
1326 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1327
1328 return 0;
1329}
1330
1331static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1332 const struct mq_attr *attr)
1333{
1334 struct target_mq_attr *target_mq_attr;
1335
1336 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1337 target_mq_attr_addr, 0))
1338 return -TARGET_EFAULT;
1339
1340 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1341 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1342 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1343 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1344
1345 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1346
1347 return 0;
1348}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001349#endif
bellard31e31b82003-02-18 22:55:36 +00001350
Mike Frysinger055e0902011-06-03 17:01:49 -04001351#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001352/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001353static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001354 abi_ulong rfd_addr, abi_ulong wfd_addr,
1355 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001356{
1357 fd_set rfds, wfds, efds;
1358 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001359 struct timeval tv;
1360 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001361 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001362
Mike Frysinger055e0902011-06-03 17:01:49 -04001363 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1364 if (ret) {
1365 return ret;
pbrook53a59602006-03-25 19:31:22 +00001366 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001367 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1368 if (ret) {
1369 return ret;
pbrook53a59602006-03-25 19:31:22 +00001370 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001371 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1372 if (ret) {
1373 return ret;
pbrook53a59602006-03-25 19:31:22 +00001374 }
ths3b46e622007-09-17 08:09:54 +00001375
ths26edcf42007-12-09 02:25:24 +00001376 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001377 if (copy_from_user_timeval(&tv, target_tv_addr))
1378 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001379 ts.tv_sec = tv.tv_sec;
1380 ts.tv_nsec = tv.tv_usec * 1000;
1381 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001382 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001383 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001384 }
ths26edcf42007-12-09 02:25:24 +00001385
Peter Maydell6df9d382016-05-12 18:47:51 +01001386 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1387 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001388
ths26edcf42007-12-09 02:25:24 +00001389 if (!is_error(ret)) {
1390 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1391 return -TARGET_EFAULT;
1392 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1393 return -TARGET_EFAULT;
1394 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1395 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001396
Peter Maydell6df9d382016-05-12 18:47:51 +01001397 if (target_tv_addr) {
1398 tv.tv_sec = ts.tv_sec;
1399 tv.tv_usec = ts.tv_nsec / 1000;
1400 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1401 return -TARGET_EFAULT;
1402 }
1403 }
bellard31e31b82003-02-18 22:55:36 +00001404 }
bellard579a97f2007-11-11 14:26:47 +00001405
bellard31e31b82003-02-18 22:55:36 +00001406 return ret;
1407}
Mike Frysinger055e0902011-06-03 17:01:49 -04001408#endif
bellard31e31b82003-02-18 22:55:36 +00001409
Riku Voipio099d6b02009-05-05 12:10:04 +03001410static abi_long do_pipe2(int host_pipe[], int flags)
1411{
1412#ifdef CONFIG_PIPE2
1413 return pipe2(host_pipe, flags);
1414#else
1415 return -ENOSYS;
1416#endif
1417}
1418
Richard Hendersonfb41a662010-05-03 10:07:52 -07001419static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1420 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001421{
1422 int host_pipe[2];
1423 abi_long ret;
1424 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1425
1426 if (is_error(ret))
1427 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001428
1429 /* Several targets have special calling conventions for the original
1430 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1431 if (!is_pipe2) {
1432#if defined(TARGET_ALPHA)
1433 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1434 return host_pipe[0];
1435#elif defined(TARGET_MIPS)
1436 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1437 return host_pipe[0];
1438#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001439 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001440 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001441#elif defined(TARGET_SPARC)
1442 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1443 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001444#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001445 }
1446
Riku Voipio099d6b02009-05-05 12:10:04 +03001447 if (put_user_s32(host_pipe[0], pipedes)
1448 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1449 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001450 return get_errno(ret);
1451}
1452
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001453static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1454 abi_ulong target_addr,
1455 socklen_t len)
1456{
1457 struct target_ip_mreqn *target_smreqn;
1458
1459 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1460 if (!target_smreqn)
1461 return -TARGET_EFAULT;
1462 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1463 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1464 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001465 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001466 unlock_user(target_smreqn, target_addr, 0);
1467
1468 return 0;
1469}
1470
Laurent Vivier7b36f782015-10-28 21:40:44 +01001471static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001472 abi_ulong target_addr,
1473 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001474{
aurel32607175e2009-04-15 16:11:59 +00001475 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1476 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001477 struct target_sockaddr *target_saddr;
1478
Laurent Vivier7b36f782015-10-28 21:40:44 +01001479 if (fd_trans_target_to_host_addr(fd)) {
1480 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1481 }
1482
bellard579a97f2007-11-11 14:26:47 +00001483 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1484 if (!target_saddr)
1485 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001486
1487 sa_family = tswap16(target_saddr->sa_family);
1488
1489 /* Oops. The caller might send a incomplete sun_path; sun_path
1490 * must be terminated by \0 (see the manual page), but
1491 * unfortunately it is quite common to specify sockaddr_un
1492 * length as "strlen(x->sun_path)" while it should be
1493 * "strlen(...) + 1". We'll fix that here if needed.
1494 * Linux kernel has a similar feature.
1495 */
1496
1497 if (sa_family == AF_UNIX) {
1498 if (len < unix_maxlen && len > 0) {
1499 char *cp = (char*)target_saddr;
1500
1501 if ( cp[len-1] && !cp[len] )
1502 len++;
1503 }
1504 if (len > unix_maxlen)
1505 len = unix_maxlen;
1506 }
1507
pbrook53a59602006-03-25 19:31:22 +00001508 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001509 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001510 if (sa_family == AF_NETLINK) {
1511 struct sockaddr_nl *nladdr;
1512
1513 nladdr = (struct sockaddr_nl *)addr;
1514 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1515 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1516 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001517 struct target_sockaddr_ll *lladdr;
1518
1519 lladdr = (struct target_sockaddr_ll *)addr;
1520 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1521 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1522 }
pbrook53a59602006-03-25 19:31:22 +00001523 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001524
1525 return 0;
bellard7854b052003-03-29 17:22:23 +00001526}
1527
bellard579a97f2007-11-11 14:26:47 +00001528static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1529 struct sockaddr *addr,
1530 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001531{
pbrook53a59602006-03-25 19:31:22 +00001532 struct target_sockaddr *target_saddr;
1533
Peter Maydella1e22192016-07-07 15:44:43 +01001534 if (len == 0) {
1535 return 0;
1536 }
1537
bellard579a97f2007-11-11 14:26:47 +00001538 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1539 if (!target_saddr)
1540 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001541 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001542 if (len >= offsetof(struct target_sockaddr, sa_family) +
1543 sizeof(target_saddr->sa_family)) {
1544 target_saddr->sa_family = tswap16(addr->sa_family);
1545 }
1546 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001547 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1548 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1549 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001550 } else if (addr->sa_family == AF_PACKET) {
1551 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1552 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1553 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001554 }
pbrook53a59602006-03-25 19:31:22 +00001555 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001556
1557 return 0;
bellard7854b052003-03-29 17:22:23 +00001558}
1559
bellard5a4a8982007-11-11 17:39:18 +00001560static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1561 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001562{
1563 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001564 abi_long msg_controllen;
1565 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001566 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001567 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001568
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001569 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001570 if (msg_controllen < sizeof (struct target_cmsghdr))
1571 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001572 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001573 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001574 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001575 if (!target_cmsg)
1576 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001577
1578 while (cmsg && target_cmsg) {
1579 void *data = CMSG_DATA(cmsg);
1580 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1581
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001582 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001583 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1584
1585 space += CMSG_SPACE(len);
1586 if (space > msgh->msg_controllen) {
1587 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001588 /* This is a QEMU bug, since we allocated the payload
1589 * area ourselves (unlike overflow in host-to-target
1590 * conversion, which is just the guest giving us a buffer
1591 * that's too small). It can't happen for the payload types
1592 * we currently support; if it becomes an issue in future
1593 * we would need to improve our allocation strategy to
1594 * something more intelligent than "twice the size of the
1595 * target buffer we're reading from".
1596 */
bellard31febb72005-12-18 20:03:27 +00001597 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001598 break;
1599 }
1600
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001601 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1602 cmsg->cmsg_level = SOL_SOCKET;
1603 } else {
1604 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1605 }
bellard7854b052003-03-29 17:22:23 +00001606 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1607 cmsg->cmsg_len = CMSG_LEN(len);
1608
Alex Suykov30b8b682014-12-23 07:52:58 +02001609 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001610 int *fd = (int *)data;
1611 int *target_fd = (int *)target_data;
1612 int i, numfds = len / sizeof(int);
1613
Peter Maydell876e23c2015-05-26 19:46:32 +01001614 for (i = 0; i < numfds; i++) {
1615 __get_user(fd[i], target_fd + i);
1616 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001617 } else if (cmsg->cmsg_level == SOL_SOCKET
1618 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1619 struct ucred *cred = (struct ucred *)data;
1620 struct target_ucred *target_cred =
1621 (struct target_ucred *)target_data;
1622
Peter Maydell876e23c2015-05-26 19:46:32 +01001623 __get_user(cred->pid, &target_cred->pid);
1624 __get_user(cred->uid, &target_cred->uid);
1625 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001626 } else {
1627 gemu_log("Unsupported ancillary data: %d/%d\n",
1628 cmsg->cmsg_level, cmsg->cmsg_type);
1629 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001630 }
1631
1632 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001633 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1634 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001635 }
bellard5a4a8982007-11-11 17:39:18 +00001636 unlock_user(target_cmsg, target_cmsg_addr, 0);
1637 the_end:
bellard7854b052003-03-29 17:22:23 +00001638 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001639 return 0;
bellard7854b052003-03-29 17:22:23 +00001640}
1641
bellard5a4a8982007-11-11 17:39:18 +00001642static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1643 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001644{
1645 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001646 abi_long msg_controllen;
1647 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001648 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001649 socklen_t space = 0;
1650
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001651 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001652 if (msg_controllen < sizeof (struct target_cmsghdr))
1653 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001654 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001655 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001656 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001657 if (!target_cmsg)
1658 return -TARGET_EFAULT;
1659
bellard7854b052003-03-29 17:22:23 +00001660 while (cmsg && target_cmsg) {
1661 void *data = CMSG_DATA(cmsg);
1662 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1663
1664 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001665 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001666
Peter Maydellc2aeb252015-05-26 19:46:31 +01001667 /* We never copy a half-header but may copy half-data;
1668 * this is Linux's behaviour in put_cmsg(). Note that
1669 * truncation here is a guest problem (which we report
1670 * to the guest via the CTRUNC bit), unlike truncation
1671 * in target_to_host_cmsg, which is a QEMU bug.
1672 */
1673 if (msg_controllen < sizeof(struct cmsghdr)) {
1674 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001675 break;
1676 }
1677
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001678 if (cmsg->cmsg_level == SOL_SOCKET) {
1679 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1680 } else {
1681 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1682 }
bellard7854b052003-03-29 17:22:23 +00001683 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001684
Peter Maydellc2aeb252015-05-26 19:46:31 +01001685 tgt_len = TARGET_CMSG_LEN(len);
1686
1687 /* Payload types which need a different size of payload on
1688 * the target must adjust tgt_len here.
1689 */
1690 switch (cmsg->cmsg_level) {
1691 case SOL_SOCKET:
1692 switch (cmsg->cmsg_type) {
1693 case SO_TIMESTAMP:
1694 tgt_len = sizeof(struct target_timeval);
1695 break;
1696 default:
1697 break;
1698 }
1699 default:
1700 break;
1701 }
1702
1703 if (msg_controllen < tgt_len) {
1704 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1705 tgt_len = msg_controllen;
1706 }
1707
1708 /* We must now copy-and-convert len bytes of payload
1709 * into tgt_len bytes of destination space. Bear in mind
1710 * that in both source and destination we may be dealing
1711 * with a truncated value!
1712 */
Huw Davies52b65492014-04-17 14:02:47 +01001713 switch (cmsg->cmsg_level) {
1714 case SOL_SOCKET:
1715 switch (cmsg->cmsg_type) {
1716 case SCM_RIGHTS:
1717 {
1718 int *fd = (int *)data;
1719 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001720 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001721
Peter Maydell876e23c2015-05-26 19:46:32 +01001722 for (i = 0; i < numfds; i++) {
1723 __put_user(fd[i], target_fd + i);
1724 }
Huw Davies52b65492014-04-17 14:02:47 +01001725 break;
1726 }
1727 case SO_TIMESTAMP:
1728 {
1729 struct timeval *tv = (struct timeval *)data;
1730 struct target_timeval *target_tv =
1731 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001732
Peter Maydellc2aeb252015-05-26 19:46:31 +01001733 if (len != sizeof(struct timeval) ||
1734 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001735 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001736 }
Huw Davies52b65492014-04-17 14:02:47 +01001737
1738 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001739 __put_user(tv->tv_sec, &target_tv->tv_sec);
1740 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001741 break;
1742 }
Huw Davies4bc29752014-04-17 14:02:48 +01001743 case SCM_CREDENTIALS:
1744 {
1745 struct ucred *cred = (struct ucred *)data;
1746 struct target_ucred *target_cred =
1747 (struct target_ucred *)target_data;
1748
1749 __put_user(cred->pid, &target_cred->pid);
1750 __put_user(cred->uid, &target_cred->uid);
1751 __put_user(cred->gid, &target_cred->gid);
1752 break;
1753 }
Huw Davies52b65492014-04-17 14:02:47 +01001754 default:
1755 goto unimplemented;
1756 }
1757 break;
1758
1759 default:
1760 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001761 gemu_log("Unsupported ancillary data: %d/%d\n",
1762 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001763 memcpy(target_data, data, MIN(len, tgt_len));
1764 if (tgt_len > len) {
1765 memset(target_data + len, 0, tgt_len - len);
1766 }
bellard7854b052003-03-29 17:22:23 +00001767 }
1768
Peter Maydellc2aeb252015-05-26 19:46:31 +01001769 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001770 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001771 if (msg_controllen < tgt_space) {
1772 tgt_space = msg_controllen;
1773 }
1774 msg_controllen -= tgt_space;
1775 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001776 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001777 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1778 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001779 }
bellard5a4a8982007-11-11 17:39:18 +00001780 unlock_user(target_cmsg, target_cmsg_addr, space);
1781 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001782 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001783 return 0;
bellard7854b052003-03-29 17:22:23 +00001784}
1785
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001786static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1787{
1788 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1789 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1790 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1791 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1792 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1793}
1794
1795static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1796 size_t len,
1797 abi_long (*host_to_target_nlmsg)
1798 (struct nlmsghdr *))
1799{
1800 uint32_t nlmsg_len;
1801 abi_long ret;
1802
1803 while (len > sizeof(struct nlmsghdr)) {
1804
1805 nlmsg_len = nlh->nlmsg_len;
1806 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1807 nlmsg_len > len) {
1808 break;
1809 }
1810
1811 switch (nlh->nlmsg_type) {
1812 case NLMSG_DONE:
1813 tswap_nlmsghdr(nlh);
1814 return 0;
1815 case NLMSG_NOOP:
1816 break;
1817 case NLMSG_ERROR:
1818 {
1819 struct nlmsgerr *e = NLMSG_DATA(nlh);
1820 e->error = tswap32(e->error);
1821 tswap_nlmsghdr(&e->msg);
1822 tswap_nlmsghdr(nlh);
1823 return 0;
1824 }
1825 default:
1826 ret = host_to_target_nlmsg(nlh);
1827 if (ret < 0) {
1828 tswap_nlmsghdr(nlh);
1829 return ret;
1830 }
1831 break;
1832 }
1833 tswap_nlmsghdr(nlh);
1834 len -= NLMSG_ALIGN(nlmsg_len);
1835 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1836 }
1837 return 0;
1838}
1839
1840static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1841 size_t len,
1842 abi_long (*target_to_host_nlmsg)
1843 (struct nlmsghdr *))
1844{
1845 int ret;
1846
1847 while (len > sizeof(struct nlmsghdr)) {
1848 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1849 tswap32(nlh->nlmsg_len) > len) {
1850 break;
1851 }
1852 tswap_nlmsghdr(nlh);
1853 switch (nlh->nlmsg_type) {
1854 case NLMSG_DONE:
1855 return 0;
1856 case NLMSG_NOOP:
1857 break;
1858 case NLMSG_ERROR:
1859 {
1860 struct nlmsgerr *e = NLMSG_DATA(nlh);
1861 e->error = tswap32(e->error);
1862 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02001863 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001864 }
1865 default:
1866 ret = target_to_host_nlmsg(nlh);
1867 if (ret < 0) {
1868 return ret;
1869 }
1870 }
1871 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1872 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1873 }
1874 return 0;
1875}
1876
Laurent Vivier575b22b2016-06-02 22:14:15 +02001877#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02001878static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
1879 size_t len, void *context,
1880 abi_long (*host_to_target_nlattr)
1881 (struct nlattr *,
1882 void *context))
1883{
1884 unsigned short nla_len;
1885 abi_long ret;
1886
1887 while (len > sizeof(struct nlattr)) {
1888 nla_len = nlattr->nla_len;
1889 if (nla_len < sizeof(struct nlattr) ||
1890 nla_len > len) {
1891 break;
1892 }
1893 ret = host_to_target_nlattr(nlattr, context);
1894 nlattr->nla_len = tswap16(nlattr->nla_len);
1895 nlattr->nla_type = tswap16(nlattr->nla_type);
1896 if (ret < 0) {
1897 return ret;
1898 }
1899 len -= NLA_ALIGN(nla_len);
1900 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
1901 }
1902 return 0;
1903}
1904
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001905static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1906 size_t len,
1907 abi_long (*host_to_target_rtattr)
1908 (struct rtattr *))
1909{
1910 unsigned short rta_len;
1911 abi_long ret;
1912
1913 while (len > sizeof(struct rtattr)) {
1914 rta_len = rtattr->rta_len;
1915 if (rta_len < sizeof(struct rtattr) ||
1916 rta_len > len) {
1917 break;
1918 }
1919 ret = host_to_target_rtattr(rtattr);
1920 rtattr->rta_len = tswap16(rtattr->rta_len);
1921 rtattr->rta_type = tswap16(rtattr->rta_type);
1922 if (ret < 0) {
1923 return ret;
1924 }
1925 len -= RTA_ALIGN(rta_len);
1926 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1927 }
1928 return 0;
1929}
1930
Laurent Vivierc5dff282016-06-27 18:54:30 +02001931#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
1932
1933static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
1934 void *context)
1935{
1936 uint16_t *u16;
1937 uint32_t *u32;
1938 uint64_t *u64;
1939
1940 switch (nlattr->nla_type) {
1941 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001942 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001943 break;
1944 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001945 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001946 break;
1947 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001948 case QEMU_IFLA_BR_VLAN_FILTERING:
1949 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
1950 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
1951 case QEMU_IFLA_BR_MCAST_ROUTER:
1952 case QEMU_IFLA_BR_MCAST_SNOOPING:
1953 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
1954 case QEMU_IFLA_BR_MCAST_QUERIER:
1955 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
1956 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
1957 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001958 break;
1959 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001960 case QEMU_IFLA_BR_PRIORITY:
1961 case QEMU_IFLA_BR_VLAN_PROTOCOL:
1962 case QEMU_IFLA_BR_GROUP_FWD_MASK:
1963 case QEMU_IFLA_BR_ROOT_PORT:
1964 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001965 u16 = NLA_DATA(nlattr);
1966 *u16 = tswap16(*u16);
1967 break;
1968 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001969 case QEMU_IFLA_BR_FORWARD_DELAY:
1970 case QEMU_IFLA_BR_HELLO_TIME:
1971 case QEMU_IFLA_BR_MAX_AGE:
1972 case QEMU_IFLA_BR_AGEING_TIME:
1973 case QEMU_IFLA_BR_STP_STATE:
1974 case QEMU_IFLA_BR_ROOT_PATH_COST:
1975 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
1976 case QEMU_IFLA_BR_MCAST_HASH_MAX:
1977 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
1978 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001979 u32 = NLA_DATA(nlattr);
1980 *u32 = tswap32(*u32);
1981 break;
1982 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001983 case QEMU_IFLA_BR_HELLO_TIMER:
1984 case QEMU_IFLA_BR_TCN_TIMER:
1985 case QEMU_IFLA_BR_GC_TIMER:
1986 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
1987 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
1988 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
1989 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
1990 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
1991 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
1992 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001993 u64 = NLA_DATA(nlattr);
1994 *u64 = tswap64(*u64);
1995 break;
1996 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02001997 case QEMU_IFLA_BR_ROOT_ID:
1998 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02001999 break;
2000 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002001 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002002 break;
2003 }
2004 return 0;
2005}
2006
2007static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2008 void *context)
2009{
2010 uint16_t *u16;
2011 uint32_t *u32;
2012 uint64_t *u64;
2013
2014 switch (nlattr->nla_type) {
2015 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002016 case QEMU_IFLA_BRPORT_STATE:
2017 case QEMU_IFLA_BRPORT_MODE:
2018 case QEMU_IFLA_BRPORT_GUARD:
2019 case QEMU_IFLA_BRPORT_PROTECT:
2020 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2021 case QEMU_IFLA_BRPORT_LEARNING:
2022 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2023 case QEMU_IFLA_BRPORT_PROXYARP:
2024 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2025 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2026 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2027 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2028 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002029 break;
2030 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002031 case QEMU_IFLA_BRPORT_PRIORITY:
2032 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2033 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2034 case QEMU_IFLA_BRPORT_ID:
2035 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002036 u16 = NLA_DATA(nlattr);
2037 *u16 = tswap16(*u16);
2038 break;
2039 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002040 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002041 u32 = NLA_DATA(nlattr);
2042 *u32 = tswap32(*u32);
2043 break;
2044 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002045 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2046 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2047 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002048 u64 = NLA_DATA(nlattr);
2049 *u64 = tswap64(*u64);
2050 break;
2051 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002052 case QEMU_IFLA_BRPORT_ROOT_ID:
2053 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002054 break;
2055 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002056 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002057 break;
2058 }
2059 return 0;
2060}
2061
2062struct linkinfo_context {
2063 int len;
2064 char *name;
2065 int slave_len;
2066 char *slave_name;
2067};
2068
2069static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2070 void *context)
2071{
2072 struct linkinfo_context *li_context = context;
2073
2074 switch (nlattr->nla_type) {
2075 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002076 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002077 li_context->name = NLA_DATA(nlattr);
2078 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2079 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002080 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002081 li_context->slave_name = NLA_DATA(nlattr);
2082 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2083 break;
2084 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002085 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002086 /* FIXME: only used by CAN */
2087 break;
2088 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002089 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002090 if (strncmp(li_context->name, "bridge",
2091 li_context->len) == 0) {
2092 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2093 nlattr->nla_len,
2094 NULL,
2095 host_to_target_data_bridge_nlattr);
2096 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002097 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002098 }
2099 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002100 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002101 if (strncmp(li_context->slave_name, "bridge",
2102 li_context->slave_len) == 0) {
2103 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2104 nlattr->nla_len,
2105 NULL,
2106 host_to_target_slave_data_bridge_nlattr);
2107 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002108 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002109 li_context->slave_name);
2110 }
2111 break;
2112 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002113 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002114 break;
2115 }
2116
2117 return 0;
2118}
2119
2120static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2121 void *context)
2122{
2123 uint32_t *u32;
2124 int i;
2125
2126 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002127 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002128 u32 = NLA_DATA(nlattr);
2129 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2130 i++) {
2131 u32[i] = tswap32(u32[i]);
2132 }
2133 break;
2134 default:
2135 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2136 }
2137 return 0;
2138}
2139
2140static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2141 void *context)
2142{
2143 uint32_t *u32;
2144 uint64_t *u64;
2145 struct ifla_cacheinfo *ci;
2146 int i;
2147
2148 switch (nlattr->nla_type) {
2149 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002150 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002151 break;
2152 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002153 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002154 break;
2155 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002156 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002157 u32 = NLA_DATA(nlattr);
2158 *u32 = tswap32(*u32);
2159 break;
2160 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002161 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002162 u32 = NLA_DATA(nlattr);
2163 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2164 i++) {
2165 u32[i] = tswap32(u32[i]);
2166 }
2167 break;
2168 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002169 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002170 ci = NLA_DATA(nlattr);
2171 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2172 ci->tstamp = tswap32(ci->tstamp);
2173 ci->reachable_time = tswap32(ci->reachable_time);
2174 ci->retrans_time = tswap32(ci->retrans_time);
2175 break;
2176 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002177 case QEMU_IFLA_INET6_STATS:
2178 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002179 u64 = NLA_DATA(nlattr);
2180 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2181 i++) {
2182 u64[i] = tswap64(u64[i]);
2183 }
2184 break;
2185 default:
2186 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2187 }
2188 return 0;
2189}
2190
2191static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2192 void *context)
2193{
2194 switch (nlattr->nla_type) {
2195 case AF_INET:
2196 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2197 NULL,
2198 host_to_target_data_inet_nlattr);
2199 case AF_INET6:
2200 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2201 NULL,
2202 host_to_target_data_inet6_nlattr);
2203 default:
2204 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2205 break;
2206 }
2207 return 0;
2208}
2209
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002210static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2211{
2212 uint32_t *u32;
2213 struct rtnl_link_stats *st;
2214 struct rtnl_link_stats64 *st64;
2215 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002216 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002217
2218 switch (rtattr->rta_type) {
2219 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002220 case QEMU_IFLA_ADDRESS:
2221 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002222 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002223 case QEMU_IFLA_IFNAME:
2224 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002225 break;
2226 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002227 case QEMU_IFLA_OPERSTATE:
2228 case QEMU_IFLA_LINKMODE:
2229 case QEMU_IFLA_CARRIER:
2230 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002231 break;
2232 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002233 case QEMU_IFLA_MTU:
2234 case QEMU_IFLA_LINK:
2235 case QEMU_IFLA_WEIGHT:
2236 case QEMU_IFLA_TXQLEN:
2237 case QEMU_IFLA_CARRIER_CHANGES:
2238 case QEMU_IFLA_NUM_RX_QUEUES:
2239 case QEMU_IFLA_NUM_TX_QUEUES:
2240 case QEMU_IFLA_PROMISCUITY:
2241 case QEMU_IFLA_EXT_MASK:
2242 case QEMU_IFLA_LINK_NETNSID:
2243 case QEMU_IFLA_GROUP:
2244 case QEMU_IFLA_MASTER:
2245 case QEMU_IFLA_NUM_VF:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002246 u32 = RTA_DATA(rtattr);
2247 *u32 = tswap32(*u32);
2248 break;
2249 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002250 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002251 st = RTA_DATA(rtattr);
2252 st->rx_packets = tswap32(st->rx_packets);
2253 st->tx_packets = tswap32(st->tx_packets);
2254 st->rx_bytes = tswap32(st->rx_bytes);
2255 st->tx_bytes = tswap32(st->tx_bytes);
2256 st->rx_errors = tswap32(st->rx_errors);
2257 st->tx_errors = tswap32(st->tx_errors);
2258 st->rx_dropped = tswap32(st->rx_dropped);
2259 st->tx_dropped = tswap32(st->tx_dropped);
2260 st->multicast = tswap32(st->multicast);
2261 st->collisions = tswap32(st->collisions);
2262
2263 /* detailed rx_errors: */
2264 st->rx_length_errors = tswap32(st->rx_length_errors);
2265 st->rx_over_errors = tswap32(st->rx_over_errors);
2266 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2267 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2268 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2269 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2270
2271 /* detailed tx_errors */
2272 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2273 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2274 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2275 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2276 st->tx_window_errors = tswap32(st->tx_window_errors);
2277
2278 /* for cslip etc */
2279 st->rx_compressed = tswap32(st->rx_compressed);
2280 st->tx_compressed = tswap32(st->tx_compressed);
2281 break;
2282 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002283 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002284 st64 = RTA_DATA(rtattr);
2285 st64->rx_packets = tswap64(st64->rx_packets);
2286 st64->tx_packets = tswap64(st64->tx_packets);
2287 st64->rx_bytes = tswap64(st64->rx_bytes);
2288 st64->tx_bytes = tswap64(st64->tx_bytes);
2289 st64->rx_errors = tswap64(st64->rx_errors);
2290 st64->tx_errors = tswap64(st64->tx_errors);
2291 st64->rx_dropped = tswap64(st64->rx_dropped);
2292 st64->tx_dropped = tswap64(st64->tx_dropped);
2293 st64->multicast = tswap64(st64->multicast);
2294 st64->collisions = tswap64(st64->collisions);
2295
2296 /* detailed rx_errors: */
2297 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2298 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2299 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2300 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2301 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2302 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2303
2304 /* detailed tx_errors */
2305 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2306 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2307 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2308 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2309 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2310
2311 /* for cslip etc */
2312 st64->rx_compressed = tswap64(st64->rx_compressed);
2313 st64->tx_compressed = tswap64(st64->tx_compressed);
2314 break;
2315 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002316 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002317 map = RTA_DATA(rtattr);
2318 map->mem_start = tswap64(map->mem_start);
2319 map->mem_end = tswap64(map->mem_end);
2320 map->base_addr = tswap64(map->base_addr);
2321 map->irq = tswap16(map->irq);
2322 break;
2323 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002324 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002325 memset(&li_context, 0, sizeof(li_context));
2326 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2327 &li_context,
2328 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002329 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002330 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2331 NULL,
2332 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002333 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002334 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002335 break;
2336 }
2337 return 0;
2338}
2339
2340static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2341{
2342 uint32_t *u32;
2343 struct ifa_cacheinfo *ci;
2344
2345 switch (rtattr->rta_type) {
2346 /* binary: depends on family type */
2347 case IFA_ADDRESS:
2348 case IFA_LOCAL:
2349 break;
2350 /* string */
2351 case IFA_LABEL:
2352 break;
2353 /* u32 */
2354 case IFA_FLAGS:
2355 case IFA_BROADCAST:
2356 u32 = RTA_DATA(rtattr);
2357 *u32 = tswap32(*u32);
2358 break;
2359 /* struct ifa_cacheinfo */
2360 case IFA_CACHEINFO:
2361 ci = RTA_DATA(rtattr);
2362 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2363 ci->ifa_valid = tswap32(ci->ifa_valid);
2364 ci->cstamp = tswap32(ci->cstamp);
2365 ci->tstamp = tswap32(ci->tstamp);
2366 break;
2367 default:
2368 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2369 break;
2370 }
2371 return 0;
2372}
2373
2374static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2375{
2376 uint32_t *u32;
2377 switch (rtattr->rta_type) {
2378 /* binary: depends on family type */
2379 case RTA_GATEWAY:
2380 case RTA_DST:
2381 case RTA_PREFSRC:
2382 break;
2383 /* u32 */
2384 case RTA_PRIORITY:
2385 case RTA_TABLE:
2386 case RTA_OIF:
2387 u32 = RTA_DATA(rtattr);
2388 *u32 = tswap32(*u32);
2389 break;
2390 default:
2391 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2392 break;
2393 }
2394 return 0;
2395}
2396
2397static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2398 uint32_t rtattr_len)
2399{
2400 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2401 host_to_target_data_link_rtattr);
2402}
2403
2404static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2405 uint32_t rtattr_len)
2406{
2407 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2408 host_to_target_data_addr_rtattr);
2409}
2410
2411static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2412 uint32_t rtattr_len)
2413{
2414 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2415 host_to_target_data_route_rtattr);
2416}
2417
2418static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2419{
2420 uint32_t nlmsg_len;
2421 struct ifinfomsg *ifi;
2422 struct ifaddrmsg *ifa;
2423 struct rtmsg *rtm;
2424
2425 nlmsg_len = nlh->nlmsg_len;
2426 switch (nlh->nlmsg_type) {
2427 case RTM_NEWLINK:
2428 case RTM_DELLINK:
2429 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002430 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2431 ifi = NLMSG_DATA(nlh);
2432 ifi->ifi_type = tswap16(ifi->ifi_type);
2433 ifi->ifi_index = tswap32(ifi->ifi_index);
2434 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2435 ifi->ifi_change = tswap32(ifi->ifi_change);
2436 host_to_target_link_rtattr(IFLA_RTA(ifi),
2437 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2438 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002439 break;
2440 case RTM_NEWADDR:
2441 case RTM_DELADDR:
2442 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002443 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2444 ifa = NLMSG_DATA(nlh);
2445 ifa->ifa_index = tswap32(ifa->ifa_index);
2446 host_to_target_addr_rtattr(IFA_RTA(ifa),
2447 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2448 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002449 break;
2450 case RTM_NEWROUTE:
2451 case RTM_DELROUTE:
2452 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002453 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2454 rtm = NLMSG_DATA(nlh);
2455 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2456 host_to_target_route_rtattr(RTM_RTA(rtm),
2457 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2458 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002459 break;
2460 default:
2461 return -TARGET_EINVAL;
2462 }
2463 return 0;
2464}
2465
2466static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2467 size_t len)
2468{
2469 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2470}
2471
2472static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2473 size_t len,
2474 abi_long (*target_to_host_rtattr)
2475 (struct rtattr *))
2476{
2477 abi_long ret;
2478
2479 while (len >= sizeof(struct rtattr)) {
2480 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2481 tswap16(rtattr->rta_len) > len) {
2482 break;
2483 }
2484 rtattr->rta_len = tswap16(rtattr->rta_len);
2485 rtattr->rta_type = tswap16(rtattr->rta_type);
2486 ret = target_to_host_rtattr(rtattr);
2487 if (ret < 0) {
2488 return ret;
2489 }
2490 len -= RTA_ALIGN(rtattr->rta_len);
2491 rtattr = (struct rtattr *)(((char *)rtattr) +
2492 RTA_ALIGN(rtattr->rta_len));
2493 }
2494 return 0;
2495}
2496
2497static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2498{
2499 switch (rtattr->rta_type) {
2500 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002501 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002502 break;
2503 }
2504 return 0;
2505}
2506
2507static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2508{
2509 switch (rtattr->rta_type) {
2510 /* binary: depends on family type */
2511 case IFA_LOCAL:
2512 case IFA_ADDRESS:
2513 break;
2514 default:
2515 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2516 break;
2517 }
2518 return 0;
2519}
2520
2521static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2522{
2523 uint32_t *u32;
2524 switch (rtattr->rta_type) {
2525 /* binary: depends on family type */
2526 case RTA_DST:
2527 case RTA_SRC:
2528 case RTA_GATEWAY:
2529 break;
2530 /* u32 */
2531 case RTA_OIF:
2532 u32 = RTA_DATA(rtattr);
2533 *u32 = tswap32(*u32);
2534 break;
2535 default:
2536 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2537 break;
2538 }
2539 return 0;
2540}
2541
2542static void target_to_host_link_rtattr(struct rtattr *rtattr,
2543 uint32_t rtattr_len)
2544{
2545 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2546 target_to_host_data_link_rtattr);
2547}
2548
2549static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2550 uint32_t rtattr_len)
2551{
2552 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2553 target_to_host_data_addr_rtattr);
2554}
2555
2556static void target_to_host_route_rtattr(struct rtattr *rtattr,
2557 uint32_t rtattr_len)
2558{
2559 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2560 target_to_host_data_route_rtattr);
2561}
2562
2563static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2564{
2565 struct ifinfomsg *ifi;
2566 struct ifaddrmsg *ifa;
2567 struct rtmsg *rtm;
2568
2569 switch (nlh->nlmsg_type) {
2570 case RTM_GETLINK:
2571 break;
2572 case RTM_NEWLINK:
2573 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002574 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2575 ifi = NLMSG_DATA(nlh);
2576 ifi->ifi_type = tswap16(ifi->ifi_type);
2577 ifi->ifi_index = tswap32(ifi->ifi_index);
2578 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2579 ifi->ifi_change = tswap32(ifi->ifi_change);
2580 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2581 NLMSG_LENGTH(sizeof(*ifi)));
2582 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002583 break;
2584 case RTM_GETADDR:
2585 case RTM_NEWADDR:
2586 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002587 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2588 ifa = NLMSG_DATA(nlh);
2589 ifa->ifa_index = tswap32(ifa->ifa_index);
2590 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2591 NLMSG_LENGTH(sizeof(*ifa)));
2592 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002593 break;
2594 case RTM_GETROUTE:
2595 break;
2596 case RTM_NEWROUTE:
2597 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002598 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2599 rtm = NLMSG_DATA(nlh);
2600 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2601 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2602 NLMSG_LENGTH(sizeof(*rtm)));
2603 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002604 break;
2605 default:
2606 return -TARGET_EOPNOTSUPP;
2607 }
2608 return 0;
2609}
2610
2611static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2612{
2613 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2614}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002615#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002616
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002617static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2618{
2619 switch (nlh->nlmsg_type) {
2620 default:
2621 gemu_log("Unknown host audit message type %d\n",
2622 nlh->nlmsg_type);
2623 return -TARGET_EINVAL;
2624 }
2625 return 0;
2626}
2627
2628static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2629 size_t len)
2630{
2631 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2632}
2633
2634static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2635{
2636 switch (nlh->nlmsg_type) {
2637 case AUDIT_USER:
2638 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2639 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2640 break;
2641 default:
2642 gemu_log("Unknown target audit message type %d\n",
2643 nlh->nlmsg_type);
2644 return -TARGET_EINVAL;
2645 }
2646
2647 return 0;
2648}
2649
2650static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2651{
2652 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2653}
2654
ths0da46a62007-10-20 20:23:07 +00002655/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002656static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002657 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002658{
blueswir1992f48a2007-10-14 16:27:31 +00002659 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002660 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002661 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002662 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002663
bellard8853f862004-02-22 14:57:26 +00002664 switch(level) {
2665 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002666 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002667 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002668 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002669
bellard2f619692007-11-16 10:46:05 +00002670 if (get_user_u32(val, optval_addr))
2671 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002672 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2673 break;
2674 case SOL_IP:
2675 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002676 case IP_TOS:
2677 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002678 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002679 case IP_ROUTER_ALERT:
2680 case IP_RECVOPTS:
2681 case IP_RETOPTS:
2682 case IP_PKTINFO:
2683 case IP_MTU_DISCOVER:
2684 case IP_RECVERR:
2685 case IP_RECVTOS:
2686#ifdef IP_FREEBIND
2687 case IP_FREEBIND:
2688#endif
2689 case IP_MULTICAST_TTL:
2690 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002691 val = 0;
2692 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002693 if (get_user_u32(val, optval_addr))
2694 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002695 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002696 if (get_user_u8(val, optval_addr))
2697 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002698 }
2699 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2700 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002701 case IP_ADD_MEMBERSHIP:
2702 case IP_DROP_MEMBERSHIP:
2703 if (optlen < sizeof (struct target_ip_mreq) ||
2704 optlen > sizeof (struct target_ip_mreqn))
2705 return -TARGET_EINVAL;
2706
2707 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2708 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2709 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2710 break;
2711
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002712 case IP_BLOCK_SOURCE:
2713 case IP_UNBLOCK_SOURCE:
2714 case IP_ADD_SOURCE_MEMBERSHIP:
2715 case IP_DROP_SOURCE_MEMBERSHIP:
2716 if (optlen != sizeof (struct target_ip_mreq_source))
2717 return -TARGET_EINVAL;
2718
2719 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2720 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2721 unlock_user (ip_mreq_source, optval_addr, 0);
2722 break;
2723
bellard8853f862004-02-22 14:57:26 +00002724 default:
2725 goto unimplemented;
2726 }
2727 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002728 case SOL_IPV6:
2729 switch (optname) {
2730 case IPV6_MTU_DISCOVER:
2731 case IPV6_MTU:
2732 case IPV6_V6ONLY:
2733 case IPV6_RECVPKTINFO:
2734 val = 0;
2735 if (optlen < sizeof(uint32_t)) {
2736 return -TARGET_EINVAL;
2737 }
2738 if (get_user_u32(val, optval_addr)) {
2739 return -TARGET_EFAULT;
2740 }
2741 ret = get_errno(setsockopt(sockfd, level, optname,
2742 &val, sizeof(val)));
2743 break;
2744 default:
2745 goto unimplemented;
2746 }
2747 break;
Jing Huang920394d2012-07-24 13:59:23 +00002748 case SOL_RAW:
2749 switch (optname) {
2750 case ICMP_FILTER:
2751 /* struct icmp_filter takes an u32 value */
2752 if (optlen < sizeof(uint32_t)) {
2753 return -TARGET_EINVAL;
2754 }
2755
2756 if (get_user_u32(val, optval_addr)) {
2757 return -TARGET_EFAULT;
2758 }
2759 ret = get_errno(setsockopt(sockfd, level, optname,
2760 &val, sizeof(val)));
2761 break;
2762
2763 default:
2764 goto unimplemented;
2765 }
2766 break;
bellard3532fa72006-06-24 15:06:03 +00002767 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002768 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002769 case TARGET_SO_RCVTIMEO:
2770 {
2771 struct timeval tv;
2772
2773 optname = SO_RCVTIMEO;
2774
2775set_timeout:
2776 if (optlen != sizeof(struct target_timeval)) {
2777 return -TARGET_EINVAL;
2778 }
2779
2780 if (copy_from_user_timeval(&tv, optval_addr)) {
2781 return -TARGET_EFAULT;
2782 }
2783
2784 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2785 &tv, sizeof(tv)));
2786 return ret;
2787 }
2788 case TARGET_SO_SNDTIMEO:
2789 optname = SO_SNDTIMEO;
2790 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002791 case TARGET_SO_ATTACH_FILTER:
2792 {
2793 struct target_sock_fprog *tfprog;
2794 struct target_sock_filter *tfilter;
2795 struct sock_fprog fprog;
2796 struct sock_filter *filter;
2797 int i;
2798
2799 if (optlen != sizeof(*tfprog)) {
2800 return -TARGET_EINVAL;
2801 }
2802 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2803 return -TARGET_EFAULT;
2804 }
2805 if (!lock_user_struct(VERIFY_READ, tfilter,
2806 tswapal(tfprog->filter), 0)) {
2807 unlock_user_struct(tfprog, optval_addr, 1);
2808 return -TARGET_EFAULT;
2809 }
2810
2811 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302812 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002813 if (filter == NULL) {
2814 unlock_user_struct(tfilter, tfprog->filter, 1);
2815 unlock_user_struct(tfprog, optval_addr, 1);
2816 return -TARGET_ENOMEM;
2817 }
2818 for (i = 0; i < fprog.len; i++) {
2819 filter[i].code = tswap16(tfilter[i].code);
2820 filter[i].jt = tfilter[i].jt;
2821 filter[i].jf = tfilter[i].jf;
2822 filter[i].k = tswap32(tfilter[i].k);
2823 }
2824 fprog.filter = filter;
2825
2826 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2827 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302828 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002829
2830 unlock_user_struct(tfilter, tfprog->filter, 1);
2831 unlock_user_struct(tfprog, optval_addr, 1);
2832 return ret;
2833 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002834 case TARGET_SO_BINDTODEVICE:
2835 {
2836 char *dev_ifname, *addr_ifname;
2837
2838 if (optlen > IFNAMSIZ - 1) {
2839 optlen = IFNAMSIZ - 1;
2840 }
2841 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2842 if (!dev_ifname) {
2843 return -TARGET_EFAULT;
2844 }
2845 optname = SO_BINDTODEVICE;
2846 addr_ifname = alloca(IFNAMSIZ);
2847 memcpy(addr_ifname, dev_ifname, optlen);
2848 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002849 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2850 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002851 unlock_user (dev_ifname, optval_addr, 0);
2852 return ret;
2853 }
bellard8853f862004-02-22 14:57:26 +00002854 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002855 case TARGET_SO_DEBUG:
2856 optname = SO_DEBUG;
2857 break;
2858 case TARGET_SO_REUSEADDR:
2859 optname = SO_REUSEADDR;
2860 break;
2861 case TARGET_SO_TYPE:
2862 optname = SO_TYPE;
2863 break;
2864 case TARGET_SO_ERROR:
2865 optname = SO_ERROR;
2866 break;
2867 case TARGET_SO_DONTROUTE:
2868 optname = SO_DONTROUTE;
2869 break;
2870 case TARGET_SO_BROADCAST:
2871 optname = SO_BROADCAST;
2872 break;
2873 case TARGET_SO_SNDBUF:
2874 optname = SO_SNDBUF;
2875 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002876 case TARGET_SO_SNDBUFFORCE:
2877 optname = SO_SNDBUFFORCE;
2878 break;
bellard3532fa72006-06-24 15:06:03 +00002879 case TARGET_SO_RCVBUF:
2880 optname = SO_RCVBUF;
2881 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002882 case TARGET_SO_RCVBUFFORCE:
2883 optname = SO_RCVBUFFORCE;
2884 break;
bellard3532fa72006-06-24 15:06:03 +00002885 case TARGET_SO_KEEPALIVE:
2886 optname = SO_KEEPALIVE;
2887 break;
2888 case TARGET_SO_OOBINLINE:
2889 optname = SO_OOBINLINE;
2890 break;
2891 case TARGET_SO_NO_CHECK:
2892 optname = SO_NO_CHECK;
2893 break;
2894 case TARGET_SO_PRIORITY:
2895 optname = SO_PRIORITY;
2896 break;
bellard5e83e8e2005-03-01 22:32:06 +00002897#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002898 case TARGET_SO_BSDCOMPAT:
2899 optname = SO_BSDCOMPAT;
2900 break;
bellard5e83e8e2005-03-01 22:32:06 +00002901#endif
bellard3532fa72006-06-24 15:06:03 +00002902 case TARGET_SO_PASSCRED:
2903 optname = SO_PASSCRED;
2904 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002905 case TARGET_SO_PASSSEC:
2906 optname = SO_PASSSEC;
2907 break;
bellard3532fa72006-06-24 15:06:03 +00002908 case TARGET_SO_TIMESTAMP:
2909 optname = SO_TIMESTAMP;
2910 break;
2911 case TARGET_SO_RCVLOWAT:
2912 optname = SO_RCVLOWAT;
2913 break;
bellard8853f862004-02-22 14:57:26 +00002914 break;
2915 default:
2916 goto unimplemented;
2917 }
bellard3532fa72006-06-24 15:06:03 +00002918 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002919 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002920
bellard2f619692007-11-16 10:46:05 +00002921 if (get_user_u32(val, optval_addr))
2922 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002923 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002924 break;
bellard7854b052003-03-29 17:22:23 +00002925 default:
bellard8853f862004-02-22 14:57:26 +00002926 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002927 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002928 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002929 }
bellard8853f862004-02-22 14:57:26 +00002930 return ret;
bellard7854b052003-03-29 17:22:23 +00002931}
2932
ths0da46a62007-10-20 20:23:07 +00002933/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002934static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002935 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002936{
blueswir1992f48a2007-10-14 16:27:31 +00002937 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002938 int len, val;
2939 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002940
2941 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002942 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002943 level = SOL_SOCKET;
2944 switch (optname) {
2945 /* These don't just return a single integer */
2946 case TARGET_SO_LINGER:
2947 case TARGET_SO_RCVTIMEO:
2948 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002949 case TARGET_SO_PEERNAME:
2950 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002951 case TARGET_SO_PEERCRED: {
2952 struct ucred cr;
2953 socklen_t crlen;
2954 struct target_ucred *tcr;
2955
2956 if (get_user_u32(len, optlen)) {
2957 return -TARGET_EFAULT;
2958 }
2959 if (len < 0) {
2960 return -TARGET_EINVAL;
2961 }
2962
2963 crlen = sizeof(cr);
2964 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2965 &cr, &crlen));
2966 if (ret < 0) {
2967 return ret;
2968 }
2969 if (len > crlen) {
2970 len = crlen;
2971 }
2972 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2973 return -TARGET_EFAULT;
2974 }
2975 __put_user(cr.pid, &tcr->pid);
2976 __put_user(cr.uid, &tcr->uid);
2977 __put_user(cr.gid, &tcr->gid);
2978 unlock_user_struct(tcr, optval_addr, 1);
2979 if (put_user_u32(len, optlen)) {
2980 return -TARGET_EFAULT;
2981 }
2982 break;
2983 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002984 /* Options with 'int' argument. */
2985 case TARGET_SO_DEBUG:
2986 optname = SO_DEBUG;
2987 goto int_case;
2988 case TARGET_SO_REUSEADDR:
2989 optname = SO_REUSEADDR;
2990 goto int_case;
2991 case TARGET_SO_TYPE:
2992 optname = SO_TYPE;
2993 goto int_case;
2994 case TARGET_SO_ERROR:
2995 optname = SO_ERROR;
2996 goto int_case;
2997 case TARGET_SO_DONTROUTE:
2998 optname = SO_DONTROUTE;
2999 goto int_case;
3000 case TARGET_SO_BROADCAST:
3001 optname = SO_BROADCAST;
3002 goto int_case;
3003 case TARGET_SO_SNDBUF:
3004 optname = SO_SNDBUF;
3005 goto int_case;
3006 case TARGET_SO_RCVBUF:
3007 optname = SO_RCVBUF;
3008 goto int_case;
3009 case TARGET_SO_KEEPALIVE:
3010 optname = SO_KEEPALIVE;
3011 goto int_case;
3012 case TARGET_SO_OOBINLINE:
3013 optname = SO_OOBINLINE;
3014 goto int_case;
3015 case TARGET_SO_NO_CHECK:
3016 optname = SO_NO_CHECK;
3017 goto int_case;
3018 case TARGET_SO_PRIORITY:
3019 optname = SO_PRIORITY;
3020 goto int_case;
3021#ifdef SO_BSDCOMPAT
3022 case TARGET_SO_BSDCOMPAT:
3023 optname = SO_BSDCOMPAT;
3024 goto int_case;
3025#endif
3026 case TARGET_SO_PASSCRED:
3027 optname = SO_PASSCRED;
3028 goto int_case;
3029 case TARGET_SO_TIMESTAMP:
3030 optname = SO_TIMESTAMP;
3031 goto int_case;
3032 case TARGET_SO_RCVLOWAT:
3033 optname = SO_RCVLOWAT;
3034 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003035 case TARGET_SO_ACCEPTCONN:
3036 optname = SO_ACCEPTCONN;
3037 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003038 default:
bellard2efbe912005-07-23 15:10:20 +00003039 goto int_case;
3040 }
3041 break;
3042 case SOL_TCP:
3043 /* TCP options all take an 'int' value. */
3044 int_case:
bellard2f619692007-11-16 10:46:05 +00003045 if (get_user_u32(len, optlen))
3046 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003047 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003048 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003049 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003050 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3051 if (ret < 0)
3052 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003053 if (optname == SO_TYPE) {
3054 val = host_to_target_sock_type(val);
3055 }
bellard2efbe912005-07-23 15:10:20 +00003056 if (len > lv)
3057 len = lv;
bellard2f619692007-11-16 10:46:05 +00003058 if (len == 4) {
3059 if (put_user_u32(val, optval_addr))
3060 return -TARGET_EFAULT;
3061 } else {
3062 if (put_user_u8(val, optval_addr))
3063 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003064 }
bellard2f619692007-11-16 10:46:05 +00003065 if (put_user_u32(len, optlen))
3066 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003067 break;
3068 case SOL_IP:
3069 switch(optname) {
3070 case IP_TOS:
3071 case IP_TTL:
3072 case IP_HDRINCL:
3073 case IP_ROUTER_ALERT:
3074 case IP_RECVOPTS:
3075 case IP_RETOPTS:
3076 case IP_PKTINFO:
3077 case IP_MTU_DISCOVER:
3078 case IP_RECVERR:
3079 case IP_RECVTOS:
3080#ifdef IP_FREEBIND
3081 case IP_FREEBIND:
3082#endif
3083 case IP_MULTICAST_TTL:
3084 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003085 if (get_user_u32(len, optlen))
3086 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003087 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003088 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003089 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003090 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3091 if (ret < 0)
3092 return ret;
bellard2efbe912005-07-23 15:10:20 +00003093 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003094 len = 1;
bellard2f619692007-11-16 10:46:05 +00003095 if (put_user_u32(len, optlen)
3096 || put_user_u8(val, optval_addr))
3097 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003098 } else {
bellard2efbe912005-07-23 15:10:20 +00003099 if (len > sizeof(int))
3100 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003101 if (put_user_u32(len, optlen)
3102 || put_user_u32(val, optval_addr))
3103 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003104 }
bellard8853f862004-02-22 14:57:26 +00003105 break;
bellard2efbe912005-07-23 15:10:20 +00003106 default:
thsc02f4992007-12-18 02:39:59 +00003107 ret = -TARGET_ENOPROTOOPT;
3108 break;
bellard8853f862004-02-22 14:57:26 +00003109 }
3110 break;
3111 default:
3112 unimplemented:
3113 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3114 level, optname);
thsc02f4992007-12-18 02:39:59 +00003115 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003116 break;
3117 }
3118 return ret;
bellard7854b052003-03-29 17:22:23 +00003119}
3120
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003121static struct iovec *lock_iovec(int type, abi_ulong target_addr,
3122 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003123{
3124 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003125 struct iovec *vec;
3126 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003127 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003128 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003129 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003130
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003131 if (count == 0) {
3132 errno = 0;
3133 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003134 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00003135 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003136 errno = EINVAL;
3137 return NULL;
3138 }
3139
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303140 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003141 if (vec == NULL) {
3142 errno = ENOMEM;
3143 return NULL;
3144 }
3145
3146 target_vec = lock_user(VERIFY_READ, target_addr,
3147 count * sizeof(struct target_iovec), 1);
3148 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003149 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003150 goto fail2;
3151 }
3152
3153 /* ??? If host page size > target page size, this will result in a
3154 value larger than what we can actually support. */
3155 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3156 total_len = 0;
3157
3158 for (i = 0; i < count; i++) {
3159 abi_ulong base = tswapal(target_vec[i].iov_base);
3160 abi_long len = tswapal(target_vec[i].iov_len);
3161
3162 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003163 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003164 goto fail;
3165 } else if (len == 0) {
3166 /* Zero length pointer is ignored. */
3167 vec[i].iov_base = 0;
3168 } else {
3169 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003170 /* If the first buffer pointer is bad, this is a fault. But
3171 * subsequent bad buffers will result in a partial write; this
3172 * is realized by filling the vector with null pointers and
3173 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003174 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003175 if (i == 0) {
3176 err = EFAULT;
3177 goto fail;
3178 } else {
3179 bad_address = true;
3180 }
3181 }
3182 if (bad_address) {
3183 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003184 }
3185 if (len > max_len - total_len) {
3186 len = max_len - total_len;
3187 }
3188 }
3189 vec[i].iov_len = len;
3190 total_len += len;
3191 }
3192
3193 unlock_user(target_vec, target_addr, 0);
3194 return vec;
3195
3196 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003197 while (--i >= 0) {
3198 if (tswapal(target_vec[i].iov_len) > 0) {
3199 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3200 }
3201 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003202 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003203 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303204 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003205 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003206 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003207}
3208
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003209static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
3210 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003211{
3212 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003213 int i;
3214
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003215 target_vec = lock_user(VERIFY_READ, target_addr,
3216 count * sizeof(struct target_iovec), 1);
3217 if (target_vec) {
3218 for (i = 0; i < count; i++) {
3219 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003220 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003221 if (len < 0) {
3222 break;
3223 }
balrogd732dcb2008-10-28 10:21:03 +00003224 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3225 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003226 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003227 }
bellard579a97f2007-11-11 14:26:47 +00003228
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303229 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003230}
3231
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003232static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003233{
3234 int host_type = 0;
3235 int target_type = *type;
3236
3237 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3238 case TARGET_SOCK_DGRAM:
3239 host_type = SOCK_DGRAM;
3240 break;
3241 case TARGET_SOCK_STREAM:
3242 host_type = SOCK_STREAM;
3243 break;
3244 default:
3245 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3246 break;
3247 }
3248 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003249#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003250 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003251#else
3252 return -TARGET_EINVAL;
3253#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003254 }
3255 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003256#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003257 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003258#elif !defined(O_NONBLOCK)
3259 return -TARGET_EINVAL;
3260#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003261 }
3262 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003263 return 0;
3264}
3265
3266/* Try to emulate socket type flags after socket creation. */
3267static int sock_flags_fixup(int fd, int target_type)
3268{
3269#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3270 if (target_type & TARGET_SOCK_NONBLOCK) {
3271 int flags = fcntl(fd, F_GETFL);
3272 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3273 close(fd);
3274 return -TARGET_EINVAL;
3275 }
3276 }
3277#endif
3278 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003279}
3280
Laurent Vivier0cf22722015-10-28 21:40:45 +01003281static abi_long packet_target_to_host_sockaddr(void *host_addr,
3282 abi_ulong target_addr,
3283 socklen_t len)
3284{
3285 struct sockaddr *addr = host_addr;
3286 struct target_sockaddr *target_saddr;
3287
3288 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3289 if (!target_saddr) {
3290 return -TARGET_EFAULT;
3291 }
3292
3293 memcpy(addr, target_saddr, len);
3294 addr->sa_family = tswap16(target_saddr->sa_family);
3295 /* spkt_protocol is big-endian */
3296
3297 unlock_user(target_saddr, target_addr, 0);
3298 return 0;
3299}
3300
3301static TargetFdTrans target_packet_trans = {
3302 .target_to_host_addr = packet_target_to_host_sockaddr,
3303};
3304
Laurent Vivier575b22b2016-06-02 22:14:15 +02003305#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003306static abi_long netlink_route_target_to_host(void *buf, size_t len)
3307{
Laurent Vivieref759f62016-06-21 19:51:13 +02003308 abi_long ret;
3309
3310 ret = target_to_host_nlmsg_route(buf, len);
3311 if (ret < 0) {
3312 return ret;
3313 }
3314
3315 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003316}
3317
3318static abi_long netlink_route_host_to_target(void *buf, size_t len)
3319{
Laurent Vivieref759f62016-06-21 19:51:13 +02003320 abi_long ret;
3321
3322 ret = host_to_target_nlmsg_route(buf, len);
3323 if (ret < 0) {
3324 return ret;
3325 }
3326
3327 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003328}
3329
3330static TargetFdTrans target_netlink_route_trans = {
3331 .target_to_host_data = netlink_route_target_to_host,
3332 .host_to_target_data = netlink_route_host_to_target,
3333};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003334#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003335
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003336static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3337{
Laurent Vivieref759f62016-06-21 19:51:13 +02003338 abi_long ret;
3339
3340 ret = target_to_host_nlmsg_audit(buf, len);
3341 if (ret < 0) {
3342 return ret;
3343 }
3344
3345 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003346}
3347
3348static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3349{
Laurent Vivieref759f62016-06-21 19:51:13 +02003350 abi_long ret;
3351
3352 ret = host_to_target_nlmsg_audit(buf, len);
3353 if (ret < 0) {
3354 return ret;
3355 }
3356
3357 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003358}
3359
3360static TargetFdTrans target_netlink_audit_trans = {
3361 .target_to_host_data = netlink_audit_target_to_host,
3362 .host_to_target_data = netlink_audit_host_to_target,
3363};
3364
ths0da46a62007-10-20 20:23:07 +00003365/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003366static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003367{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003368 int target_type = type;
3369 int ret;
3370
3371 ret = target_to_host_sock_type(&type);
3372 if (ret) {
3373 return ret;
3374 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003375
Laurent Vivier575b22b2016-06-02 22:14:15 +02003376 if (domain == PF_NETLINK && !(
3377#ifdef CONFIG_RTNETLINK
3378 protocol == NETLINK_ROUTE ||
3379#endif
3380 protocol == NETLINK_KOBJECT_UEVENT ||
3381 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003382 return -EPFNOSUPPORT;
3383 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003384
3385 if (domain == AF_PACKET ||
3386 (domain == AF_INET && type == SOCK_PACKET)) {
3387 protocol = tswap16(protocol);
3388 }
3389
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003390 ret = get_errno(socket(domain, type, protocol));
3391 if (ret >= 0) {
3392 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003393 if (type == SOCK_PACKET) {
3394 /* Manage an obsolete case :
3395 * if socket type is SOCK_PACKET, bind by name
3396 */
3397 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003398 } else if (domain == PF_NETLINK) {
3399 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003400#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003401 case NETLINK_ROUTE:
3402 fd_trans_register(ret, &target_netlink_route_trans);
3403 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003404#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003405 case NETLINK_KOBJECT_UEVENT:
3406 /* nothing to do: messages are strings */
3407 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003408 case NETLINK_AUDIT:
3409 fd_trans_register(ret, &target_netlink_audit_trans);
3410 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003411 default:
3412 g_assert_not_reached();
3413 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003414 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003415 }
3416 return ret;
bellard3532fa72006-06-24 15:06:03 +00003417}
3418
ths0da46a62007-10-20 20:23:07 +00003419/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003420static abi_long do_bind(int sockfd, abi_ulong target_addr,
3421 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003422{
aurel328f7aeaf2009-01-30 19:47:57 +00003423 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003424 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003425
Blue Swirl38724252010-09-18 05:53:14 +00003426 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003427 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003428 }
aurel328f7aeaf2009-01-30 19:47:57 +00003429
aurel32607175e2009-04-15 16:11:59 +00003430 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003431
Laurent Vivier7b36f782015-10-28 21:40:44 +01003432 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003433 if (ret)
3434 return ret;
3435
bellard3532fa72006-06-24 15:06:03 +00003436 return get_errno(bind(sockfd, addr, addrlen));
3437}
3438
ths0da46a62007-10-20 20:23:07 +00003439/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003440static abi_long do_connect(int sockfd, abi_ulong target_addr,
3441 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003442{
aurel328f7aeaf2009-01-30 19:47:57 +00003443 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003444 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003445
Blue Swirl38724252010-09-18 05:53:14 +00003446 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003447 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003448 }
aurel328f7aeaf2009-01-30 19:47:57 +00003449
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003450 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003451
Laurent Vivier7b36f782015-10-28 21:40:44 +01003452 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003453 if (ret)
3454 return ret;
3455
Peter Maydell2a3c7612016-06-06 19:58:03 +01003456 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003457}
3458
Alexander Graff19e00d2014-03-02 19:36:42 +00003459/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3460static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3461 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003462{
balrog6de645c2008-10-28 10:26:29 +00003463 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003464 struct msghdr msg;
3465 int count;
3466 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003467 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003468
bellard3532fa72006-06-24 15:06:03 +00003469 if (msgp->msg_name) {
3470 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003471 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003472 ret = target_to_host_sockaddr(fd, msg.msg_name,
3473 tswapal(msgp->msg_name),
3474 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003475 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003476 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003477 }
bellard3532fa72006-06-24 15:06:03 +00003478 } else {
3479 msg.msg_name = NULL;
3480 msg.msg_namelen = 0;
3481 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003482 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003483 msg.msg_control = alloca(msg.msg_controllen);
3484 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003485
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003486 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003487 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003488 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3489 target_vec, count, send);
3490 if (vec == NULL) {
3491 ret = -host_to_target_errno(errno);
3492 goto out2;
3493 }
bellard3532fa72006-06-24 15:06:03 +00003494 msg.msg_iovlen = count;
3495 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003496
bellard3532fa72006-06-24 15:06:03 +00003497 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003498 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003499 void *host_msg;
3500
3501 host_msg = g_malloc(msg.msg_iov->iov_len);
3502 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3503 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003504 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003505 if (ret >= 0) {
3506 msg.msg_iov->iov_base = host_msg;
3507 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3508 }
3509 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003510 } else {
3511 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003512 if (ret == 0) {
3513 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3514 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003515 }
bellard3532fa72006-06-24 15:06:03 +00003516 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003517 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003518 if (!is_error(ret)) {
3519 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003520 if (fd_trans_host_to_target_data(fd)) {
3521 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003522 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003523 } else {
3524 ret = host_to_target_cmsg(msgp, &msg);
3525 }
Jing Huangca619062012-07-24 13:58:02 +00003526 if (!is_error(ret)) {
3527 msgp->msg_namelen = tswap32(msg.msg_namelen);
3528 if (msg.msg_name != NULL) {
3529 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3530 msg.msg_name, msg.msg_namelen);
3531 if (ret) {
3532 goto out;
3533 }
3534 }
3535
balrog6de645c2008-10-28 10:26:29 +00003536 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003537 }
balrog6de645c2008-10-28 10:26:29 +00003538 }
bellard3532fa72006-06-24 15:06:03 +00003539 }
Jing Huangca619062012-07-24 13:58:02 +00003540
3541out:
bellard3532fa72006-06-24 15:06:03 +00003542 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003543out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003544 return ret;
3545}
3546
3547static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3548 int flags, int send)
3549{
3550 abi_long ret;
3551 struct target_msghdr *msgp;
3552
3553 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3554 msgp,
3555 target_msg,
3556 send ? 1 : 0)) {
3557 return -TARGET_EFAULT;
3558 }
3559 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003560 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003561 return ret;
3562}
3563
Alexander Graff19e00d2014-03-02 19:36:42 +00003564/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3565 * so it might not have this *mmsg-specific flag either.
3566 */
3567#ifndef MSG_WAITFORONE
3568#define MSG_WAITFORONE 0x10000
3569#endif
3570
3571static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3572 unsigned int vlen, unsigned int flags,
3573 int send)
3574{
3575 struct target_mmsghdr *mmsgp;
3576 abi_long ret = 0;
3577 int i;
3578
3579 if (vlen > UIO_MAXIOV) {
3580 vlen = UIO_MAXIOV;
3581 }
3582
3583 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3584 if (!mmsgp) {
3585 return -TARGET_EFAULT;
3586 }
3587
3588 for (i = 0; i < vlen; i++) {
3589 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3590 if (is_error(ret)) {
3591 break;
3592 }
3593 mmsgp[i].msg_len = tswap32(ret);
3594 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3595 if (flags & MSG_WAITFORONE) {
3596 flags |= MSG_DONTWAIT;
3597 }
3598 }
3599
3600 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3601
3602 /* Return number of datagrams sent if we sent any at all;
3603 * otherwise return the error.
3604 */
3605 if (i) {
3606 return i;
3607 }
3608 return ret;
3609}
Alexander Graff19e00d2014-03-02 19:36:42 +00003610
Peter Maydella94b4982013-02-08 04:35:04 +00003611/* do_accept4() Must return target values and target errnos. */
3612static abi_long do_accept4(int fd, abi_ulong target_addr,
3613 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003614{
bellard2f619692007-11-16 10:46:05 +00003615 socklen_t addrlen;
3616 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003617 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003618 int host_flags;
3619
3620 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003621
Peter Maydella94b4982013-02-08 04:35:04 +00003622 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003623 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003624 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003625
3626 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003627 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003628 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003629
Blue Swirl38724252010-09-18 05:53:14 +00003630 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003631 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003632 }
aurel328f7aeaf2009-01-30 19:47:57 +00003633
Arnaud Patard917507b2009-06-19 10:44:45 +03003634 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3635 return -TARGET_EINVAL;
3636
bellard2f619692007-11-16 10:46:05 +00003637 addr = alloca(addrlen);
3638
Peter Maydellff6dc132016-06-06 19:58:13 +01003639 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003640 if (!is_error(ret)) {
3641 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003642 if (put_user_u32(addrlen, target_addrlen_addr))
3643 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003644 }
3645 return ret;
3646}
3647
ths0da46a62007-10-20 20:23:07 +00003648/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003649static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003650 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003651{
bellard2f619692007-11-16 10:46:05 +00003652 socklen_t addrlen;
3653 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003654 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003655
bellard2f619692007-11-16 10:46:05 +00003656 if (get_user_u32(addrlen, target_addrlen_addr))
3657 return -TARGET_EFAULT;
3658
Blue Swirl38724252010-09-18 05:53:14 +00003659 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003660 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003661 }
aurel328f7aeaf2009-01-30 19:47:57 +00003662
Arnaud Patard917507b2009-06-19 10:44:45 +03003663 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3664 return -TARGET_EFAULT;
3665
bellard2f619692007-11-16 10:46:05 +00003666 addr = alloca(addrlen);
3667
pbrook1be9e1d2006-11-19 15:26:04 +00003668 ret = get_errno(getpeername(fd, addr, &addrlen));
3669 if (!is_error(ret)) {
3670 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003671 if (put_user_u32(addrlen, target_addrlen_addr))
3672 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003673 }
3674 return ret;
3675}
3676
ths0da46a62007-10-20 20:23:07 +00003677/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003678static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003679 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003680{
bellard2f619692007-11-16 10:46:05 +00003681 socklen_t addrlen;
3682 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003683 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003684
bellard2f619692007-11-16 10:46:05 +00003685 if (get_user_u32(addrlen, target_addrlen_addr))
3686 return -TARGET_EFAULT;
3687
Blue Swirl38724252010-09-18 05:53:14 +00003688 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003689 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003690 }
aurel328f7aeaf2009-01-30 19:47:57 +00003691
Arnaud Patard917507b2009-06-19 10:44:45 +03003692 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3693 return -TARGET_EFAULT;
3694
bellard2f619692007-11-16 10:46:05 +00003695 addr = alloca(addrlen);
3696
pbrook1be9e1d2006-11-19 15:26:04 +00003697 ret = get_errno(getsockname(fd, addr, &addrlen));
3698 if (!is_error(ret)) {
3699 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003700 if (put_user_u32(addrlen, target_addrlen_addr))
3701 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003702 }
3703 return ret;
3704}
3705
ths0da46a62007-10-20 20:23:07 +00003706/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003707static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003708 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003709{
3710 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003711 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003712
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003713 target_to_host_sock_type(&type);
3714
pbrook1be9e1d2006-11-19 15:26:04 +00003715 ret = get_errno(socketpair(domain, type, protocol, tab));
3716 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003717 if (put_user_s32(tab[0], target_tab_addr)
3718 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3719 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003720 }
3721 return ret;
3722}
3723
ths0da46a62007-10-20 20:23:07 +00003724/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003725static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3726 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003727{
3728 void *addr;
3729 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003730 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003731 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003732
Blue Swirl38724252010-09-18 05:53:14 +00003733 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003734 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003735 }
aurel328f7aeaf2009-01-30 19:47:57 +00003736
bellard579a97f2007-11-11 14:26:47 +00003737 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3738 if (!host_msg)
3739 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003740 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003741 copy_msg = host_msg;
3742 host_msg = g_malloc(len);
3743 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003744 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3745 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003746 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003747 }
3748 }
pbrook1be9e1d2006-11-19 15:26:04 +00003749 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003750 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003751 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003752 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003753 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003754 }
Peter Maydell66687532016-06-06 19:58:04 +01003755 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003756 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003757 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003758 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003759fail:
3760 if (copy_msg) {
3761 g_free(host_msg);
3762 host_msg = copy_msg;
3763 }
pbrook1be9e1d2006-11-19 15:26:04 +00003764 unlock_user(host_msg, msg, 0);
3765 return ret;
3766}
3767
ths0da46a62007-10-20 20:23:07 +00003768/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003769static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3770 abi_ulong target_addr,
3771 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003772{
3773 socklen_t addrlen;
3774 void *addr;
3775 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003776 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003777
bellard579a97f2007-11-11 14:26:47 +00003778 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3779 if (!host_msg)
3780 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003781 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003782 if (get_user_u32(addrlen, target_addrlen)) {
3783 ret = -TARGET_EFAULT;
3784 goto fail;
3785 }
Blue Swirl38724252010-09-18 05:53:14 +00003786 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003787 ret = -TARGET_EINVAL;
3788 goto fail;
3789 }
pbrook1be9e1d2006-11-19 15:26:04 +00003790 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003791 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3792 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003793 } else {
3794 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003795 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003796 }
3797 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003798 if (fd_trans_host_to_target_data(fd)) {
3799 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
3800 }
pbrook1be9e1d2006-11-19 15:26:04 +00003801 if (target_addr) {
3802 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003803 if (put_user_u32(addrlen, target_addrlen)) {
3804 ret = -TARGET_EFAULT;
3805 goto fail;
3806 }
pbrook1be9e1d2006-11-19 15:26:04 +00003807 }
3808 unlock_user(host_msg, msg, len);
3809 } else {
bellard2f619692007-11-16 10:46:05 +00003810fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003811 unlock_user(host_msg, msg, 0);
3812 }
3813 return ret;
3814}
3815
j_mayer32407102007-09-26 23:01:49 +00003816#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003817/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003818static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003819{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003820 static const unsigned ac[] = { /* number of arguments per call */
3821 [SOCKOP_socket] = 3, /* domain, type, protocol */
3822 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3823 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3824 [SOCKOP_listen] = 2, /* sockfd, backlog */
3825 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3826 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3827 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3828 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3829 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3830 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3831 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3832 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3833 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3834 [SOCKOP_shutdown] = 2, /* sockfd, how */
3835 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3836 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003837 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3838 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003839 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3840 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3841 };
3842 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003843
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003844 /* first, collect the arguments in a[] according to ac[] */
3845 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3846 unsigned i;
3847 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3848 for (i = 0; i < ac[num]; ++i) {
3849 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003850 return -TARGET_EFAULT;
3851 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003852 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003853 }
bellard2f619692007-11-16 10:46:05 +00003854
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003855 /* now when we have the args, actually handle the call */
3856 switch (num) {
3857 case SOCKOP_socket: /* domain, type, protocol */
3858 return do_socket(a[0], a[1], a[2]);
3859 case SOCKOP_bind: /* sockfd, addr, addrlen */
3860 return do_bind(a[0], a[1], a[2]);
3861 case SOCKOP_connect: /* sockfd, addr, addrlen */
3862 return do_connect(a[0], a[1], a[2]);
3863 case SOCKOP_listen: /* sockfd, backlog */
3864 return get_errno(listen(a[0], a[1]));
3865 case SOCKOP_accept: /* sockfd, addr, addrlen */
3866 return do_accept4(a[0], a[1], a[2], 0);
3867 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3868 return do_accept4(a[0], a[1], a[2], a[3]);
3869 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3870 return do_getsockname(a[0], a[1], a[2]);
3871 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3872 return do_getpeername(a[0], a[1], a[2]);
3873 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3874 return do_socketpair(a[0], a[1], a[2], a[3]);
3875 case SOCKOP_send: /* sockfd, msg, len, flags */
3876 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3877 case SOCKOP_recv: /* sockfd, msg, len, flags */
3878 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3879 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3880 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3881 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3882 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3883 case SOCKOP_shutdown: /* sockfd, how */
3884 return get_errno(shutdown(a[0], a[1]));
3885 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3886 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3887 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3888 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003889 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3890 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3891 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3892 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003893 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3894 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3895 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3896 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003897 default:
3898 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003899 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003900 }
bellard31e31b82003-02-18 22:55:36 +00003901}
j_mayer32407102007-09-26 23:01:49 +00003902#endif
bellard31e31b82003-02-18 22:55:36 +00003903
bellard8853f862004-02-22 14:57:26 +00003904#define N_SHM_REGIONS 32
3905
3906static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003907 abi_ulong start;
3908 abi_ulong size;
3909 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003910} shm_regions[N_SHM_REGIONS];
3911
Peter Maydell005eb2a2016-07-15 16:50:47 +01003912#ifndef TARGET_SEMID64_DS
3913/* asm-generic version of this struct */
3914struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00003915{
3916 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003917 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003918#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003919 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003920#endif
blueswir1992f48a2007-10-14 16:27:31 +00003921 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003922#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003923 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003924#endif
blueswir1992f48a2007-10-14 16:27:31 +00003925 abi_ulong sem_nsems;
3926 abi_ulong __unused3;
3927 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003928};
Peter Maydell005eb2a2016-07-15 16:50:47 +01003929#endif
ths3eb6b042007-06-03 14:26:27 +00003930
bellard579a97f2007-11-11 14:26:47 +00003931static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3932 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003933{
3934 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003935 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003936
bellard579a97f2007-11-11 14:26:47 +00003937 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3938 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003939 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003940 host_ip->__key = tswap32(target_ip->__key);
3941 host_ip->uid = tswap32(target_ip->uid);
3942 host_ip->gid = tswap32(target_ip->gid);
3943 host_ip->cuid = tswap32(target_ip->cuid);
3944 host_ip->cgid = tswap32(target_ip->cgid);
3945#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3946 host_ip->mode = tswap32(target_ip->mode);
3947#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003948 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003949#endif
3950#if defined(TARGET_PPC)
3951 host_ip->__seq = tswap32(target_ip->__seq);
3952#else
3953 host_ip->__seq = tswap16(target_ip->__seq);
3954#endif
ths3eb6b042007-06-03 14:26:27 +00003955 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003956 return 0;
ths3eb6b042007-06-03 14:26:27 +00003957}
3958
bellard579a97f2007-11-11 14:26:47 +00003959static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3960 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003961{
3962 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003963 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003964
bellard579a97f2007-11-11 14:26:47 +00003965 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3966 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003967 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003968 target_ip->__key = tswap32(host_ip->__key);
3969 target_ip->uid = tswap32(host_ip->uid);
3970 target_ip->gid = tswap32(host_ip->gid);
3971 target_ip->cuid = tswap32(host_ip->cuid);
3972 target_ip->cgid = tswap32(host_ip->cgid);
3973#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3974 target_ip->mode = tswap32(host_ip->mode);
3975#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003976 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003977#endif
3978#if defined(TARGET_PPC)
3979 target_ip->__seq = tswap32(host_ip->__seq);
3980#else
3981 target_ip->__seq = tswap16(host_ip->__seq);
3982#endif
ths3eb6b042007-06-03 14:26:27 +00003983 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003984 return 0;
ths3eb6b042007-06-03 14:26:27 +00003985}
3986
bellard579a97f2007-11-11 14:26:47 +00003987static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3988 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003989{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003990 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003991
bellard579a97f2007-11-11 14:26:47 +00003992 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3993 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003994 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3995 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003996 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3997 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3998 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003999 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004000 return 0;
ths3eb6b042007-06-03 14:26:27 +00004001}
4002
bellard579a97f2007-11-11 14:26:47 +00004003static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4004 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004005{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004006 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004007
bellard579a97f2007-11-11 14:26:47 +00004008 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4009 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004010 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004011 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004012 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4013 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4014 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004015 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004016 return 0;
ths3eb6b042007-06-03 14:26:27 +00004017}
4018
aurel32e5289082009-04-18 16:16:12 +00004019struct target_seminfo {
4020 int semmap;
4021 int semmni;
4022 int semmns;
4023 int semmnu;
4024 int semmsl;
4025 int semopm;
4026 int semume;
4027 int semusz;
4028 int semvmx;
4029 int semaem;
4030};
4031
4032static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4033 struct seminfo *host_seminfo)
4034{
4035 struct target_seminfo *target_seminfo;
4036 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4037 return -TARGET_EFAULT;
4038 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4039 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4040 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4041 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4042 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4043 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4044 __put_user(host_seminfo->semume, &target_seminfo->semume);
4045 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4046 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4047 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4048 unlock_user_struct(target_seminfo, target_addr, 1);
4049 return 0;
4050}
4051
thsfa294812007-02-02 22:05:00 +00004052union semun {
4053 int val;
ths3eb6b042007-06-03 14:26:27 +00004054 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004055 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004056 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004057};
4058
ths3eb6b042007-06-03 14:26:27 +00004059union target_semun {
4060 int val;
aurel32e5289082009-04-18 16:16:12 +00004061 abi_ulong buf;
4062 abi_ulong array;
4063 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004064};
4065
aurel32e5289082009-04-18 16:16:12 +00004066static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4067 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004068{
aurel32e5289082009-04-18 16:16:12 +00004069 int nsems;
4070 unsigned short *array;
4071 union semun semun;
4072 struct semid_ds semid_ds;
4073 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004074
aurel32e5289082009-04-18 16:16:12 +00004075 semun.buf = &semid_ds;
4076
4077 ret = semctl(semid, 0, IPC_STAT, semun);
4078 if (ret == -1)
4079 return get_errno(ret);
4080
4081 nsems = semid_ds.sem_nsems;
4082
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304083 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004084 if (!*host_array) {
4085 return -TARGET_ENOMEM;
4086 }
aurel32e5289082009-04-18 16:16:12 +00004087 array = lock_user(VERIFY_READ, target_addr,
4088 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004089 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304090 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004091 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004092 }
aurel32e5289082009-04-18 16:16:12 +00004093
4094 for(i=0; i<nsems; i++) {
4095 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004096 }
aurel32e5289082009-04-18 16:16:12 +00004097 unlock_user(array, target_addr, 0);
4098
bellard579a97f2007-11-11 14:26:47 +00004099 return 0;
ths3eb6b042007-06-03 14:26:27 +00004100}
4101
aurel32e5289082009-04-18 16:16:12 +00004102static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4103 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004104{
aurel32e5289082009-04-18 16:16:12 +00004105 int nsems;
4106 unsigned short *array;
4107 union semun semun;
4108 struct semid_ds semid_ds;
4109 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004110
aurel32e5289082009-04-18 16:16:12 +00004111 semun.buf = &semid_ds;
4112
4113 ret = semctl(semid, 0, IPC_STAT, semun);
4114 if (ret == -1)
4115 return get_errno(ret);
4116
4117 nsems = semid_ds.sem_nsems;
4118
4119 array = lock_user(VERIFY_WRITE, target_addr,
4120 nsems*sizeof(unsigned short), 0);
4121 if (!array)
4122 return -TARGET_EFAULT;
4123
4124 for(i=0; i<nsems; i++) {
4125 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004126 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304127 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004128 unlock_user(array, target_addr, 1);
4129
bellard579a97f2007-11-11 14:26:47 +00004130 return 0;
ths3eb6b042007-06-03 14:26:27 +00004131}
4132
aurel32e5289082009-04-18 16:16:12 +00004133static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004134 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004135{
Stefan Weild1c002b2015-02-08 15:40:58 +01004136 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004137 union semun arg;
4138 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304139 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004140 struct seminfo seminfo;
4141 abi_long ret = -TARGET_EINVAL;
4142 abi_long err;
4143 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004144
4145 switch( cmd ) {
4146 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004147 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004148 /* In 64 bit cross-endian situations, we will erroneously pick up
4149 * the wrong half of the union for the "val" element. To rectify
4150 * this, the entire 8-byte structure is byteswapped, followed by
4151 * a swap of the 4 byte val field. In other cases, the data is
4152 * already in proper host byte order. */
4153 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4154 target_su.buf = tswapal(target_su.buf);
4155 arg.val = tswap32(target_su.val);
4156 } else {
4157 arg.val = target_su.val;
4158 }
aurel32e5289082009-04-18 16:16:12 +00004159 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004160 break;
4161 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004162 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004163 err = target_to_host_semarray(semid, &array, target_su.array);
4164 if (err)
4165 return err;
4166 arg.array = array;
4167 ret = get_errno(semctl(semid, semnum, cmd, arg));
4168 err = host_to_target_semarray(semid, target_su.array, &array);
4169 if (err)
4170 return err;
ths3eb6b042007-06-03 14:26:27 +00004171 break;
4172 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004173 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004174 case SEM_STAT:
4175 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4176 if (err)
4177 return err;
4178 arg.buf = &dsarg;
4179 ret = get_errno(semctl(semid, semnum, cmd, arg));
4180 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4181 if (err)
4182 return err;
ths3eb6b042007-06-03 14:26:27 +00004183 break;
aurel32e5289082009-04-18 16:16:12 +00004184 case IPC_INFO:
4185 case SEM_INFO:
4186 arg.__buf = &seminfo;
4187 ret = get_errno(semctl(semid, semnum, cmd, arg));
4188 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4189 if (err)
4190 return err;
4191 break;
4192 case IPC_RMID:
4193 case GETPID:
4194 case GETNCNT:
4195 case GETZCNT:
4196 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4197 break;
ths3eb6b042007-06-03 14:26:27 +00004198 }
4199
4200 return ret;
4201}
4202
aurel32e5289082009-04-18 16:16:12 +00004203struct target_sembuf {
4204 unsigned short sem_num;
4205 short sem_op;
4206 short sem_flg;
4207};
4208
4209static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4210 abi_ulong target_addr,
4211 unsigned nsops)
4212{
4213 struct target_sembuf *target_sembuf;
4214 int i;
4215
4216 target_sembuf = lock_user(VERIFY_READ, target_addr,
4217 nsops*sizeof(struct target_sembuf), 1);
4218 if (!target_sembuf)
4219 return -TARGET_EFAULT;
4220
4221 for(i=0; i<nsops; i++) {
4222 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4223 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4224 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4225 }
4226
4227 unlock_user(target_sembuf, target_addr, 0);
4228
4229 return 0;
4230}
4231
4232static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4233{
4234 struct sembuf sops[nsops];
4235
4236 if (target_to_host_sembuf(sops, ptr, nsops))
4237 return -TARGET_EFAULT;
4238
Peter Maydellffb7ee72016-06-06 19:58:12 +01004239 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004240}
4241
ths1bc012f2007-06-03 14:27:49 +00004242struct target_msqid_ds
4243{
aurel321c54ff92008-10-13 21:08:44 +00004244 struct target_ipc_perm msg_perm;
4245 abi_ulong msg_stime;
4246#if TARGET_ABI_BITS == 32
4247 abi_ulong __unused1;
4248#endif
4249 abi_ulong msg_rtime;
4250#if TARGET_ABI_BITS == 32
4251 abi_ulong __unused2;
4252#endif
4253 abi_ulong msg_ctime;
4254#if TARGET_ABI_BITS == 32
4255 abi_ulong __unused3;
4256#endif
4257 abi_ulong __msg_cbytes;
4258 abi_ulong msg_qnum;
4259 abi_ulong msg_qbytes;
4260 abi_ulong msg_lspid;
4261 abi_ulong msg_lrpid;
4262 abi_ulong __unused4;
4263 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004264};
4265
bellard579a97f2007-11-11 14:26:47 +00004266static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4267 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004268{
4269 struct target_msqid_ds *target_md;
4270
bellard579a97f2007-11-11 14:26:47 +00004271 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4272 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004273 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4274 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004275 host_md->msg_stime = tswapal(target_md->msg_stime);
4276 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4277 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4278 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4279 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4280 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4281 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4282 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004283 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004284 return 0;
ths1bc012f2007-06-03 14:27:49 +00004285}
4286
bellard579a97f2007-11-11 14:26:47 +00004287static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4288 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004289{
4290 struct target_msqid_ds *target_md;
4291
bellard579a97f2007-11-11 14:26:47 +00004292 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4293 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004294 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4295 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004296 target_md->msg_stime = tswapal(host_md->msg_stime);
4297 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4298 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4299 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4300 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4301 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4302 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4303 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004304 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004305 return 0;
ths1bc012f2007-06-03 14:27:49 +00004306}
4307
aurel321c54ff92008-10-13 21:08:44 +00004308struct target_msginfo {
4309 int msgpool;
4310 int msgmap;
4311 int msgmax;
4312 int msgmnb;
4313 int msgmni;
4314 int msgssz;
4315 int msgtql;
4316 unsigned short int msgseg;
4317};
4318
4319static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4320 struct msginfo *host_msginfo)
4321{
4322 struct target_msginfo *target_msginfo;
4323 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4324 return -TARGET_EFAULT;
4325 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4326 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4327 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4328 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4329 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4330 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4331 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4332 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4333 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004334 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004335}
4336
4337static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004338{
4339 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004340 struct msginfo msginfo;
4341 abi_long ret = -TARGET_EINVAL;
4342
4343 cmd &= 0xff;
4344
4345 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004346 case IPC_STAT:
4347 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004348 case MSG_STAT:
4349 if (target_to_host_msqid_ds(&dsarg,ptr))
4350 return -TARGET_EFAULT;
4351 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4352 if (host_to_target_msqid_ds(ptr,&dsarg))
4353 return -TARGET_EFAULT;
4354 break;
4355 case IPC_RMID:
4356 ret = get_errno(msgctl(msgid, cmd, NULL));
4357 break;
4358 case IPC_INFO:
4359 case MSG_INFO:
4360 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4361 if (host_to_target_msginfo(ptr, &msginfo))
4362 return -TARGET_EFAULT;
4363 break;
ths1bc012f2007-06-03 14:27:49 +00004364 }
aurel321c54ff92008-10-13 21:08:44 +00004365
ths1bc012f2007-06-03 14:27:49 +00004366 return ret;
4367}
4368
4369struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004370 abi_long mtype;
4371 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004372};
4373
blueswir1992f48a2007-10-14 16:27:31 +00004374static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004375 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004376{
4377 struct target_msgbuf *target_mb;
4378 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004379 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004380
Tom Mustaedcc5f92014-08-12 13:53:37 -05004381 if (msgsz < 0) {
4382 return -TARGET_EINVAL;
4383 }
4384
bellard579a97f2007-11-11 14:26:47 +00004385 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4386 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304387 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004388 if (!host_mb) {
4389 unlock_user_struct(target_mb, msgp, 0);
4390 return -TARGET_ENOMEM;
4391 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004392 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004393 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004394 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304395 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004396 unlock_user_struct(target_mb, msgp, 0);
4397
4398 return ret;
4399}
4400
blueswir1992f48a2007-10-14 16:27:31 +00004401static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004402 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004403 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004404{
4405 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004406 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004407 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004408 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004409
Peter Maydell99874f62016-05-20 19:00:56 +01004410 if (msgsz < 0) {
4411 return -TARGET_EINVAL;
4412 }
4413
bellard579a97f2007-11-11 14:26:47 +00004414 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4415 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004416
Peter Maydell415d8472016-05-20 19:00:57 +01004417 host_mb = g_try_malloc(msgsz + sizeof(long));
4418 if (!host_mb) {
4419 ret = -TARGET_ENOMEM;
4420 goto end;
4421 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004422 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004423
bellard579a97f2007-11-11 14:26:47 +00004424 if (ret > 0) {
4425 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4426 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4427 if (!target_mtext) {
4428 ret = -TARGET_EFAULT;
4429 goto end;
4430 }
aurel321c54ff92008-10-13 21:08:44 +00004431 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004432 unlock_user(target_mtext, target_mtext_addr, ret);
4433 }
aurel321c54ff92008-10-13 21:08:44 +00004434
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004435 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004436
bellard579a97f2007-11-11 14:26:47 +00004437end:
4438 if (target_mb)
4439 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004440 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004441 return ret;
4442}
4443
Riku Voipio88a8c982009-04-03 10:42:00 +03004444static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4445 abi_ulong target_addr)
4446{
4447 struct target_shmid_ds *target_sd;
4448
4449 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4450 return -TARGET_EFAULT;
4451 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4452 return -TARGET_EFAULT;
4453 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4454 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4455 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4456 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4457 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4458 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4459 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4460 unlock_user_struct(target_sd, target_addr, 0);
4461 return 0;
4462}
4463
4464static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4465 struct shmid_ds *host_sd)
4466{
4467 struct target_shmid_ds *target_sd;
4468
4469 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4470 return -TARGET_EFAULT;
4471 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4472 return -TARGET_EFAULT;
4473 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4474 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4475 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4476 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4477 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4478 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4479 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4480 unlock_user_struct(target_sd, target_addr, 1);
4481 return 0;
4482}
4483
4484struct target_shminfo {
4485 abi_ulong shmmax;
4486 abi_ulong shmmin;
4487 abi_ulong shmmni;
4488 abi_ulong shmseg;
4489 abi_ulong shmall;
4490};
4491
4492static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4493 struct shminfo *host_shminfo)
4494{
4495 struct target_shminfo *target_shminfo;
4496 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4497 return -TARGET_EFAULT;
4498 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4499 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4500 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4501 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4502 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4503 unlock_user_struct(target_shminfo, target_addr, 1);
4504 return 0;
4505}
4506
4507struct target_shm_info {
4508 int used_ids;
4509 abi_ulong shm_tot;
4510 abi_ulong shm_rss;
4511 abi_ulong shm_swp;
4512 abi_ulong swap_attempts;
4513 abi_ulong swap_successes;
4514};
4515
4516static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4517 struct shm_info *host_shm_info)
4518{
4519 struct target_shm_info *target_shm_info;
4520 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4521 return -TARGET_EFAULT;
4522 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4523 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4524 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4525 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4526 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4527 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4528 unlock_user_struct(target_shm_info, target_addr, 1);
4529 return 0;
4530}
4531
4532static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4533{
4534 struct shmid_ds dsarg;
4535 struct shminfo shminfo;
4536 struct shm_info shm_info;
4537 abi_long ret = -TARGET_EINVAL;
4538
4539 cmd &= 0xff;
4540
4541 switch(cmd) {
4542 case IPC_STAT:
4543 case IPC_SET:
4544 case SHM_STAT:
4545 if (target_to_host_shmid_ds(&dsarg, buf))
4546 return -TARGET_EFAULT;
4547 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4548 if (host_to_target_shmid_ds(buf, &dsarg))
4549 return -TARGET_EFAULT;
4550 break;
4551 case IPC_INFO:
4552 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4553 if (host_to_target_shminfo(buf, &shminfo))
4554 return -TARGET_EFAULT;
4555 break;
4556 case SHM_INFO:
4557 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4558 if (host_to_target_shm_info(buf, &shm_info))
4559 return -TARGET_EFAULT;
4560 break;
4561 case IPC_RMID:
4562 case SHM_LOCK:
4563 case SHM_UNLOCK:
4564 ret = get_errno(shmctl(shmid, cmd, NULL));
4565 break;
4566 }
4567
4568 return ret;
4569}
4570
4571static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4572{
4573 abi_long raddr;
4574 void *host_raddr;
4575 struct shmid_ds shm_info;
4576 int i,ret;
4577
4578 /* find out the length of the shared memory segment */
4579 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4580 if (is_error(ret)) {
4581 /* can't get length, bail out */
4582 return ret;
4583 }
4584
4585 mmap_lock();
4586
4587 if (shmaddr)
4588 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4589 else {
4590 abi_ulong mmap_start;
4591
4592 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4593
4594 if (mmap_start == -1) {
4595 errno = ENOMEM;
4596 host_raddr = (void *)-1;
4597 } else
4598 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4599 }
4600
4601 if (host_raddr == (void *)-1) {
4602 mmap_unlock();
4603 return get_errno((long)host_raddr);
4604 }
4605 raddr=h2g((unsigned long)host_raddr);
4606
4607 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4608 PAGE_VALID | PAGE_READ |
4609 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4610
4611 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004612 if (!shm_regions[i].in_use) {
4613 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004614 shm_regions[i].start = raddr;
4615 shm_regions[i].size = shm_info.shm_segsz;
4616 break;
4617 }
4618 }
4619
4620 mmap_unlock();
4621 return raddr;
4622
4623}
4624
4625static inline abi_long do_shmdt(abi_ulong shmaddr)
4626{
4627 int i;
4628
4629 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004630 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4631 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004632 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004633 break;
4634 }
4635 }
4636
4637 return get_errno(shmdt(g2h(shmaddr)));
4638}
4639
aurel321c54ff92008-10-13 21:08:44 +00004640#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004641/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004642/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004643static abi_long do_ipc(unsigned int call, abi_long first,
4644 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004645 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004646{
4647 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004648 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004649
4650 version = call >> 16;
4651 call &= 0xffff;
4652
4653 switch (call) {
thsfa294812007-02-02 22:05:00 +00004654 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004655 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004656 break;
4657
4658 case IPCOP_semget:
4659 ret = get_errno(semget(first, second, third));
4660 break;
4661
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004662 case IPCOP_semctl: {
4663 /* The semun argument to semctl is passed by value, so dereference the
4664 * ptr argument. */
4665 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004666 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004667 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004668 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004669 }
thsd96372e2007-02-02 22:05:44 +00004670
aurel321c54ff92008-10-13 21:08:44 +00004671 case IPCOP_msgget:
4672 ret = get_errno(msgget(first, second));
4673 break;
thsd96372e2007-02-02 22:05:44 +00004674
aurel321c54ff92008-10-13 21:08:44 +00004675 case IPCOP_msgsnd:
4676 ret = do_msgsnd(first, ptr, second, third);
4677 break;
thsd96372e2007-02-02 22:05:44 +00004678
aurel321c54ff92008-10-13 21:08:44 +00004679 case IPCOP_msgctl:
4680 ret = do_msgctl(first, second, ptr);
4681 break;
thsd96372e2007-02-02 22:05:44 +00004682
aurel321c54ff92008-10-13 21:08:44 +00004683 case IPCOP_msgrcv:
4684 switch (version) {
4685 case 0:
4686 {
4687 struct target_ipc_kludge {
4688 abi_long msgp;
4689 abi_long msgtyp;
4690 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004691
aurel321c54ff92008-10-13 21:08:44 +00004692 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4693 ret = -TARGET_EFAULT;
4694 break;
ths1bc012f2007-06-03 14:27:49 +00004695 }
aurel321c54ff92008-10-13 21:08:44 +00004696
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004697 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004698
4699 unlock_user_struct(tmp, ptr, 0);
4700 break;
4701 }
4702 default:
4703 ret = do_msgrcv(first, ptr, second, fifth, third);
4704 }
4705 break;
thsd96372e2007-02-02 22:05:44 +00004706
bellard8853f862004-02-22 14:57:26 +00004707 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004708 switch (version) {
4709 default:
bellard5a4a8982007-11-11 17:39:18 +00004710 {
4711 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004712 raddr = do_shmat(first, ptr, second);
4713 if (is_error(raddr))
4714 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004715 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004716 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004717 break;
4718 }
4719 case 1:
4720 ret = -TARGET_EINVAL;
4721 break;
bellard5a4a8982007-11-11 17:39:18 +00004722 }
bellard8853f862004-02-22 14:57:26 +00004723 break;
4724 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004725 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004726 break;
4727
4728 case IPCOP_shmget:
4729 /* IPC_* flag values are the same on all linux platforms */
4730 ret = get_errno(shmget(first, second, third));
4731 break;
4732
4733 /* IPC_* and SHM_* command values are the same on all linux platforms */
4734 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004735 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004736 break;
4737 default:
j_mayer32407102007-09-26 23:01:49 +00004738 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004739 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004740 break;
4741 }
4742 return ret;
4743}
j_mayer32407102007-09-26 23:01:49 +00004744#endif
bellard8853f862004-02-22 14:57:26 +00004745
bellard31e31b82003-02-18 22:55:36 +00004746/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004747
Blue Swirl001faf32009-05-13 17:53:17 +00004748#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004749#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4750enum {
4751#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004752STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004753};
4754#undef STRUCT
4755#undef STRUCT_SPECIAL
4756
Blue Swirl001faf32009-05-13 17:53:17 +00004757#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004758#define STRUCT_SPECIAL(name)
4759#include "syscall_types.h"
4760#undef STRUCT
4761#undef STRUCT_SPECIAL
4762
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004763typedef struct IOCTLEntry IOCTLEntry;
4764
4765typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004766 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004767
4768struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004769 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004770 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004771 const char *name;
4772 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004773 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004774 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004775};
bellard31e31b82003-02-18 22:55:36 +00004776
4777#define IOC_R 0x0001
4778#define IOC_W 0x0002
4779#define IOC_RW (IOC_R | IOC_W)
4780
4781#define MAX_STRUCT_SIZE 4096
4782
Peter Maydelldace20d2011-01-10 13:11:24 +00004783#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004784/* So fiemap access checks don't overflow on 32 bit systems.
4785 * This is very slightly smaller than the limit imposed by
4786 * the underlying kernel.
4787 */
4788#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4789 / sizeof(struct fiemap_extent))
4790
4791static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004792 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004793{
4794 /* The parameter for this ioctl is a struct fiemap followed
4795 * by an array of struct fiemap_extent whose size is set
4796 * in fiemap->fm_extent_count. The array is filled in by the
4797 * ioctl.
4798 */
4799 int target_size_in, target_size_out;
4800 struct fiemap *fm;
4801 const argtype *arg_type = ie->arg_type;
4802 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4803 void *argptr, *p;
4804 abi_long ret;
4805 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4806 uint32_t outbufsz;
4807 int free_fm = 0;
4808
4809 assert(arg_type[0] == TYPE_PTR);
4810 assert(ie->access == IOC_RW);
4811 arg_type++;
4812 target_size_in = thunk_type_size(arg_type, 0);
4813 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4814 if (!argptr) {
4815 return -TARGET_EFAULT;
4816 }
4817 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4818 unlock_user(argptr, arg, 0);
4819 fm = (struct fiemap *)buf_temp;
4820 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4821 return -TARGET_EINVAL;
4822 }
4823
4824 outbufsz = sizeof (*fm) +
4825 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4826
4827 if (outbufsz > MAX_STRUCT_SIZE) {
4828 /* We can't fit all the extents into the fixed size buffer.
4829 * Allocate one that is large enough and use it instead.
4830 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304831 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004832 if (!fm) {
4833 return -TARGET_ENOMEM;
4834 }
4835 memcpy(fm, buf_temp, sizeof(struct fiemap));
4836 free_fm = 1;
4837 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004838 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004839 if (!is_error(ret)) {
4840 target_size_out = target_size_in;
4841 /* An extent_count of 0 means we were only counting the extents
4842 * so there are no structs to copy
4843 */
4844 if (fm->fm_extent_count != 0) {
4845 target_size_out += fm->fm_mapped_extents * extent_size;
4846 }
4847 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4848 if (!argptr) {
4849 ret = -TARGET_EFAULT;
4850 } else {
4851 /* Convert the struct fiemap */
4852 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4853 if (fm->fm_extent_count != 0) {
4854 p = argptr + target_size_in;
4855 /* ...and then all the struct fiemap_extents */
4856 for (i = 0; i < fm->fm_mapped_extents; i++) {
4857 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4858 THUNK_TARGET);
4859 p += extent_size;
4860 }
4861 }
4862 unlock_user(argptr, arg, target_size_out);
4863 }
4864 }
4865 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304866 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004867 }
4868 return ret;
4869}
Peter Maydelldace20d2011-01-10 13:11:24 +00004870#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004871
Laurent Vivier059c2f22011-03-30 00:12:12 +02004872static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004873 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004874{
4875 const argtype *arg_type = ie->arg_type;
4876 int target_size;
4877 void *argptr;
4878 int ret;
4879 struct ifconf *host_ifconf;
4880 uint32_t outbufsz;
4881 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4882 int target_ifreq_size;
4883 int nb_ifreq;
4884 int free_buf = 0;
4885 int i;
4886 int target_ifc_len;
4887 abi_long target_ifc_buf;
4888 int host_ifc_len;
4889 char *host_ifc_buf;
4890
4891 assert(arg_type[0] == TYPE_PTR);
4892 assert(ie->access == IOC_RW);
4893
4894 arg_type++;
4895 target_size = thunk_type_size(arg_type, 0);
4896
4897 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4898 if (!argptr)
4899 return -TARGET_EFAULT;
4900 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4901 unlock_user(argptr, arg, 0);
4902
4903 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4904 target_ifc_len = host_ifconf->ifc_len;
4905 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4906
4907 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4908 nb_ifreq = target_ifc_len / target_ifreq_size;
4909 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4910
4911 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4912 if (outbufsz > MAX_STRUCT_SIZE) {
4913 /* We can't fit all the extents into the fixed size buffer.
4914 * Allocate one that is large enough and use it instead.
4915 */
4916 host_ifconf = malloc(outbufsz);
4917 if (!host_ifconf) {
4918 return -TARGET_ENOMEM;
4919 }
4920 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4921 free_buf = 1;
4922 }
4923 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4924
4925 host_ifconf->ifc_len = host_ifc_len;
4926 host_ifconf->ifc_buf = host_ifc_buf;
4927
Peter Maydell49ca6f32016-06-06 19:58:14 +01004928 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004929 if (!is_error(ret)) {
4930 /* convert host ifc_len to target ifc_len */
4931
4932 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4933 target_ifc_len = nb_ifreq * target_ifreq_size;
4934 host_ifconf->ifc_len = target_ifc_len;
4935
4936 /* restore target ifc_buf */
4937
4938 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4939
4940 /* copy struct ifconf to target user */
4941
4942 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4943 if (!argptr)
4944 return -TARGET_EFAULT;
4945 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4946 unlock_user(argptr, arg, target_size);
4947
4948 /* copy ifreq[] to target user */
4949
4950 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4951 for (i = 0; i < nb_ifreq ; i++) {
4952 thunk_convert(argptr + i * target_ifreq_size,
4953 host_ifc_buf + i * sizeof(struct ifreq),
4954 ifreq_arg_type, THUNK_TARGET);
4955 }
4956 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4957 }
4958
4959 if (free_buf) {
4960 free(host_ifconf);
4961 }
4962
4963 return ret;
4964}
4965
Alexander Graf56e904e2012-01-31 18:42:06 +01004966static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004967 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004968{
4969 void *argptr;
4970 struct dm_ioctl *host_dm;
4971 abi_long guest_data;
4972 uint32_t guest_data_size;
4973 int target_size;
4974 const argtype *arg_type = ie->arg_type;
4975 abi_long ret;
4976 void *big_buf = NULL;
4977 char *host_data;
4978
4979 arg_type++;
4980 target_size = thunk_type_size(arg_type, 0);
4981 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4982 if (!argptr) {
4983 ret = -TARGET_EFAULT;
4984 goto out;
4985 }
4986 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4987 unlock_user(argptr, arg, 0);
4988
4989 /* buf_temp is too small, so fetch things into a bigger buffer */
4990 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4991 memcpy(big_buf, buf_temp, target_size);
4992 buf_temp = big_buf;
4993 host_dm = big_buf;
4994
4995 guest_data = arg + host_dm->data_start;
4996 if ((guest_data - arg) < 0) {
4997 ret = -EINVAL;
4998 goto out;
4999 }
5000 guest_data_size = host_dm->data_size - host_dm->data_start;
5001 host_data = (char*)host_dm + host_dm->data_start;
5002
5003 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
5004 switch (ie->host_cmd) {
5005 case DM_REMOVE_ALL:
5006 case DM_LIST_DEVICES:
5007 case DM_DEV_CREATE:
5008 case DM_DEV_REMOVE:
5009 case DM_DEV_SUSPEND:
5010 case DM_DEV_STATUS:
5011 case DM_DEV_WAIT:
5012 case DM_TABLE_STATUS:
5013 case DM_TABLE_CLEAR:
5014 case DM_TABLE_DEPS:
5015 case DM_LIST_VERSIONS:
5016 /* no input data */
5017 break;
5018 case DM_DEV_RENAME:
5019 case DM_DEV_SET_GEOMETRY:
5020 /* data contains only strings */
5021 memcpy(host_data, argptr, guest_data_size);
5022 break;
5023 case DM_TARGET_MSG:
5024 memcpy(host_data, argptr, guest_data_size);
5025 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5026 break;
5027 case DM_TABLE_LOAD:
5028 {
5029 void *gspec = argptr;
5030 void *cur_data = host_data;
5031 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5032 int spec_size = thunk_type_size(arg_type, 0);
5033 int i;
5034
5035 for (i = 0; i < host_dm->target_count; i++) {
5036 struct dm_target_spec *spec = cur_data;
5037 uint32_t next;
5038 int slen;
5039
5040 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5041 slen = strlen((char*)gspec + spec_size) + 1;
5042 next = spec->next;
5043 spec->next = sizeof(*spec) + slen;
5044 strcpy((char*)&spec[1], gspec + spec_size);
5045 gspec += next;
5046 cur_data += spec->next;
5047 }
5048 break;
5049 }
5050 default:
5051 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005052 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005053 goto out;
5054 }
5055 unlock_user(argptr, guest_data, 0);
5056
Peter Maydell49ca6f32016-06-06 19:58:14 +01005057 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005058 if (!is_error(ret)) {
5059 guest_data = arg + host_dm->data_start;
5060 guest_data_size = host_dm->data_size - host_dm->data_start;
5061 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5062 switch (ie->host_cmd) {
5063 case DM_REMOVE_ALL:
5064 case DM_DEV_CREATE:
5065 case DM_DEV_REMOVE:
5066 case DM_DEV_RENAME:
5067 case DM_DEV_SUSPEND:
5068 case DM_DEV_STATUS:
5069 case DM_TABLE_LOAD:
5070 case DM_TABLE_CLEAR:
5071 case DM_TARGET_MSG:
5072 case DM_DEV_SET_GEOMETRY:
5073 /* no return data */
5074 break;
5075 case DM_LIST_DEVICES:
5076 {
5077 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5078 uint32_t remaining_data = guest_data_size;
5079 void *cur_data = argptr;
5080 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5081 int nl_size = 12; /* can't use thunk_size due to alignment */
5082
5083 while (1) {
5084 uint32_t next = nl->next;
5085 if (next) {
5086 nl->next = nl_size + (strlen(nl->name) + 1);
5087 }
5088 if (remaining_data < nl->next) {
5089 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5090 break;
5091 }
5092 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5093 strcpy(cur_data + nl_size, nl->name);
5094 cur_data += nl->next;
5095 remaining_data -= nl->next;
5096 if (!next) {
5097 break;
5098 }
5099 nl = (void*)nl + next;
5100 }
5101 break;
5102 }
5103 case DM_DEV_WAIT:
5104 case DM_TABLE_STATUS:
5105 {
5106 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5107 void *cur_data = argptr;
5108 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5109 int spec_size = thunk_type_size(arg_type, 0);
5110 int i;
5111
5112 for (i = 0; i < host_dm->target_count; i++) {
5113 uint32_t next = spec->next;
5114 int slen = strlen((char*)&spec[1]) + 1;
5115 spec->next = (cur_data - argptr) + spec_size + slen;
5116 if (guest_data_size < spec->next) {
5117 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5118 break;
5119 }
5120 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5121 strcpy(cur_data + spec_size, (char*)&spec[1]);
5122 cur_data = argptr + spec->next;
5123 spec = (void*)host_dm + host_dm->data_start + next;
5124 }
5125 break;
5126 }
5127 case DM_TABLE_DEPS:
5128 {
5129 void *hdata = (void*)host_dm + host_dm->data_start;
5130 int count = *(uint32_t*)hdata;
5131 uint64_t *hdev = hdata + 8;
5132 uint64_t *gdev = argptr + 8;
5133 int i;
5134
5135 *(uint32_t*)argptr = tswap32(count);
5136 for (i = 0; i < count; i++) {
5137 *gdev = tswap64(*hdev);
5138 gdev++;
5139 hdev++;
5140 }
5141 break;
5142 }
5143 case DM_LIST_VERSIONS:
5144 {
5145 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5146 uint32_t remaining_data = guest_data_size;
5147 void *cur_data = argptr;
5148 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5149 int vers_size = thunk_type_size(arg_type, 0);
5150
5151 while (1) {
5152 uint32_t next = vers->next;
5153 if (next) {
5154 vers->next = vers_size + (strlen(vers->name) + 1);
5155 }
5156 if (remaining_data < vers->next) {
5157 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5158 break;
5159 }
5160 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5161 strcpy(cur_data + vers_size, vers->name);
5162 cur_data += vers->next;
5163 remaining_data -= vers->next;
5164 if (!next) {
5165 break;
5166 }
5167 vers = (void*)vers + next;
5168 }
5169 break;
5170 }
5171 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005172 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005173 ret = -TARGET_EINVAL;
5174 goto out;
5175 }
5176 unlock_user(argptr, guest_data, guest_data_size);
5177
5178 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5179 if (!argptr) {
5180 ret = -TARGET_EFAULT;
5181 goto out;
5182 }
5183 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5184 unlock_user(argptr, arg, target_size);
5185 }
5186out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005187 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005188 return ret;
5189}
5190
Alexander Grafa59b5e32014-08-22 13:15:50 +02005191static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005192 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005193{
5194 void *argptr;
5195 int target_size;
5196 const argtype *arg_type = ie->arg_type;
5197 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5198 abi_long ret;
5199
5200 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5201 struct blkpg_partition host_part;
5202
5203 /* Read and convert blkpg */
5204 arg_type++;
5205 target_size = thunk_type_size(arg_type, 0);
5206 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5207 if (!argptr) {
5208 ret = -TARGET_EFAULT;
5209 goto out;
5210 }
5211 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5212 unlock_user(argptr, arg, 0);
5213
5214 switch (host_blkpg->op) {
5215 case BLKPG_ADD_PARTITION:
5216 case BLKPG_DEL_PARTITION:
5217 /* payload is struct blkpg_partition */
5218 break;
5219 default:
5220 /* Unknown opcode */
5221 ret = -TARGET_EINVAL;
5222 goto out;
5223 }
5224
5225 /* Read and convert blkpg->data */
5226 arg = (abi_long)(uintptr_t)host_blkpg->data;
5227 target_size = thunk_type_size(part_arg_type, 0);
5228 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5229 if (!argptr) {
5230 ret = -TARGET_EFAULT;
5231 goto out;
5232 }
5233 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5234 unlock_user(argptr, arg, 0);
5235
5236 /* Swizzle the data pointer to our local copy and call! */
5237 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005238 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005239
5240out:
5241 return ret;
5242}
5243
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005244static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005245 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005246{
5247 const argtype *arg_type = ie->arg_type;
5248 const StructEntry *se;
5249 const argtype *field_types;
5250 const int *dst_offsets, *src_offsets;
5251 int target_size;
5252 void *argptr;
5253 abi_ulong *target_rt_dev_ptr;
5254 unsigned long *host_rt_dev_ptr;
5255 abi_long ret;
5256 int i;
5257
5258 assert(ie->access == IOC_W);
5259 assert(*arg_type == TYPE_PTR);
5260 arg_type++;
5261 assert(*arg_type == TYPE_STRUCT);
5262 target_size = thunk_type_size(arg_type, 0);
5263 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5264 if (!argptr) {
5265 return -TARGET_EFAULT;
5266 }
5267 arg_type++;
5268 assert(*arg_type == (int)STRUCT_rtentry);
5269 se = struct_entries + *arg_type++;
5270 assert(se->convert[0] == NULL);
5271 /* convert struct here to be able to catch rt_dev string */
5272 field_types = se->field_types;
5273 dst_offsets = se->field_offsets[THUNK_HOST];
5274 src_offsets = se->field_offsets[THUNK_TARGET];
5275 for (i = 0; i < se->nb_fields; i++) {
5276 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5277 assert(*field_types == TYPE_PTRVOID);
5278 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5279 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5280 if (*target_rt_dev_ptr != 0) {
5281 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5282 tswapal(*target_rt_dev_ptr));
5283 if (!*host_rt_dev_ptr) {
5284 unlock_user(argptr, arg, 0);
5285 return -TARGET_EFAULT;
5286 }
5287 } else {
5288 *host_rt_dev_ptr = 0;
5289 }
5290 field_types++;
5291 continue;
5292 }
5293 field_types = thunk_convert(buf_temp + dst_offsets[i],
5294 argptr + src_offsets[i],
5295 field_types, THUNK_HOST);
5296 }
5297 unlock_user(argptr, arg, 0);
5298
Peter Maydell49ca6f32016-06-06 19:58:14 +01005299 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005300 if (*host_rt_dev_ptr != 0) {
5301 unlock_user((void *)*host_rt_dev_ptr,
5302 *target_rt_dev_ptr, 0);
5303 }
5304 return ret;
5305}
5306
Paul Burtonca56f5b2014-06-22 11:25:47 +01005307static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005308 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005309{
5310 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005311 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005312}
5313
blueswir19f106a72008-10-05 10:52:52 +00005314static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005315#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005316 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5317#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5318 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00005319#include "ioctls.h"
5320 { 0, 0, },
5321};
5322
pbrook53a59602006-03-25 19:31:22 +00005323/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005324/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005325static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005326{
5327 const IOCTLEntry *ie;
5328 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005329 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005330 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005331 int target_size;
5332 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005333
5334 ie = ioctl_entries;
5335 for(;;) {
5336 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005337 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005338 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005339 }
5340 if (ie->target_cmd == cmd)
5341 break;
5342 ie++;
5343 }
5344 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005345#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005346 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005347#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005348 if (ie->do_ioctl) {
5349 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
5350 }
5351
bellard31e31b82003-02-18 22:55:36 +00005352 switch(arg_type[0]) {
5353 case TYPE_NULL:
5354 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005355 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005356 break;
5357 case TYPE_PTRVOID:
5358 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005359 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005360 break;
5361 case TYPE_PTR:
5362 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005363 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005364 switch(ie->access) {
5365 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005366 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005367 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005368 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5369 if (!argptr)
5370 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005371 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5372 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005373 }
5374 break;
5375 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005376 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5377 if (!argptr)
5378 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005379 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5380 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005381 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005382 break;
5383 default:
5384 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005385 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5386 if (!argptr)
5387 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005388 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5389 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005390 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005391 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005392 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5393 if (!argptr)
5394 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005395 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5396 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005397 }
5398 break;
5399 }
5400 break;
5401 default:
j_mayer32407102007-09-26 23:01:49 +00005402 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5403 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005404 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005405 break;
5406 }
5407 return ret;
5408}
5409
blueswir1b39bc502008-10-05 10:51:10 +00005410static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005411 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5412 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5413 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5414 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5415 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5416 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5417 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5418 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5419 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5420 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5421 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5422 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5423 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5424 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5425 { 0, 0, 0, 0 }
5426};
5427
blueswir1b39bc502008-10-05 10:51:10 +00005428static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005429 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5430 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5431 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5432 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5433 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5434 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5435 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5436 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5437 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5438 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5439 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5440 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5441 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5442 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5443 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5444 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5445 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5446 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5447 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5448 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5449 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5450 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5451 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5452 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5453 { 0, 0, 0, 0 }
5454};
5455
blueswir1b39bc502008-10-05 10:51:10 +00005456static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005457 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5458 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5459 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5460 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5461 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5462 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5463 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5464 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5465 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5466 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5467 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5468 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5469 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5470 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5471 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5472 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5473 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5474 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5475 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5476 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5477 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5478 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5479 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5480 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5481 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5482 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5483 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5484 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5485 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5486 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5487 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5488 { 0, 0, 0, 0 }
5489};
5490
blueswir1b39bc502008-10-05 10:51:10 +00005491static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005492 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5493 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5494 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5495 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5496 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5497 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5498 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5499 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5500 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5501 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5502 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5503 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5504 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5505 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5506 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5507 { 0, 0, 0, 0 }
5508};
5509
5510static void target_to_host_termios (void *dst, const void *src)
5511{
5512 struct host_termios *host = dst;
5513 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005514
ths5fafdf22007-09-16 21:08:06 +00005515 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005516 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005517 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005518 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005519 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005520 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005521 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005522 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5523 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005524
Arnaud Patard44607122009-04-21 17:39:08 +03005525 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005526 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5527 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005528 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005529 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005530 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005531 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005532 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005533 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005534 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005535 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5536 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005537 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5538 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5539 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5540 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5541 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005542 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005543}
ths3b46e622007-09-17 08:09:54 +00005544
bellard31e31b82003-02-18 22:55:36 +00005545static void host_to_target_termios (void *dst, const void *src)
5546{
5547 struct target_termios *target = dst;
5548 const struct host_termios *host = src;
5549
ths5fafdf22007-09-16 21:08:06 +00005550 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005551 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005552 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005553 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005554 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005555 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005556 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005557 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5558 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005559
Arnaud Patard44607122009-04-21 17:39:08 +03005560 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005561 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5562 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5563 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5564 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5565 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5566 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5567 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5568 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5569 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5570 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5571 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5572 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5573 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5574 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5575 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5576 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5577 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5578}
5579
blueswir18e853dc2008-10-05 10:49:32 +00005580static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005581 .convert = { host_to_target_termios, target_to_host_termios },
5582 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5583 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5584};
5585
bellard5286db72003-06-05 00:57:30 +00005586static bitmask_transtbl mmap_flags_tbl[] = {
5587 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5588 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5589 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5590 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5591 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5592 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5593 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5594 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005595 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5596 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005597 { 0, 0, 0, 0 }
5598};
5599
bellard2ab83ea2003-06-15 19:56:46 +00005600#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005601
5602/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005603static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005604
bellard03acab62007-11-11 14:57:14 +00005605static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005606{
5607 int size;
pbrook53a59602006-03-25 19:31:22 +00005608 void *p;
bellard6dbad632003-03-16 18:05:05 +00005609
5610 if (!ldt_table)
5611 return 0;
5612 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5613 if (size > bytecount)
5614 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005615 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5616 if (!p)
bellard03acab62007-11-11 14:57:14 +00005617 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005618 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005619 memcpy(p, ldt_table, size);
5620 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005621 return size;
5622}
5623
5624/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005625static abi_long write_ldt(CPUX86State *env,
5626 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005627{
5628 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005629 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005630 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005631 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005632 uint32_t *lp, entry_1, entry_2;
5633
5634 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005635 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005636 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005637 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005638 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005639 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005640 ldt_info.limit = tswap32(target_ldt_info->limit);
5641 ldt_info.flags = tswap32(target_ldt_info->flags);
5642 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005643
bellard6dbad632003-03-16 18:05:05 +00005644 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005645 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005646 seg_32bit = ldt_info.flags & 1;
5647 contents = (ldt_info.flags >> 1) & 3;
5648 read_exec_only = (ldt_info.flags >> 3) & 1;
5649 limit_in_pages = (ldt_info.flags >> 4) & 1;
5650 seg_not_present = (ldt_info.flags >> 5) & 1;
5651 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005652#ifdef TARGET_ABI32
5653 lm = 0;
5654#else
5655 lm = (ldt_info.flags >> 7) & 1;
5656#endif
bellard6dbad632003-03-16 18:05:05 +00005657 if (contents == 3) {
5658 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005659 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005660 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005661 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005662 }
5663 /* allocate the LDT */
5664 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005665 env->ldt.base = target_mmap(0,
5666 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5667 PROT_READ|PROT_WRITE,
5668 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5669 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005670 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005671 memset(g2h(env->ldt.base), 0,
5672 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005673 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005674 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005675 }
5676
5677 /* NOTE: same code as Linux kernel */
5678 /* Allow LDTs to be cleared by the user. */
5679 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5680 if (oldmode ||
5681 (contents == 0 &&
5682 read_exec_only == 1 &&
5683 seg_32bit == 0 &&
5684 limit_in_pages == 0 &&
5685 seg_not_present == 1 &&
5686 useable == 0 )) {
5687 entry_1 = 0;
5688 entry_2 = 0;
5689 goto install;
5690 }
5691 }
ths3b46e622007-09-17 08:09:54 +00005692
bellard6dbad632003-03-16 18:05:05 +00005693 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5694 (ldt_info.limit & 0x0ffff);
5695 entry_2 = (ldt_info.base_addr & 0xff000000) |
5696 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5697 (ldt_info.limit & 0xf0000) |
5698 ((read_exec_only ^ 1) << 9) |
5699 (contents << 10) |
5700 ((seg_not_present ^ 1) << 15) |
5701 (seg_32bit << 22) |
5702 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005703 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005704 0x7000;
5705 if (!oldmode)
5706 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005707
bellard6dbad632003-03-16 18:05:05 +00005708 /* Install the new entry ... */
5709install:
5710 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5711 lp[0] = tswap32(entry_1);
5712 lp[1] = tswap32(entry_2);
5713 return 0;
5714}
5715
5716/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005717static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5718 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005719{
bellard03acab62007-11-11 14:57:14 +00005720 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005721
bellard6dbad632003-03-16 18:05:05 +00005722 switch (func) {
5723 case 0:
5724 ret = read_ldt(ptr, bytecount);
5725 break;
5726 case 1:
5727 ret = write_ldt(env, ptr, bytecount, 1);
5728 break;
5729 case 0x11:
5730 ret = write_ldt(env, ptr, bytecount, 0);
5731 break;
bellard03acab62007-11-11 14:57:14 +00005732 default:
5733 ret = -TARGET_ENOSYS;
5734 break;
bellard6dbad632003-03-16 18:05:05 +00005735 }
5736 return ret;
5737}
bellard1b6b0292003-03-22 17:31:38 +00005738
blueswir14583f582008-08-24 10:35:55 +00005739#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005740abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005741{
5742 uint64_t *gdt_table = g2h(env->gdt.base);
5743 struct target_modify_ldt_ldt_s ldt_info;
5744 struct target_modify_ldt_ldt_s *target_ldt_info;
5745 int seg_32bit, contents, read_exec_only, limit_in_pages;
5746 int seg_not_present, useable, lm;
5747 uint32_t *lp, entry_1, entry_2;
5748 int i;
5749
5750 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5751 if (!target_ldt_info)
5752 return -TARGET_EFAULT;
5753 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005754 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005755 ldt_info.limit = tswap32(target_ldt_info->limit);
5756 ldt_info.flags = tswap32(target_ldt_info->flags);
5757 if (ldt_info.entry_number == -1) {
5758 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5759 if (gdt_table[i] == 0) {
5760 ldt_info.entry_number = i;
5761 target_ldt_info->entry_number = tswap32(i);
5762 break;
5763 }
5764 }
5765 }
5766 unlock_user_struct(target_ldt_info, ptr, 1);
5767
5768 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5769 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5770 return -TARGET_EINVAL;
5771 seg_32bit = ldt_info.flags & 1;
5772 contents = (ldt_info.flags >> 1) & 3;
5773 read_exec_only = (ldt_info.flags >> 3) & 1;
5774 limit_in_pages = (ldt_info.flags >> 4) & 1;
5775 seg_not_present = (ldt_info.flags >> 5) & 1;
5776 useable = (ldt_info.flags >> 6) & 1;
5777#ifdef TARGET_ABI32
5778 lm = 0;
5779#else
5780 lm = (ldt_info.flags >> 7) & 1;
5781#endif
5782
5783 if (contents == 3) {
5784 if (seg_not_present == 0)
5785 return -TARGET_EINVAL;
5786 }
5787
5788 /* NOTE: same code as Linux kernel */
5789 /* Allow LDTs to be cleared by the user. */
5790 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5791 if ((contents == 0 &&
5792 read_exec_only == 1 &&
5793 seg_32bit == 0 &&
5794 limit_in_pages == 0 &&
5795 seg_not_present == 1 &&
5796 useable == 0 )) {
5797 entry_1 = 0;
5798 entry_2 = 0;
5799 goto install;
5800 }
5801 }
5802
5803 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5804 (ldt_info.limit & 0x0ffff);
5805 entry_2 = (ldt_info.base_addr & 0xff000000) |
5806 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5807 (ldt_info.limit & 0xf0000) |
5808 ((read_exec_only ^ 1) << 9) |
5809 (contents << 10) |
5810 ((seg_not_present ^ 1) << 15) |
5811 (seg_32bit << 22) |
5812 (limit_in_pages << 23) |
5813 (useable << 20) |
5814 (lm << 21) |
5815 0x7000;
5816
5817 /* Install the new entry ... */
5818install:
5819 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5820 lp[0] = tswap32(entry_1);
5821 lp[1] = tswap32(entry_2);
5822 return 0;
5823}
5824
blueswir18fcd3692008-08-17 20:26:25 +00005825static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005826{
5827 struct target_modify_ldt_ldt_s *target_ldt_info;
5828 uint64_t *gdt_table = g2h(env->gdt.base);
5829 uint32_t base_addr, limit, flags;
5830 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5831 int seg_not_present, useable, lm;
5832 uint32_t *lp, entry_1, entry_2;
5833
5834 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5835 if (!target_ldt_info)
5836 return -TARGET_EFAULT;
5837 idx = tswap32(target_ldt_info->entry_number);
5838 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5839 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5840 unlock_user_struct(target_ldt_info, ptr, 1);
5841 return -TARGET_EINVAL;
5842 }
5843 lp = (uint32_t *)(gdt_table + idx);
5844 entry_1 = tswap32(lp[0]);
5845 entry_2 = tswap32(lp[1]);
5846
5847 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5848 contents = (entry_2 >> 10) & 3;
5849 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5850 seg_32bit = (entry_2 >> 22) & 1;
5851 limit_in_pages = (entry_2 >> 23) & 1;
5852 useable = (entry_2 >> 20) & 1;
5853#ifdef TARGET_ABI32
5854 lm = 0;
5855#else
5856 lm = (entry_2 >> 21) & 1;
5857#endif
5858 flags = (seg_32bit << 0) | (contents << 1) |
5859 (read_exec_only << 3) | (limit_in_pages << 4) |
5860 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5861 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5862 base_addr = (entry_1 >> 16) |
5863 (entry_2 & 0xff000000) |
5864 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005865 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005866 target_ldt_info->limit = tswap32(limit);
5867 target_ldt_info->flags = tswap32(flags);
5868 unlock_user_struct(target_ldt_info, ptr, 1);
5869 return 0;
5870}
blueswir14583f582008-08-24 10:35:55 +00005871#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005872
bellardd2fd1af2007-11-14 18:08:56 +00005873#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005874abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005875{
Juan Quintela1add8692011-06-16 17:37:09 +01005876 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005877 abi_ulong val;
5878 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005879
bellardd2fd1af2007-11-14 18:08:56 +00005880 switch(code) {
5881 case TARGET_ARCH_SET_GS:
5882 case TARGET_ARCH_SET_FS:
5883 if (code == TARGET_ARCH_SET_GS)
5884 idx = R_GS;
5885 else
5886 idx = R_FS;
5887 cpu_x86_load_seg(env, idx, 0);
5888 env->segs[idx].base = addr;
5889 break;
5890 case TARGET_ARCH_GET_GS:
5891 case TARGET_ARCH_GET_FS:
5892 if (code == TARGET_ARCH_GET_GS)
5893 idx = R_GS;
5894 else
5895 idx = R_FS;
5896 val = env->segs[idx].base;
5897 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005898 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005899 break;
5900 default:
5901 ret = -TARGET_EINVAL;
5902 break;
5903 }
Juan Quintela1add8692011-06-16 17:37:09 +01005904 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005905}
5906#endif
5907
bellard2ab83ea2003-06-15 19:56:46 +00005908#endif /* defined(TARGET_I386) */
5909
Riku Voipio05098a92011-03-04 15:27:29 +02005910#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005911
pbrookd865bab2008-06-07 22:12:17 +00005912
5913static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5914typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005915 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005916 pthread_mutex_t mutex;
5917 pthread_cond_t cond;
5918 pthread_t thread;
5919 uint32_t tid;
5920 abi_ulong child_tidptr;
5921 abi_ulong parent_tidptr;
5922 sigset_t sigmask;
5923} new_thread_info;
5924
5925static void *clone_func(void *arg)
5926{
5927 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005928 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005929 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005930 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005931
Emilio G. Cota70903762015-08-23 20:23:41 -04005932 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005933 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005934 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005935 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005936 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005937 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005938 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005939 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005940 if (info->child_tidptr)
5941 put_user_u32(info->tid, info->child_tidptr);
5942 if (info->parent_tidptr)
5943 put_user_u32(info->tid, info->parent_tidptr);
5944 /* Enable signals. */
5945 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5946 /* Signal to the parent that we're ready. */
5947 pthread_mutex_lock(&info->mutex);
5948 pthread_cond_broadcast(&info->cond);
5949 pthread_mutex_unlock(&info->mutex);
5950 /* Wait until the parent has finshed initializing the tls state. */
5951 pthread_mutex_lock(&clone_lock);
5952 pthread_mutex_unlock(&clone_lock);
5953 cpu_loop(env);
5954 /* never exits */
5955 return NULL;
5956}
bellard1b6b0292003-03-22 17:31:38 +00005957
ths0da46a62007-10-20 20:23:07 +00005958/* do_fork() Must return host values and target errnos (unlike most
5959 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005960static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005961 abi_ulong parent_tidptr, target_ulong newtls,
5962 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005963{
Andreas Färber0429a972013-08-26 18:14:44 +02005964 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005965 int ret;
bellard5cd43932003-03-29 16:54:36 +00005966 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005967 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005968 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005969 unsigned int nptl_flags;
5970 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005971
balrog436d1242008-09-21 02:39:45 +00005972 /* Emulate vfork() with fork() */
5973 if (flags & CLONE_VFORK)
5974 flags &= ~(CLONE_VFORK | CLONE_VM);
5975
bellard1b6b0292003-03-22 17:31:38 +00005976 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005977 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005978 new_thread_info info;
5979 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005980
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005981 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005982 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005983 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005984 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005985 /* Init regs that differ from the parent. */
5986 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005987 new_cpu = ENV_GET_CPU(new_env);
5988 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005989 ts->bprm = parent_ts->bprm;
5990 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005991 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005992 nptl_flags = flags;
5993 flags &= ~CLONE_NPTL_FLAGS2;
5994
pbrookc2764712009-03-07 15:24:59 +00005995 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5996 ts->child_tidptr = child_tidptr;
5997 }
5998
pbrookd865bab2008-06-07 22:12:17 +00005999 if (nptl_flags & CLONE_SETTLS)
6000 cpu_set_tls (new_env, newtls);
6001
6002 /* Grab a mutex so that thread setup appears atomic. */
6003 pthread_mutex_lock(&clone_lock);
6004
6005 memset(&info, 0, sizeof(info));
6006 pthread_mutex_init(&info.mutex, NULL);
6007 pthread_mutex_lock(&info.mutex);
6008 pthread_cond_init(&info.cond, NULL);
6009 info.env = new_env;
6010 if (nptl_flags & CLONE_CHILD_SETTID)
6011 info.child_tidptr = child_tidptr;
6012 if (nptl_flags & CLONE_PARENT_SETTID)
6013 info.parent_tidptr = parent_tidptr;
6014
6015 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006016 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6017 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006018 /* It is not safe to deliver signals until the child has finished
6019 initializing, so temporarily block all signals. */
6020 sigfillset(&sigmask);
6021 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6022
6023 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006024 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006025
6026 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6027 pthread_attr_destroy(&attr);
6028 if (ret == 0) {
6029 /* Wait for the child to initialize. */
6030 pthread_cond_wait(&info.cond, &info.mutex);
6031 ret = info.tid;
6032 if (flags & CLONE_PARENT_SETTID)
6033 put_user_u32(ret, parent_tidptr);
6034 } else {
6035 ret = -1;
6036 }
6037 pthread_mutex_unlock(&info.mutex);
6038 pthread_cond_destroy(&info.cond);
6039 pthread_mutex_destroy(&info.mutex);
6040 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006041 } else {
6042 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006043 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
6044 return -TARGET_EINVAL;
6045 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006046
6047 if (block_signals()) {
6048 return -TARGET_ERESTARTSYS;
6049 }
6050
pbrookd865bab2008-06-07 22:12:17 +00006051 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006052 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006053 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006054 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02006055 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00006056 cpu_clone_regs(env, newsp);
6057 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006058 /* There is a race condition here. The parent process could
6059 theoretically read the TID in the child process before the child
6060 tid is set. This would require using either ptrace
6061 (not implemented) or having *_tidptr to point at a shared memory
6062 mapping. We can't repeat the spinlock hack used above because
6063 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006064 if (flags & CLONE_CHILD_SETTID)
6065 put_user_u32(gettid(), child_tidptr);
6066 if (flags & CLONE_PARENT_SETTID)
6067 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006068 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006069 if (flags & CLONE_SETTLS)
6070 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006071 if (flags & CLONE_CHILD_CLEARTID)
6072 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006073 } else {
6074 fork_end(0);
6075 }
bellard1b6b0292003-03-22 17:31:38 +00006076 }
6077 return ret;
6078}
6079
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006080/* warning : doesn't handle linux specific flags... */
6081static int target_to_host_fcntl_cmd(int cmd)
6082{
6083 switch(cmd) {
6084 case TARGET_F_DUPFD:
6085 case TARGET_F_GETFD:
6086 case TARGET_F_SETFD:
6087 case TARGET_F_GETFL:
6088 case TARGET_F_SETFL:
6089 return cmd;
6090 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006091 return F_GETLK64;
6092 case TARGET_F_SETLK:
6093 return F_SETLK64;
6094 case TARGET_F_SETLKW:
6095 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006096 case TARGET_F_GETOWN:
6097 return F_GETOWN;
6098 case TARGET_F_SETOWN:
6099 return F_SETOWN;
6100 case TARGET_F_GETSIG:
6101 return F_GETSIG;
6102 case TARGET_F_SETSIG:
6103 return F_SETSIG;
6104#if TARGET_ABI_BITS == 32
6105 case TARGET_F_GETLK64:
6106 return F_GETLK64;
6107 case TARGET_F_SETLK64:
6108 return F_SETLK64;
6109 case TARGET_F_SETLKW64:
6110 return F_SETLKW64;
6111#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006112 case TARGET_F_SETLEASE:
6113 return F_SETLEASE;
6114 case TARGET_F_GETLEASE:
6115 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006116#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006117 case TARGET_F_DUPFD_CLOEXEC:
6118 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006119#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006120 case TARGET_F_NOTIFY:
6121 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006122#ifdef F_GETOWN_EX
6123 case TARGET_F_GETOWN_EX:
6124 return F_GETOWN_EX;
6125#endif
6126#ifdef F_SETOWN_EX
6127 case TARGET_F_SETOWN_EX:
6128 return F_SETOWN_EX;
6129#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006130#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006131 case TARGET_F_SETPIPE_SZ:
6132 return F_SETPIPE_SZ;
6133 case TARGET_F_GETPIPE_SZ:
6134 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006135#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006136 default:
6137 return -TARGET_EINVAL;
6138 }
6139 return -TARGET_EINVAL;
6140}
6141
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006142#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6143static const bitmask_transtbl flock_tbl[] = {
6144 TRANSTBL_CONVERT(F_RDLCK),
6145 TRANSTBL_CONVERT(F_WRLCK),
6146 TRANSTBL_CONVERT(F_UNLCK),
6147 TRANSTBL_CONVERT(F_EXLCK),
6148 TRANSTBL_CONVERT(F_SHLCK),
6149 { 0, 0, 0, 0 }
6150};
6151
Peter Maydell213d3e92016-06-13 11:22:05 +01006152static inline abi_long copy_from_user_flock(struct flock64 *fl,
6153 abi_ulong target_flock_addr)
6154{
6155 struct target_flock *target_fl;
6156 short l_type;
6157
6158 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6159 return -TARGET_EFAULT;
6160 }
6161
6162 __get_user(l_type, &target_fl->l_type);
6163 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6164 __get_user(fl->l_whence, &target_fl->l_whence);
6165 __get_user(fl->l_start, &target_fl->l_start);
6166 __get_user(fl->l_len, &target_fl->l_len);
6167 __get_user(fl->l_pid, &target_fl->l_pid);
6168 unlock_user_struct(target_fl, target_flock_addr, 0);
6169 return 0;
6170}
6171
6172static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6173 const struct flock64 *fl)
6174{
6175 struct target_flock *target_fl;
6176 short l_type;
6177
6178 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6179 return -TARGET_EFAULT;
6180 }
6181
6182 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6183 __put_user(l_type, &target_fl->l_type);
6184 __put_user(fl->l_whence, &target_fl->l_whence);
6185 __put_user(fl->l_start, &target_fl->l_start);
6186 __put_user(fl->l_len, &target_fl->l_len);
6187 __put_user(fl->l_pid, &target_fl->l_pid);
6188 unlock_user_struct(target_fl, target_flock_addr, 1);
6189 return 0;
6190}
6191
6192typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6193typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6194
6195#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6196static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6197 abi_ulong target_flock_addr)
6198{
6199 struct target_eabi_flock64 *target_fl;
6200 short l_type;
6201
6202 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6203 return -TARGET_EFAULT;
6204 }
6205
6206 __get_user(l_type, &target_fl->l_type);
6207 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6208 __get_user(fl->l_whence, &target_fl->l_whence);
6209 __get_user(fl->l_start, &target_fl->l_start);
6210 __get_user(fl->l_len, &target_fl->l_len);
6211 __get_user(fl->l_pid, &target_fl->l_pid);
6212 unlock_user_struct(target_fl, target_flock_addr, 0);
6213 return 0;
6214}
6215
6216static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6217 const struct flock64 *fl)
6218{
6219 struct target_eabi_flock64 *target_fl;
6220 short l_type;
6221
6222 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6223 return -TARGET_EFAULT;
6224 }
6225
6226 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6227 __put_user(l_type, &target_fl->l_type);
6228 __put_user(fl->l_whence, &target_fl->l_whence);
6229 __put_user(fl->l_start, &target_fl->l_start);
6230 __put_user(fl->l_len, &target_fl->l_len);
6231 __put_user(fl->l_pid, &target_fl->l_pid);
6232 unlock_user_struct(target_fl, target_flock_addr, 1);
6233 return 0;
6234}
6235#endif
6236
6237static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6238 abi_ulong target_flock_addr)
6239{
6240 struct target_flock64 *target_fl;
6241 short l_type;
6242
6243 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6244 return -TARGET_EFAULT;
6245 }
6246
6247 __get_user(l_type, &target_fl->l_type);
6248 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6249 __get_user(fl->l_whence, &target_fl->l_whence);
6250 __get_user(fl->l_start, &target_fl->l_start);
6251 __get_user(fl->l_len, &target_fl->l_len);
6252 __get_user(fl->l_pid, &target_fl->l_pid);
6253 unlock_user_struct(target_fl, target_flock_addr, 0);
6254 return 0;
6255}
6256
6257static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6258 const struct flock64 *fl)
6259{
6260 struct target_flock64 *target_fl;
6261 short l_type;
6262
6263 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6264 return -TARGET_EFAULT;
6265 }
6266
6267 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6268 __put_user(l_type, &target_fl->l_type);
6269 __put_user(fl->l_whence, &target_fl->l_whence);
6270 __put_user(fl->l_start, &target_fl->l_start);
6271 __put_user(fl->l_len, &target_fl->l_len);
6272 __put_user(fl->l_pid, &target_fl->l_pid);
6273 unlock_user_struct(target_fl, target_flock_addr, 1);
6274 return 0;
6275}
6276
blueswir1992f48a2007-10-14 16:27:31 +00006277static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006278{
ths43f238d2007-01-05 20:55:49 +00006279 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006280#ifdef F_GETOWN_EX
6281 struct f_owner_ex fox;
6282 struct target_f_owner_ex *target_fox;
6283#endif
blueswir1992f48a2007-10-14 16:27:31 +00006284 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006285 int host_cmd = target_to_host_fcntl_cmd(cmd);
6286
6287 if (host_cmd == -TARGET_EINVAL)
6288 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006289
bellard7775e9e2003-05-14 22:46:48 +00006290 switch(cmd) {
6291 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006292 ret = copy_from_user_flock(&fl64, arg);
6293 if (ret) {
6294 return ret;
6295 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006296 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006297 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006298 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006299 }
6300 break;
ths3b46e622007-09-17 08:09:54 +00006301
bellard7775e9e2003-05-14 22:46:48 +00006302 case TARGET_F_SETLK:
6303 case TARGET_F_SETLKW:
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 break;
ths3b46e622007-09-17 08:09:54 +00006310
bellard7775e9e2003-05-14 22:46:48 +00006311 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006312 ret = copy_from_user_flock64(&fl64, arg);
6313 if (ret) {
6314 return ret;
6315 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006316 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006317 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006318 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006319 }
bellard9ee1fa22007-11-11 15:11:19 +00006320 break;
bellard7775e9e2003-05-14 22:46:48 +00006321 case TARGET_F_SETLK64:
6322 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006323 ret = copy_from_user_flock64(&fl64, arg);
6324 if (ret) {
6325 return ret;
6326 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006327 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006328 break;
6329
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006330 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006331 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006332 if (ret >= 0) {
6333 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6334 }
bellardffa65c32004-01-04 23:57:22 +00006335 break;
6336
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006337 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006338 ret = get_errno(safe_fcntl(fd, host_cmd,
6339 target_to_host_bitmask(arg,
6340 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006341 break;
6342
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006343#ifdef F_GETOWN_EX
6344 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006345 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006346 if (ret >= 0) {
6347 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6348 return -TARGET_EFAULT;
6349 target_fox->type = tswap32(fox.type);
6350 target_fox->pid = tswap32(fox.pid);
6351 unlock_user_struct(target_fox, arg, 1);
6352 }
6353 break;
6354#endif
6355
6356#ifdef F_SETOWN_EX
6357 case TARGET_F_SETOWN_EX:
6358 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6359 return -TARGET_EFAULT;
6360 fox.type = tswap32(target_fox->type);
6361 fox.pid = tswap32(target_fox->pid);
6362 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006363 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006364 break;
6365#endif
6366
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006367 case TARGET_F_SETOWN:
6368 case TARGET_F_GETOWN:
6369 case TARGET_F_SETSIG:
6370 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006371 case TARGET_F_SETLEASE:
6372 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006373 case TARGET_F_SETPIPE_SZ:
6374 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006375 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006376 break;
6377
bellard7775e9e2003-05-14 22:46:48 +00006378 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006379 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006380 break;
6381 }
6382 return ret;
6383}
6384
bellard67867302003-11-23 17:05:30 +00006385#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006386
bellard67867302003-11-23 17:05:30 +00006387static inline int high2lowuid(int uid)
6388{
6389 if (uid > 65535)
6390 return 65534;
6391 else
6392 return uid;
6393}
6394
6395static inline int high2lowgid(int gid)
6396{
6397 if (gid > 65535)
6398 return 65534;
6399 else
6400 return gid;
6401}
6402
6403static inline int low2highuid(int uid)
6404{
6405 if ((int16_t)uid == -1)
6406 return -1;
6407 else
6408 return uid;
6409}
6410
6411static inline int low2highgid(int gid)
6412{
6413 if ((int16_t)gid == -1)
6414 return -1;
6415 else
6416 return gid;
6417}
Riku Voipio0c866a72011-04-18 15:23:06 +03006418static inline int tswapid(int id)
6419{
6420 return tswap16(id);
6421}
Peter Maydell76ca3102014-03-02 19:36:41 +00006422
6423#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6424
Riku Voipio0c866a72011-04-18 15:23:06 +03006425#else /* !USE_UID16 */
6426static inline int high2lowuid(int uid)
6427{
6428 return uid;
6429}
6430static inline int high2lowgid(int gid)
6431{
6432 return gid;
6433}
6434static inline int low2highuid(int uid)
6435{
6436 return uid;
6437}
6438static inline int low2highgid(int gid)
6439{
6440 return gid;
6441}
6442static inline int tswapid(int id)
6443{
6444 return tswap32(id);
6445}
Peter Maydell76ca3102014-03-02 19:36:41 +00006446
6447#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6448
bellard67867302003-11-23 17:05:30 +00006449#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006450
Peter Maydellfd6f7792016-03-01 16:33:02 +00006451/* We must do direct syscalls for setting UID/GID, because we want to
6452 * implement the Linux system call semantics of "change only for this thread",
6453 * not the libc/POSIX semantics of "change for all threads in process".
6454 * (See http://ewontfix.com/17/ for more details.)
6455 * We use the 32-bit version of the syscalls if present; if it is not
6456 * then either the host architecture supports 32-bit UIDs natively with
6457 * the standard syscall, or the 16-bit UID is the best we can do.
6458 */
6459#ifdef __NR_setuid32
6460#define __NR_sys_setuid __NR_setuid32
6461#else
6462#define __NR_sys_setuid __NR_setuid
6463#endif
6464#ifdef __NR_setgid32
6465#define __NR_sys_setgid __NR_setgid32
6466#else
6467#define __NR_sys_setgid __NR_setgid
6468#endif
6469#ifdef __NR_setresuid32
6470#define __NR_sys_setresuid __NR_setresuid32
6471#else
6472#define __NR_sys_setresuid __NR_setresuid
6473#endif
6474#ifdef __NR_setresgid32
6475#define __NR_sys_setresgid __NR_setresgid32
6476#else
6477#define __NR_sys_setresgid __NR_setresgid
6478#endif
6479
6480_syscall1(int, sys_setuid, uid_t, uid)
6481_syscall1(int, sys_setgid, gid_t, gid)
6482_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6483_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6484
bellard31e31b82003-02-18 22:55:36 +00006485void syscall_init(void)
6486{
bellard2ab83ea2003-06-15 19:56:46 +00006487 IOCTLEntry *ie;
6488 const argtype *arg_type;
6489 int size;
thsb92c47c2007-11-01 00:07:38 +00006490 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006491
Alexander Graf8be656b2015-05-06 23:47:32 +02006492 thunk_init(STRUCT_MAX);
6493
Blue Swirl001faf32009-05-13 17:53:17 +00006494#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006495#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006496#include "syscall_types.h"
6497#undef STRUCT
6498#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006499
Peter Maydelldd6e9572012-07-23 08:07:22 +00006500 /* Build target_to_host_errno_table[] table from
6501 * host_to_target_errno_table[]. */
6502 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6503 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6504 }
6505
bellard2ab83ea2003-06-15 19:56:46 +00006506 /* we patch the ioctl size if necessary. We rely on the fact that
6507 no ioctl has all the bits at '1' in the size field */
6508 ie = ioctl_entries;
6509 while (ie->target_cmd != 0) {
6510 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6511 TARGET_IOC_SIZEMASK) {
6512 arg_type = ie->arg_type;
6513 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006514 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006515 ie->target_cmd);
6516 exit(1);
6517 }
6518 arg_type++;
6519 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006520 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006521 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6522 (size << TARGET_IOC_SIZESHIFT);
6523 }
thsb92c47c2007-11-01 00:07:38 +00006524
bellard2ab83ea2003-06-15 19:56:46 +00006525 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006526#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6527 (defined(__x86_64__) && defined(TARGET_X86_64))
6528 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6529 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6530 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006531 }
6532#endif
6533 ie++;
6534 }
bellard31e31b82003-02-18 22:55:36 +00006535}
bellardc573ff62004-01-04 15:51:36 +00006536
blueswir1992f48a2007-10-14 16:27:31 +00006537#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006538static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6539{
thsaf325d32008-06-10 15:29:15 +00006540#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006541 return ((uint64_t)word0 << 32) | word1;
6542#else
6543 return ((uint64_t)word1 << 32) | word0;
6544#endif
6545}
blueswir1992f48a2007-10-14 16:27:31 +00006546#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006547static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6548{
6549 return word0;
6550}
blueswir1992f48a2007-10-14 16:27:31 +00006551#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006552
6553#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006554static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6555 abi_long arg2,
6556 abi_long arg3,
6557 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006558{
Riku Voipio48e515d2011-07-12 15:40:51 +03006559 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006560 arg2 = arg3;
6561 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006562 }
pbrookce4defa2006-02-09 16:49:55 +00006563 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6564}
6565#endif
6566
6567#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006568static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6569 abi_long arg2,
6570 abi_long arg3,
6571 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006572{
Riku Voipio48e515d2011-07-12 15:40:51 +03006573 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006574 arg2 = arg3;
6575 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006576 }
pbrookce4defa2006-02-09 16:49:55 +00006577 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6578}
6579#endif
6580
bellard579a97f2007-11-11 14:26:47 +00006581static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6582 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006583{
6584 struct target_timespec *target_ts;
6585
bellard579a97f2007-11-11 14:26:47 +00006586 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6587 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006588 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6589 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006590 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006591 return 0;
pbrook53a59602006-03-25 19:31:22 +00006592}
6593
bellard579a97f2007-11-11 14:26:47 +00006594static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6595 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006596{
6597 struct target_timespec *target_ts;
6598
bellard579a97f2007-11-11 14:26:47 +00006599 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6600 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006601 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6602 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006603 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006604 return 0;
pbrook53a59602006-03-25 19:31:22 +00006605}
6606
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006607static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6608 abi_ulong target_addr)
6609{
6610 struct target_itimerspec *target_itspec;
6611
6612 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6613 return -TARGET_EFAULT;
6614 }
6615
6616 host_itspec->it_interval.tv_sec =
6617 tswapal(target_itspec->it_interval.tv_sec);
6618 host_itspec->it_interval.tv_nsec =
6619 tswapal(target_itspec->it_interval.tv_nsec);
6620 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6621 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6622
6623 unlock_user_struct(target_itspec, target_addr, 1);
6624 return 0;
6625}
6626
6627static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6628 struct itimerspec *host_its)
6629{
6630 struct target_itimerspec *target_itspec;
6631
6632 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6633 return -TARGET_EFAULT;
6634 }
6635
6636 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6637 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6638
6639 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6640 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6641
6642 unlock_user_struct(target_itspec, target_addr, 0);
6643 return 0;
6644}
6645
Peter Maydellc0659762014-08-09 15:42:32 +01006646static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6647 abi_ulong target_addr)
6648{
6649 struct target_sigevent *target_sevp;
6650
6651 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6652 return -TARGET_EFAULT;
6653 }
6654
6655 /* This union is awkward on 64 bit systems because it has a 32 bit
6656 * integer and a pointer in it; we follow the conversion approach
6657 * used for handling sigval types in signal.c so the guest should get
6658 * the correct value back even if we did a 64 bit byteswap and it's
6659 * using the 32 bit integer.
6660 */
6661 host_sevp->sigev_value.sival_ptr =
6662 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6663 host_sevp->sigev_signo =
6664 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6665 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6666 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6667
6668 unlock_user_struct(target_sevp, target_addr, 1);
6669 return 0;
6670}
6671
Tom Musta6f6a4032014-08-12 13:53:42 -05006672#if defined(TARGET_NR_mlockall)
6673static inline int target_to_host_mlockall_arg(int arg)
6674{
6675 int result = 0;
6676
6677 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6678 result |= MCL_CURRENT;
6679 }
6680 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6681 result |= MCL_FUTURE;
6682 }
6683 return result;
6684}
6685#endif
6686
balrog6a24a772008-09-20 02:23:36 +00006687static inline abi_long host_to_target_stat64(void *cpu_env,
6688 abi_ulong target_addr,
6689 struct stat *host_st)
6690{
Alexander Graf09701192013-09-03 20:12:15 +01006691#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006692 if (((CPUARMState *)cpu_env)->eabi) {
6693 struct target_eabi_stat64 *target_st;
6694
6695 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6696 return -TARGET_EFAULT;
6697 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6698 __put_user(host_st->st_dev, &target_st->st_dev);
6699 __put_user(host_st->st_ino, &target_st->st_ino);
6700#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6701 __put_user(host_st->st_ino, &target_st->__st_ino);
6702#endif
6703 __put_user(host_st->st_mode, &target_st->st_mode);
6704 __put_user(host_st->st_nlink, &target_st->st_nlink);
6705 __put_user(host_st->st_uid, &target_st->st_uid);
6706 __put_user(host_st->st_gid, &target_st->st_gid);
6707 __put_user(host_st->st_rdev, &target_st->st_rdev);
6708 __put_user(host_st->st_size, &target_st->st_size);
6709 __put_user(host_st->st_blksize, &target_st->st_blksize);
6710 __put_user(host_st->st_blocks, &target_st->st_blocks);
6711 __put_user(host_st->st_atime, &target_st->target_st_atime);
6712 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6713 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6714 unlock_user_struct(target_st, target_addr, 1);
6715 } else
6716#endif
6717 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006718#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006719 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006720#else
6721 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006722#endif
balrog6a24a772008-09-20 02:23:36 +00006723
6724 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6725 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006726 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006727 __put_user(host_st->st_dev, &target_st->st_dev);
6728 __put_user(host_st->st_ino, &target_st->st_ino);
6729#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6730 __put_user(host_st->st_ino, &target_st->__st_ino);
6731#endif
6732 __put_user(host_st->st_mode, &target_st->st_mode);
6733 __put_user(host_st->st_nlink, &target_st->st_nlink);
6734 __put_user(host_st->st_uid, &target_st->st_uid);
6735 __put_user(host_st->st_gid, &target_st->st_gid);
6736 __put_user(host_st->st_rdev, &target_st->st_rdev);
6737 /* XXX: better use of kernel struct */
6738 __put_user(host_st->st_size, &target_st->st_size);
6739 __put_user(host_st->st_blksize, &target_st->st_blksize);
6740 __put_user(host_st->st_blocks, &target_st->st_blocks);
6741 __put_user(host_st->st_atime, &target_st->target_st_atime);
6742 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6743 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6744 unlock_user_struct(target_st, target_addr, 1);
6745 }
6746
6747 return 0;
6748}
balrog6a24a772008-09-20 02:23:36 +00006749
pbrookbd0c5662008-05-29 14:34:11 +00006750/* ??? Using host futex calls even when target atomic operations
6751 are not really atomic probably breaks things. However implementing
6752 futexes locally would make futexes shared between multiple processes
6753 tricky. However they're probably useless because guest atomic
6754 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006755static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6756 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006757{
6758 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006759 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006760
6761 /* ??? We assume FUTEX_* constants are the same on both host
6762 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006763#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006764 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006765#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006766 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006767#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006768 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006769 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006770 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006771 if (timeout) {
6772 pts = &ts;
6773 target_to_host_timespec(pts, timeout);
6774 } else {
6775 pts = NULL;
6776 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006777 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006778 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006779 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006780 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006781 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006782 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006783 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006784 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006785 case FUTEX_WAKE_OP:
6786 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6787 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6788 But the prototype takes a `struct timespec *'; insert casts
6789 to satisfy the compiler. We do not need to tswap TIMEOUT
6790 since it's not compared to guest memory. */
6791 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006792 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6793 g2h(uaddr2),
6794 (base_op == FUTEX_CMP_REQUEUE
6795 ? tswap32(val3)
6796 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006797 default:
6798 return -TARGET_ENOSYS;
6799 }
6800}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006801#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6802static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6803 abi_long handle, abi_long mount_id,
6804 abi_long flags)
6805{
6806 struct file_handle *target_fh;
6807 struct file_handle *fh;
6808 int mid = 0;
6809 abi_long ret;
6810 char *name;
6811 unsigned int size, total_size;
6812
6813 if (get_user_s32(size, handle)) {
6814 return -TARGET_EFAULT;
6815 }
6816
6817 name = lock_user_string(pathname);
6818 if (!name) {
6819 return -TARGET_EFAULT;
6820 }
6821
6822 total_size = sizeof(struct file_handle) + size;
6823 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6824 if (!target_fh) {
6825 unlock_user(name, pathname, 0);
6826 return -TARGET_EFAULT;
6827 }
6828
6829 fh = g_malloc0(total_size);
6830 fh->handle_bytes = size;
6831
6832 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6833 unlock_user(name, pathname, 0);
6834
6835 /* man name_to_handle_at(2):
6836 * Other than the use of the handle_bytes field, the caller should treat
6837 * the file_handle structure as an opaque data type
6838 */
6839
6840 memcpy(target_fh, fh, total_size);
6841 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6842 target_fh->handle_type = tswap32(fh->handle_type);
6843 g_free(fh);
6844 unlock_user(target_fh, handle, total_size);
6845
6846 if (put_user_s32(mid, mount_id)) {
6847 return -TARGET_EFAULT;
6848 }
6849
6850 return ret;
6851
6852}
6853#endif
6854
6855#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6856static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6857 abi_long flags)
6858{
6859 struct file_handle *target_fh;
6860 struct file_handle *fh;
6861 unsigned int size, total_size;
6862 abi_long ret;
6863
6864 if (get_user_s32(size, handle)) {
6865 return -TARGET_EFAULT;
6866 }
6867
6868 total_size = sizeof(struct file_handle) + size;
6869 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6870 if (!target_fh) {
6871 return -TARGET_EFAULT;
6872 }
6873
Thomas Huthe9d49d52015-10-09 17:56:38 +02006874 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006875 fh->handle_bytes = size;
6876 fh->handle_type = tswap32(target_fh->handle_type);
6877
6878 ret = get_errno(open_by_handle_at(mount_fd, fh,
6879 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6880
6881 g_free(fh);
6882
6883 unlock_user(target_fh, handle, total_size);
6884
6885 return ret;
6886}
6887#endif
pbrookbd0c5662008-05-29 14:34:11 +00006888
Laurent Viviere36800c2015-10-02 14:48:09 +02006889#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6890
6891/* signalfd siginfo conversion */
6892
6893static void
6894host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6895 const struct signalfd_siginfo *info)
6896{
6897 int sig = host_to_target_signal(info->ssi_signo);
6898
6899 /* linux/signalfd.h defines a ssi_addr_lsb
6900 * not defined in sys/signalfd.h but used by some kernels
6901 */
6902
6903#ifdef BUS_MCEERR_AO
6904 if (tinfo->ssi_signo == SIGBUS &&
6905 (tinfo->ssi_code == BUS_MCEERR_AR ||
6906 tinfo->ssi_code == BUS_MCEERR_AO)) {
6907 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6908 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6909 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6910 }
6911#endif
6912
6913 tinfo->ssi_signo = tswap32(sig);
6914 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6915 tinfo->ssi_code = tswap32(info->ssi_code);
6916 tinfo->ssi_pid = tswap32(info->ssi_pid);
6917 tinfo->ssi_uid = tswap32(info->ssi_uid);
6918 tinfo->ssi_fd = tswap32(info->ssi_fd);
6919 tinfo->ssi_tid = tswap32(info->ssi_tid);
6920 tinfo->ssi_band = tswap32(info->ssi_band);
6921 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6922 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6923 tinfo->ssi_status = tswap32(info->ssi_status);
6924 tinfo->ssi_int = tswap32(info->ssi_int);
6925 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6926 tinfo->ssi_utime = tswap64(info->ssi_utime);
6927 tinfo->ssi_stime = tswap64(info->ssi_stime);
6928 tinfo->ssi_addr = tswap64(info->ssi_addr);
6929}
6930
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006931static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006932{
6933 int i;
6934
6935 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6936 host_to_target_signalfd_siginfo(buf + i, buf + i);
6937 }
6938
6939 return len;
6940}
6941
6942static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006943 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006944};
6945
6946static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6947{
6948 int host_flags;
6949 target_sigset_t *target_mask;
6950 sigset_t host_mask;
6951 abi_long ret;
6952
6953 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6954 return -TARGET_EINVAL;
6955 }
6956 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6957 return -TARGET_EFAULT;
6958 }
6959
6960 target_to_host_sigset(&host_mask, target_mask);
6961
6962 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6963
6964 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6965 if (ret >= 0) {
6966 fd_trans_register(ret, &target_signalfd_trans);
6967 }
6968
6969 unlock_user_struct(target_mask, mask, 0);
6970
6971 return ret;
6972}
6973#endif
6974
pbrook1d9d8b52009-04-16 15:17:02 +00006975/* Map host to target signal numbers for the wait family of syscalls.
6976 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006977int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006978{
6979 if (WIFSIGNALED(status)) {
6980 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6981 }
6982 if (WIFSTOPPED(status)) {
6983 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6984 | (status & 0xff);
6985 }
6986 return status;
6987}
6988
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006989static int open_self_cmdline(void *cpu_env, int fd)
6990{
6991 int fd_orig = -1;
6992 bool word_skipped = false;
6993
6994 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6995 if (fd_orig < 0) {
6996 return fd_orig;
6997 }
6998
6999 while (true) {
7000 ssize_t nb_read;
7001 char buf[128];
7002 char *cp_buf = buf;
7003
7004 nb_read = read(fd_orig, buf, sizeof(buf));
7005 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007006 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007007 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007008 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007009 return -1;
7010 } else if (nb_read == 0) {
7011 break;
7012 }
7013
7014 if (!word_skipped) {
7015 /* Skip the first string, which is the path to qemu-*-static
7016 instead of the actual command. */
Peter Maydellba4b3f62016-07-12 13:02:19 +01007017 cp_buf = memchr(buf, 0, nb_read);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007018 if (cp_buf) {
7019 /* Null byte found, skip one string */
7020 cp_buf++;
7021 nb_read -= cp_buf - buf;
7022 word_skipped = true;
7023 }
7024 }
7025
7026 if (word_skipped) {
7027 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007028 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08007029 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007030 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007031 return -1;
7032 }
7033 }
7034 }
7035
7036 return close(fd_orig);
7037}
7038
Alexander Graf36c08d42011-11-02 20:23:24 +01007039static int open_self_maps(void *cpu_env, int fd)
7040{
Andreas Färber0429a972013-08-26 18:14:44 +02007041 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7042 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007043 FILE *fp;
7044 char *line = NULL;
7045 size_t len = 0;
7046 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007047
Alexander Graf1a49ef22012-05-01 16:30:28 +01007048 fp = fopen("/proc/self/maps", "r");
7049 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007050 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007051 }
7052
7053 while ((read = getline(&line, &len, fp)) != -1) {
7054 int fields, dev_maj, dev_min, inode;
7055 uint64_t min, max, offset;
7056 char flag_r, flag_w, flag_x, flag_p;
7057 char path[512] = "";
7058 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7059 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7060 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7061
7062 if ((fields < 10) || (fields > 11)) {
7063 continue;
7064 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007065 if (h2g_valid(min)) {
7066 int flags = page_get_flags(h2g(min));
7067 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
7068 if (page_check_range(h2g(min), max - min, flags) == -1) {
7069 continue;
7070 }
7071 if (h2g(min) == ts->info->stack_limit) {
7072 pstrcpy(path, sizeof(path), " [stack]");
7073 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007074 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007075 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007076 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007077 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007078 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007079 }
7080 }
7081
7082 free(line);
7083 fclose(fp);
7084
Alexander Graf36c08d42011-11-02 20:23:24 +01007085 return 0;
7086}
7087
Alexander Graf480b8e72011-11-02 20:23:25 +01007088static int open_self_stat(void *cpu_env, int fd)
7089{
Andreas Färber0429a972013-08-26 18:14:44 +02007090 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7091 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007092 abi_ulong start_stack = ts->info->start_stack;
7093 int i;
7094
7095 for (i = 0; i < 44; i++) {
7096 char buf[128];
7097 int len;
7098 uint64_t val = 0;
7099
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007100 if (i == 0) {
7101 /* pid */
7102 val = getpid();
7103 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7104 } else if (i == 1) {
7105 /* app name */
7106 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7107 } else if (i == 27) {
7108 /* stack bottom */
7109 val = start_stack;
7110 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7111 } else {
7112 /* for the rest, there is MasterCard */
7113 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007114 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007115
Alexander Graf480b8e72011-11-02 20:23:25 +01007116 len = strlen(buf);
7117 if (write(fd, buf, len) != len) {
7118 return -1;
7119 }
7120 }
7121
7122 return 0;
7123}
7124
Alexander Graf257450e2011-11-02 20:23:26 +01007125static int open_self_auxv(void *cpu_env, int fd)
7126{
Andreas Färber0429a972013-08-26 18:14:44 +02007127 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7128 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007129 abi_ulong auxv = ts->info->saved_auxv;
7130 abi_ulong len = ts->info->auxv_len;
7131 char *ptr;
7132
7133 /*
7134 * Auxiliary vector is stored in target process stack.
7135 * read in whole auxv vector and copy it to file
7136 */
7137 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7138 if (ptr != NULL) {
7139 while (len > 0) {
7140 ssize_t r;
7141 r = write(fd, ptr, len);
7142 if (r <= 0) {
7143 break;
7144 }
7145 len -= r;
7146 ptr += r;
7147 }
7148 lseek(fd, 0, SEEK_SET);
7149 unlock_user(ptr, auxv, len);
7150 }
7151
7152 return 0;
7153}
7154
Andreas Schwab463d8e72013-07-02 14:04:12 +01007155static int is_proc_myself(const char *filename, const char *entry)
7156{
7157 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7158 filename += strlen("/proc/");
7159 if (!strncmp(filename, "self/", strlen("self/"))) {
7160 filename += strlen("self/");
7161 } else if (*filename >= '1' && *filename <= '9') {
7162 char myself[80];
7163 snprintf(myself, sizeof(myself), "%d/", getpid());
7164 if (!strncmp(filename, myself, strlen(myself))) {
7165 filename += strlen(myself);
7166 } else {
7167 return 0;
7168 }
7169 } else {
7170 return 0;
7171 }
7172 if (!strcmp(filename, entry)) {
7173 return 1;
7174 }
7175 }
7176 return 0;
7177}
7178
Laurent Vivierde6b9932013-08-30 01:46:40 +02007179#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7180static int is_proc(const char *filename, const char *entry)
7181{
7182 return strcmp(filename, entry) == 0;
7183}
7184
7185static int open_net_route(void *cpu_env, int fd)
7186{
7187 FILE *fp;
7188 char *line = NULL;
7189 size_t len = 0;
7190 ssize_t read;
7191
7192 fp = fopen("/proc/net/route", "r");
7193 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007194 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007195 }
7196
7197 /* read header */
7198
7199 read = getline(&line, &len, fp);
7200 dprintf(fd, "%s", line);
7201
7202 /* read routes */
7203
7204 while ((read = getline(&line, &len, fp)) != -1) {
7205 char iface[16];
7206 uint32_t dest, gw, mask;
7207 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7208 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7209 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7210 &mask, &mtu, &window, &irtt);
7211 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7212 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7213 metric, tswap32(mask), mtu, window, irtt);
7214 }
7215
7216 free(line);
7217 fclose(fp);
7218
7219 return 0;
7220}
7221#endif
7222
Riku Voipio0b2effd2014-08-06 10:36:37 +03007223static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007224{
7225 struct fake_open {
7226 const char *filename;
7227 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007228 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007229 };
7230 const struct fake_open *fake_open;
7231 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007232 { "maps", open_self_maps, is_proc_myself },
7233 { "stat", open_self_stat, is_proc_myself },
7234 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007235 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007236#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7237 { "/proc/net/route", open_net_route, is_proc },
7238#endif
7239 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007240 };
7241
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007242 if (is_proc_myself(pathname, "exe")) {
7243 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007244 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007245 }
7246
Alexander Graf3be14d02011-11-02 20:23:23 +01007247 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007248 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007249 break;
7250 }
7251 }
7252
7253 if (fake_open->filename) {
7254 const char *tmpdir;
7255 char filename[PATH_MAX];
7256 int fd, r;
7257
7258 /* create temporary file to map stat to */
7259 tmpdir = getenv("TMPDIR");
7260 if (!tmpdir)
7261 tmpdir = "/tmp";
7262 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7263 fd = mkstemp(filename);
7264 if (fd < 0) {
7265 return fd;
7266 }
7267 unlink(filename);
7268
7269 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007270 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007271 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007272 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007273 return r;
7274 }
7275 lseek(fd, 0, SEEK_SET);
7276
7277 return fd;
7278 }
7279
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007280 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007281}
7282
Alexander Grafaecc8862014-11-10 21:33:03 +01007283#define TIMER_MAGIC 0x0caf0000
7284#define TIMER_MAGIC_MASK 0xffff0000
7285
7286/* Convert QEMU provided timer ID back to internal 16bit index format */
7287static target_timer_t get_timer_id(abi_long arg)
7288{
7289 target_timer_t timerid = arg;
7290
7291 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7292 return -TARGET_EINVAL;
7293 }
7294
7295 timerid &= 0xffff;
7296
7297 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7298 return -TARGET_EINVAL;
7299 }
7300
7301 return timerid;
7302}
7303
ths0da46a62007-10-20 20:23:07 +00007304/* do_syscall() should always have a single exit point at the end so
7305 that actions, such as logging of syscall results, can be performed.
7306 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007307abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7308 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007309 abi_long arg5, abi_long arg6, abi_long arg7,
7310 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007311{
Andreas Färber182735e2013-05-29 22:29:20 +02007312 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007313 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007314 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007315 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007316 void *p;
ths3b46e622007-09-17 08:09:54 +00007317
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007318#if defined(DEBUG_ERESTARTSYS)
7319 /* Debug-only code for exercising the syscall-restart code paths
7320 * in the per-architecture cpu main loops: restart every syscall
7321 * the guest makes once before letting it through.
7322 */
7323 {
7324 static int flag;
7325
7326 flag = !flag;
7327 if (flag) {
7328 return -TARGET_ERESTARTSYS;
7329 }
7330 }
7331#endif
7332
bellard72f03902003-02-18 23:33:18 +00007333#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007334 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007335#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007336 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007337 if(do_strace)
7338 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7339
bellard31e31b82003-02-18 22:55:36 +00007340 switch(num) {
7341 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007342 /* In old applications this may be used to implement _exit(2).
7343 However in threaded applictions it is used for thread termination,
7344 and _exit_group is used for application termination.
7345 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007346
7347 if (block_signals()) {
7348 ret = -TARGET_ERESTARTSYS;
7349 break;
7350 }
7351
Andreas Färberbdc44642013-06-24 23:50:24 +02007352 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007353 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007354
Andreas Färber9b056fc2013-06-24 23:53:10 +02007355 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007356 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007357 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02007358 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02007359 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007360 if (ts->child_tidptr) {
7361 put_user_u32(0, ts->child_tidptr);
7362 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7363 NULL, NULL, 0);
7364 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007365 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007366 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007367 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007368 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007369 pthread_exit(NULL);
7370 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02007371#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007372 _mcleanup();
7373#endif
bellarde9009672005-04-26 20:42:36 +00007374 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007375 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007376 ret = 0; /* avoid warning */
7377 break;
7378 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007379 if (arg3 == 0)
7380 ret = 0;
7381 else {
7382 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7383 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007384 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007385 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007386 fd_trans_host_to_target_data(arg1)) {
7387 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007388 }
aurel3238d840e2009-01-30 19:48:17 +00007389 unlock_user(p, arg2, ret);
7390 }
bellard31e31b82003-02-18 22:55:36 +00007391 break;
7392 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007393 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7394 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007395 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00007396 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007397 break;
Chen Gang704eff62015-08-21 05:37:33 +08007398#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007399 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007400 if (!(p = lock_user_string(arg1)))
7401 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007402 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7403 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7404 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007405 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007406 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007407 break;
Chen Gang704eff62015-08-21 05:37:33 +08007408#endif
ths82424832007-09-24 09:21:55 +00007409 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007410 if (!(p = lock_user_string(arg2)))
7411 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007412 ret = get_errno(do_openat(cpu_env, arg1, p,
7413 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7414 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007415 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007416 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007417 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007418#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7419 case TARGET_NR_name_to_handle_at:
7420 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7421 break;
7422#endif
7423#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7424 case TARGET_NR_open_by_handle_at:
7425 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007426 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007427 break;
7428#endif
bellard31e31b82003-02-18 22:55:36 +00007429 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007430 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007431 ret = get_errno(close(arg1));
7432 break;
7433 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007434 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007435 break;
Chen Gang704eff62015-08-21 05:37:33 +08007436#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007437 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00007438 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007439 break;
Chen Gang704eff62015-08-21 05:37:33 +08007440#endif
thse5febef2007-04-01 18:31:35 +00007441#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007442 case TARGET_NR_waitpid:
7443 {
pbrook53a59602006-03-25 19:31:22 +00007444 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007445 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007446 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007447 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007448 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007449 }
7450 break;
thse5febef2007-04-01 18:31:35 +00007451#endif
pbrookf0cbb612008-05-30 18:20:05 +00007452#ifdef TARGET_NR_waitid
7453 case TARGET_NR_waitid:
7454 {
7455 siginfo_t info;
7456 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007457 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007458 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007459 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00007460 goto efault;
7461 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007462 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007463 }
7464 }
7465 break;
7466#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007467#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007468 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007469 if (!(p = lock_user_string(arg1)))
7470 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007471 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007472 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007473 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007474 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007475#endif
Chen Gang704eff62015-08-21 05:37:33 +08007476#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007477 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007478 {
7479 void * p2;
7480 p = lock_user_string(arg1);
7481 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007482 if (!p || !p2)
7483 ret = -TARGET_EFAULT;
7484 else
7485 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007486 unlock_user(p2, arg2, 0);
7487 unlock_user(p, arg1, 0);
7488 }
bellard31e31b82003-02-18 22:55:36 +00007489 break;
Chen Gang704eff62015-08-21 05:37:33 +08007490#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007491#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007492 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007493 {
7494 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007495 if (!arg2 || !arg4)
7496 goto efault;
ths64f0ce42007-09-24 09:25:06 +00007497 p = lock_user_string(arg2);
7498 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007499 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007500 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007501 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007502 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007503 unlock_user(p, arg2, 0);
7504 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007505 }
7506 break;
7507#endif
Chen Gang704eff62015-08-21 05:37:33 +08007508#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007509 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007510 if (!(p = lock_user_string(arg1)))
7511 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007512 ret = get_errno(unlink(p));
7513 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007514 break;
Chen Gang704eff62015-08-21 05:37:33 +08007515#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007516#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007517 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007518 if (!(p = lock_user_string(arg2)))
7519 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007520 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007521 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007522 break;
balrogb7d35e62007-12-12 00:40:24 +00007523#endif
bellard31e31b82003-02-18 22:55:36 +00007524 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007525 {
7526 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007527 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007528 abi_ulong gp;
7529 abi_ulong guest_argp;
7530 abi_ulong guest_envp;
7531 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007532 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007533 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007534
bellardf7341ff2003-03-30 21:00:25 +00007535 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007536 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007537 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007538 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007539 goto efault;
ths03aa1972007-12-02 06:28:08 +00007540 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007541 break;
bellard7854b052003-03-29 17:22:23 +00007542 argc++;
bellard2f619692007-11-16 10:46:05 +00007543 }
bellardf7341ff2003-03-30 21:00:25 +00007544 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007545 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007546 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007547 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007548 goto efault;
ths03aa1972007-12-02 06:28:08 +00007549 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007550 break;
bellard7854b052003-03-29 17:22:23 +00007551 envc++;
bellard2f619692007-11-16 10:46:05 +00007552 }
bellard7854b052003-03-29 17:22:23 +00007553
bellardf7341ff2003-03-30 21:00:25 +00007554 argp = alloca((argc + 1) * sizeof(void *));
7555 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007556
pbrookda94d262008-05-30 18:24:00 +00007557 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007558 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007559 if (get_user_ual(addr, gp))
7560 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007561 if (!addr)
7562 break;
bellard2f619692007-11-16 10:46:05 +00007563 if (!(*q = lock_user_string(addr)))
7564 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007565 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007566 }
bellardf7341ff2003-03-30 21:00:25 +00007567 *q = NULL;
7568
pbrookda94d262008-05-30 18:24:00 +00007569 for (gp = guest_envp, q = envp; 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;
bellard7854b052003-03-29 17:22:23 +00007580
bellard2f619692007-11-16 10:46:05 +00007581 if (!(p = lock_user_string(arg1)))
7582 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007583 /* Although execve() is not an interruptible syscall it is
7584 * a special case where we must use the safe_syscall wrapper:
7585 * if we allow a signal to happen before we make the host
7586 * syscall then we will 'lose' it, because at the point of
7587 * execve the process leaves QEMU's control. So we use the
7588 * safe syscall wrapper to ensure that we either take the
7589 * signal as a guest signal, or else it does not happen
7590 * before the execve completes and makes it the other
7591 * program's problem.
7592 */
7593 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007594 unlock_user(p, arg1, 0);
7595
bellard2f619692007-11-16 10:46:05 +00007596 goto execve_end;
7597
7598 execve_efault:
7599 ret = -TARGET_EFAULT;
7600
7601 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007602 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007603 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007604 if (get_user_ual(addr, gp)
7605 || !addr)
7606 break;
pbrook53a59602006-03-25 19:31:22 +00007607 unlock_user(*q, addr, 0);
7608 }
7609 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007610 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007611 if (get_user_ual(addr, gp)
7612 || !addr)
7613 break;
pbrook53a59602006-03-25 19:31:22 +00007614 unlock_user(*q, addr, 0);
7615 }
bellard7854b052003-03-29 17:22:23 +00007616 }
bellard31e31b82003-02-18 22:55:36 +00007617 break;
7618 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007619 if (!(p = lock_user_string(arg1)))
7620 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007621 ret = get_errno(chdir(p));
7622 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007623 break;
bellarda315a142005-01-30 22:59:18 +00007624#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007625 case TARGET_NR_time:
7626 {
pbrook53a59602006-03-25 19:31:22 +00007627 time_t host_time;
7628 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007629 if (!is_error(ret)
7630 && arg1
7631 && put_user_sal(host_time, arg1))
7632 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007633 }
7634 break;
bellarda315a142005-01-30 22:59:18 +00007635#endif
Chen Gang704eff62015-08-21 05:37:33 +08007636#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007637 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007638 if (!(p = lock_user_string(arg1)))
7639 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007640 ret = get_errno(mknod(p, arg2, arg3));
7641 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007642 break;
Chen Gang704eff62015-08-21 05:37:33 +08007643#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007644#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007645 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007646 if (!(p = lock_user_string(arg2)))
7647 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007648 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007649 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007650 break;
7651#endif
Chen Gang704eff62015-08-21 05:37:33 +08007652#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007653 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007654 if (!(p = lock_user_string(arg1)))
7655 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007656 ret = get_errno(chmod(p, arg2));
7657 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007658 break;
Chen Gang704eff62015-08-21 05:37:33 +08007659#endif
bellardebc05482003-09-30 21:08:41 +00007660#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007661 case TARGET_NR_break:
7662 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007663#endif
7664#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007665 case TARGET_NR_oldstat:
7666 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007667#endif
bellard31e31b82003-02-18 22:55:36 +00007668 case TARGET_NR_lseek:
7669 ret = get_errno(lseek(arg1, arg2, arg3));
7670 break;
Richard Henderson92317332010-05-03 10:07:53 -07007671#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7672 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007673 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007674 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007675 ret = get_errno(getpid());
7676 break;
Richard Henderson92317332010-05-03 10:07:53 -07007677#endif
7678#ifdef TARGET_NR_getpid
7679 case TARGET_NR_getpid:
7680 ret = get_errno(getpid());
7681 break;
7682#endif
bellard31e31b82003-02-18 22:55:36 +00007683 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007684 {
7685 /* need to look at the data field */
7686 void *p2, *p3;
7687
7688 if (arg1) {
7689 p = lock_user_string(arg1);
7690 if (!p) {
7691 goto efault;
7692 }
7693 } else {
7694 p = NULL;
7695 }
7696
7697 p2 = lock_user_string(arg2);
7698 if (!p2) {
7699 if (arg1) {
7700 unlock_user(p, arg1, 0);
7701 }
7702 goto efault;
7703 }
7704
7705 if (arg3) {
7706 p3 = lock_user_string(arg3);
7707 if (!p3) {
7708 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007709 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007710 }
7711 unlock_user(p2, arg2, 0);
7712 goto efault;
7713 }
7714 } else {
7715 p3 = NULL;
7716 }
7717
7718 /* FIXME - arg5 should be locked, but it isn't clear how to
7719 * do that since it's not guaranteed to be a NULL-terminated
7720 * string.
7721 */
7722 if (!arg5) {
7723 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7724 } else {
7725 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7726 }
7727 ret = get_errno(ret);
7728
7729 if (arg1) {
7730 unlock_user(p, arg1, 0);
7731 }
7732 unlock_user(p2, arg2, 0);
7733 if (arg3) {
7734 unlock_user(p3, arg3, 0);
7735 }
7736 }
7737 break;
thse5febef2007-04-01 18:31:35 +00007738#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007739 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007740 if (!(p = lock_user_string(arg1)))
7741 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007742 ret = get_errno(umount(p));
7743 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007744 break;
thse5febef2007-04-01 18:31:35 +00007745#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007746#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007747 case TARGET_NR_stime:
7748 {
pbrook53a59602006-03-25 19:31:22 +00007749 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007750 if (get_user_sal(host_time, arg1))
7751 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007752 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007753 }
7754 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007755#endif
bellard31e31b82003-02-18 22:55:36 +00007756 case TARGET_NR_ptrace:
7757 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007758#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007759 case TARGET_NR_alarm:
7760 ret = alarm(arg1);
7761 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007762#endif
bellardebc05482003-09-30 21:08:41 +00007763#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007764 case TARGET_NR_oldfstat:
7765 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007766#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007767#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007768 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007769 if (!block_signals()) {
7770 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7771 }
7772 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007773 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007774#endif
thse5febef2007-04-01 18:31:35 +00007775#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007776 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007777 {
pbrook53a59602006-03-25 19:31:22 +00007778 struct utimbuf tbuf, *host_tbuf;
7779 struct target_utimbuf *target_tbuf;
7780 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007781 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7782 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007783 tbuf.actime = tswapal(target_tbuf->actime);
7784 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007785 unlock_user_struct(target_tbuf, arg2, 0);
7786 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007787 } else {
pbrook53a59602006-03-25 19:31:22 +00007788 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007789 }
bellard579a97f2007-11-11 14:26:47 +00007790 if (!(p = lock_user_string(arg1)))
7791 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007792 ret = get_errno(utime(p, host_tbuf));
7793 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007794 }
7795 break;
thse5febef2007-04-01 18:31:35 +00007796#endif
Chen Gang704eff62015-08-21 05:37:33 +08007797#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007798 case TARGET_NR_utimes:
7799 {
bellard978a66f2004-12-06 22:58:05 +00007800 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007801 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007802 if (copy_from_user_timeval(&tv[0], arg2)
7803 || copy_from_user_timeval(&tv[1],
7804 arg2 + sizeof(struct target_timeval)))
7805 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007806 tvp = tv;
7807 } else {
7808 tvp = NULL;
7809 }
bellard579a97f2007-11-11 14:26:47 +00007810 if (!(p = lock_user_string(arg1)))
7811 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007812 ret = get_errno(utimes(p, tvp));
7813 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007814 }
7815 break;
Chen Gang704eff62015-08-21 05:37:33 +08007816#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007817#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007818 case TARGET_NR_futimesat:
7819 {
7820 struct timeval *tvp, tv[2];
7821 if (arg3) {
7822 if (copy_from_user_timeval(&tv[0], arg3)
7823 || copy_from_user_timeval(&tv[1],
7824 arg3 + sizeof(struct target_timeval)))
7825 goto efault;
7826 tvp = tv;
7827 } else {
7828 tvp = NULL;
7829 }
7830 if (!(p = lock_user_string(arg2)))
7831 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007832 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007833 unlock_user(p, arg2, 0);
7834 }
7835 break;
7836#endif
bellardebc05482003-09-30 21:08:41 +00007837#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007838 case TARGET_NR_stty:
7839 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007840#endif
7841#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007842 case TARGET_NR_gtty:
7843 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007844#endif
Chen Gang704eff62015-08-21 05:37:33 +08007845#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007846 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007847 if (!(p = lock_user_string(arg1)))
7848 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007849 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007850 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007851 break;
Chen Gang704eff62015-08-21 05:37:33 +08007852#endif
ths92a34c12007-09-24 09:27:49 +00007853#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7854 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007855 if (!(p = lock_user_string(arg2)))
7856 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007857 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007858 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007859 break;
7860#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007861#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007862 case TARGET_NR_nice:
7863 ret = get_errno(nice(arg1));
7864 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007865#endif
bellardebc05482003-09-30 21:08:41 +00007866#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007867 case TARGET_NR_ftime:
7868 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007869#endif
bellard31e31b82003-02-18 22:55:36 +00007870 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007871 sync();
7872 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007873 break;
7874 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007875 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007876 break;
Chen Gang704eff62015-08-21 05:37:33 +08007877#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007878 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007879 {
7880 void *p2;
7881 p = lock_user_string(arg1);
7882 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007883 if (!p || !p2)
7884 ret = -TARGET_EFAULT;
7885 else
7886 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007887 unlock_user(p2, arg2, 0);
7888 unlock_user(p, arg1, 0);
7889 }
bellard31e31b82003-02-18 22:55:36 +00007890 break;
Chen Gang704eff62015-08-21 05:37:33 +08007891#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007892#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007893 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007894 {
bellard579a97f2007-11-11 14:26:47 +00007895 void *p2;
ths722183f2007-09-24 09:24:37 +00007896 p = lock_user_string(arg2);
7897 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007898 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007899 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007900 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007901 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007902 unlock_user(p2, arg4, 0);
7903 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007904 }
7905 break;
7906#endif
Chen Gang704eff62015-08-21 05:37:33 +08007907#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007908 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007909 if (!(p = lock_user_string(arg1)))
7910 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007911 ret = get_errno(mkdir(p, arg2));
7912 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007913 break;
Chen Gang704eff62015-08-21 05:37:33 +08007914#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007915#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007916 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007917 if (!(p = lock_user_string(arg2)))
7918 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007919 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007920 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007921 break;
7922#endif
Chen Gang704eff62015-08-21 05:37:33 +08007923#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007924 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007925 if (!(p = lock_user_string(arg1)))
7926 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007927 ret = get_errno(rmdir(p));
7928 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007929 break;
Chen Gang704eff62015-08-21 05:37:33 +08007930#endif
bellard31e31b82003-02-18 22:55:36 +00007931 case TARGET_NR_dup:
7932 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007933 if (ret >= 0) {
7934 fd_trans_dup(arg1, ret);
7935 }
bellard31e31b82003-02-18 22:55:36 +00007936 break;
Chen Gang704eff62015-08-21 05:37:33 +08007937#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007938 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007939 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007940 break;
Chen Gang704eff62015-08-21 05:37:33 +08007941#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007942#ifdef TARGET_NR_pipe2
7943 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007944 ret = do_pipe(cpu_env, arg1,
7945 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007946 break;
7947#endif
bellard31e31b82003-02-18 22:55:36 +00007948 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007949 {
pbrook53a59602006-03-25 19:31:22 +00007950 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007951 struct tms tms;
7952 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007953 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007954 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7955 if (!tmsp)
7956 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007957 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7958 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7959 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7960 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007961 }
bellardc596ed12003-07-13 17:32:31 +00007962 if (!is_error(ret))
7963 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007964 }
7965 break;
bellardebc05482003-09-30 21:08:41 +00007966#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007967 case TARGET_NR_prof:
7968 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007969#endif
thse5febef2007-04-01 18:31:35 +00007970#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007971 case TARGET_NR_signal:
7972 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007973#endif
bellard31e31b82003-02-18 22:55:36 +00007974 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007975 if (arg1 == 0) {
7976 ret = get_errno(acct(NULL));
7977 } else {
7978 if (!(p = lock_user_string(arg1)))
7979 goto efault;
7980 ret = get_errno(acct(path(p)));
7981 unlock_user(p, arg1, 0);
7982 }
pbrook24836682006-04-16 14:14:53 +00007983 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007984#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007985 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007986 if (!(p = lock_user_string(arg1)))
7987 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007988 ret = get_errno(umount2(p, arg2));
7989 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007990 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007991#endif
bellardebc05482003-09-30 21:08:41 +00007992#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007993 case TARGET_NR_lock:
7994 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007995#endif
bellard31e31b82003-02-18 22:55:36 +00007996 case TARGET_NR_ioctl:
7997 ret = do_ioctl(arg1, arg2, arg3);
7998 break;
7999 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008000 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008001 break;
bellardebc05482003-09-30 21:08:41 +00008002#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008003 case TARGET_NR_mpx:
8004 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008005#endif
bellard31e31b82003-02-18 22:55:36 +00008006 case TARGET_NR_setpgid:
8007 ret = get_errno(setpgid(arg1, arg2));
8008 break;
bellardebc05482003-09-30 21:08:41 +00008009#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008010 case TARGET_NR_ulimit:
8011 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008012#endif
8013#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008014 case TARGET_NR_oldolduname:
8015 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008016#endif
bellard31e31b82003-02-18 22:55:36 +00008017 case TARGET_NR_umask:
8018 ret = get_errno(umask(arg1));
8019 break;
8020 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008021 if (!(p = lock_user_string(arg1)))
8022 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008023 ret = get_errno(chroot(p));
8024 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008025 break;
Chen Gang704eff62015-08-21 05:37:33 +08008026#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008027 case TARGET_NR_ustat:
8028 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008029#endif
8030#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008031 case TARGET_NR_dup2:
8032 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008033 if (ret >= 0) {
8034 fd_trans_dup(arg1, arg2);
8035 }
bellard31e31b82003-02-18 22:55:36 +00008036 break;
Chen Gang704eff62015-08-21 05:37:33 +08008037#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008038#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8039 case TARGET_NR_dup3:
8040 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008041 if (ret >= 0) {
8042 fd_trans_dup(arg1, arg2);
8043 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008044 break;
8045#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008046#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008047 case TARGET_NR_getppid:
8048 ret = get_errno(getppid());
8049 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008050#endif
Chen Gang704eff62015-08-21 05:37:33 +08008051#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008052 case TARGET_NR_getpgrp:
8053 ret = get_errno(getpgrp());
8054 break;
Chen Gang704eff62015-08-21 05:37:33 +08008055#endif
bellard31e31b82003-02-18 22:55:36 +00008056 case TARGET_NR_setsid:
8057 ret = get_errno(setsid());
8058 break;
thse5febef2007-04-01 18:31:35 +00008059#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008060 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008061 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008062#if defined(TARGET_ALPHA)
8063 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008064 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008065 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008066 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8067 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008068 act._sa_handler = old_act->_sa_handler;
8069 target_siginitset(&act.sa_mask, old_act->sa_mask);
8070 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008071 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008072 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008073 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008074 }
8075 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008076 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008077 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8078 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008079 old_act->_sa_handler = oact._sa_handler;
8080 old_act->sa_mask = oact.sa_mask.sig[0];
8081 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008082 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008083 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008084#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008085 struct target_sigaction act, oact, *pact, *old_act;
8086
8087 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008088 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8089 goto efault;
bellard106ec872006-06-27 21:08:10 +00008090 act._sa_handler = old_act->_sa_handler;
8091 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8092 act.sa_flags = old_act->sa_flags;
8093 unlock_user_struct(old_act, arg2, 0);
8094 pact = &act;
8095 } else {
8096 pact = NULL;
8097 }
8098
8099 ret = get_errno(do_sigaction(arg1, pact, &oact));
8100
8101 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008102 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8103 goto efault;
bellard106ec872006-06-27 21:08:10 +00008104 old_act->_sa_handler = oact._sa_handler;
8105 old_act->sa_flags = oact.sa_flags;
8106 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8107 old_act->sa_mask.sig[1] = 0;
8108 old_act->sa_mask.sig[2] = 0;
8109 old_act->sa_mask.sig[3] = 0;
8110 unlock_user_struct(old_act, arg3, 1);
8111 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008112#else
8113 struct target_old_sigaction *old_act;
8114 struct target_sigaction act, oact, *pact;
8115 if (arg2) {
8116 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8117 goto efault;
8118 act._sa_handler = old_act->_sa_handler;
8119 target_siginitset(&act.sa_mask, old_act->sa_mask);
8120 act.sa_flags = old_act->sa_flags;
8121 act.sa_restorer = old_act->sa_restorer;
8122 unlock_user_struct(old_act, arg2, 0);
8123 pact = &act;
8124 } else {
8125 pact = NULL;
8126 }
8127 ret = get_errno(do_sigaction(arg1, pact, &oact));
8128 if (!is_error(ret) && arg3) {
8129 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8130 goto efault;
8131 old_act->_sa_handler = oact._sa_handler;
8132 old_act->sa_mask = oact.sa_mask.sig[0];
8133 old_act->sa_flags = oact.sa_flags;
8134 old_act->sa_restorer = oact.sa_restorer;
8135 unlock_user_struct(old_act, arg3, 1);
8136 }
ths388bb212007-05-13 13:58:00 +00008137#endif
bellard31e31b82003-02-18 22:55:36 +00008138 }
8139 break;
thse5febef2007-04-01 18:31:35 +00008140#endif
bellard66fb9762003-03-23 01:06:05 +00008141 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008142 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008143#if defined(TARGET_ALPHA)
8144 struct target_sigaction act, oact, *pact = 0;
8145 struct target_rt_sigaction *rt_act;
Peter Maydellc8157012016-06-30 14:23:24 +01008146
8147 if (arg4 != sizeof(target_sigset_t)) {
8148 ret = -TARGET_EINVAL;
8149 break;
8150 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008151 if (arg2) {
8152 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8153 goto efault;
8154 act._sa_handler = rt_act->_sa_handler;
8155 act.sa_mask = rt_act->sa_mask;
8156 act.sa_flags = rt_act->sa_flags;
8157 act.sa_restorer = arg5;
8158 unlock_user_struct(rt_act, arg2, 0);
8159 pact = &act;
8160 }
8161 ret = get_errno(do_sigaction(arg1, pact, &oact));
8162 if (!is_error(ret) && arg3) {
8163 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8164 goto efault;
8165 rt_act->_sa_handler = oact._sa_handler;
8166 rt_act->sa_mask = oact.sa_mask;
8167 rt_act->sa_flags = oact.sa_flags;
8168 unlock_user_struct(rt_act, arg3, 1);
8169 }
8170#else
pbrook53a59602006-03-25 19:31:22 +00008171 struct target_sigaction *act;
8172 struct target_sigaction *oact;
8173
Peter Maydellc8157012016-06-30 14:23:24 +01008174 if (arg4 != sizeof(target_sigset_t)) {
8175 ret = -TARGET_EINVAL;
8176 break;
8177 }
bellard579a97f2007-11-11 14:26:47 +00008178 if (arg2) {
8179 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
8180 goto efault;
8181 } else
pbrook53a59602006-03-25 19:31:22 +00008182 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00008183 if (arg3) {
8184 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8185 ret = -TARGET_EFAULT;
8186 goto rt_sigaction_fail;
8187 }
8188 } else
pbrook53a59602006-03-25 19:31:22 +00008189 oact = NULL;
8190 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008191 rt_sigaction_fail:
8192 if (act)
pbrook53a59602006-03-25 19:31:22 +00008193 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008194 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008195 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008196#endif
pbrook53a59602006-03-25 19:31:22 +00008197 }
bellard66fb9762003-03-23 01:06:05 +00008198 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008199#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008200 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008201 {
8202 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008203 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008204 ret = do_sigprocmask(0, NULL, &cur_set);
8205 if (!ret) {
8206 host_to_target_old_sigset(&target_set, &cur_set);
8207 ret = target_set;
8208 }
bellard66fb9762003-03-23 01:06:05 +00008209 }
8210 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008211#endif
8212#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008213 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008214 {
8215 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008216 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008217 /* We only have one word of the new mask so we must read
8218 * the rest of it with do_sigprocmask() and OR in this word.
8219 * We are guaranteed that a do_sigprocmask() that only queries
8220 * the signal mask will not fail.
8221 */
8222 ret = do_sigprocmask(0, NULL, &cur_set);
8223 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00008224 target_to_host_old_sigset(&set, &target_set);
8225 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008226 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8227 if (!ret) {
8228 host_to_target_old_sigset(&target_set, &oset);
8229 ret = target_set;
8230 }
bellard66fb9762003-03-23 01:06:05 +00008231 }
8232 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008233#endif
thse5febef2007-04-01 18:31:35 +00008234#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008235 case TARGET_NR_sigprocmask:
8236 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008237#if defined(TARGET_ALPHA)
8238 sigset_t set, oldset;
8239 abi_ulong mask;
8240 int how;
8241
8242 switch (arg1) {
8243 case TARGET_SIG_BLOCK:
8244 how = SIG_BLOCK;
8245 break;
8246 case TARGET_SIG_UNBLOCK:
8247 how = SIG_UNBLOCK;
8248 break;
8249 case TARGET_SIG_SETMASK:
8250 how = SIG_SETMASK;
8251 break;
8252 default:
8253 ret = -TARGET_EINVAL;
8254 goto fail;
8255 }
8256 mask = arg2;
8257 target_to_host_old_sigset(&set, &mask);
8258
Peter Maydell3d3efba2016-05-27 15:51:49 +01008259 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008260 if (!is_error(ret)) {
8261 host_to_target_old_sigset(&mask, &oldset);
8262 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008263 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008264 }
8265#else
bellard66fb9762003-03-23 01:06:05 +00008266 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008267 int how;
ths3b46e622007-09-17 08:09:54 +00008268
pbrook53a59602006-03-25 19:31:22 +00008269 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008270 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008271 case TARGET_SIG_BLOCK:
8272 how = SIG_BLOCK;
8273 break;
8274 case TARGET_SIG_UNBLOCK:
8275 how = SIG_UNBLOCK;
8276 break;
8277 case TARGET_SIG_SETMASK:
8278 how = SIG_SETMASK;
8279 break;
8280 default:
ths0da46a62007-10-20 20:23:07 +00008281 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008282 goto fail;
8283 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008284 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008285 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008286 target_to_host_old_sigset(&set, p);
8287 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008288 set_ptr = &set;
8289 } else {
8290 how = 0;
8291 set_ptr = NULL;
8292 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008293 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008294 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008295 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008296 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008297 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008298 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008299 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008300#endif
bellard66fb9762003-03-23 01:06:05 +00008301 }
8302 break;
thse5febef2007-04-01 18:31:35 +00008303#endif
bellard66fb9762003-03-23 01:06:05 +00008304 case TARGET_NR_rt_sigprocmask:
8305 {
8306 int how = arg1;
8307 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008308
Peter Maydellc8157012016-06-30 14:23:24 +01008309 if (arg4 != sizeof(target_sigset_t)) {
8310 ret = -TARGET_EINVAL;
8311 break;
8312 }
8313
pbrook53a59602006-03-25 19:31:22 +00008314 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008315 switch(how) {
8316 case TARGET_SIG_BLOCK:
8317 how = SIG_BLOCK;
8318 break;
8319 case TARGET_SIG_UNBLOCK:
8320 how = SIG_UNBLOCK;
8321 break;
8322 case TARGET_SIG_SETMASK:
8323 how = SIG_SETMASK;
8324 break;
8325 default:
ths0da46a62007-10-20 20:23:07 +00008326 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008327 goto fail;
8328 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008329 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008330 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008331 target_to_host_sigset(&set, p);
8332 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008333 set_ptr = &set;
8334 } else {
8335 how = 0;
8336 set_ptr = NULL;
8337 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008338 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008339 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008340 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008341 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008342 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008343 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008344 }
8345 }
8346 break;
thse5febef2007-04-01 18:31:35 +00008347#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008348 case TARGET_NR_sigpending:
8349 {
8350 sigset_t set;
8351 ret = get_errno(sigpending(&set));
8352 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008353 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008354 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008355 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008356 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008357 }
8358 }
8359 break;
thse5febef2007-04-01 18:31:35 +00008360#endif
bellard66fb9762003-03-23 01:06:05 +00008361 case TARGET_NR_rt_sigpending:
8362 {
8363 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008364
8365 /* Yes, this check is >, not != like most. We follow the kernel's
8366 * logic and it does it like this because it implements
8367 * NR_sigpending through the same code path, and in that case
8368 * the old_sigset_t is smaller in size.
8369 */
8370 if (arg2 > sizeof(target_sigset_t)) {
8371 ret = -TARGET_EINVAL;
8372 break;
8373 }
8374
bellard66fb9762003-03-23 01:06:05 +00008375 ret = get_errno(sigpending(&set));
8376 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008377 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008378 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008379 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008380 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008381 }
8382 }
8383 break;
thse5febef2007-04-01 18:31:35 +00008384#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008385 case TARGET_NR_sigsuspend:
8386 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008387 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008388#if defined(TARGET_ALPHA)
8389 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008390 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008391#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008392 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008393 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008394 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008395 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008396#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008397 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8398 SIGSET_T_SIZE));
8399 if (ret != -TARGET_ERESTARTSYS) {
8400 ts->in_sigsuspend = 1;
8401 }
bellard66fb9762003-03-23 01:06:05 +00008402 }
8403 break;
thse5febef2007-04-01 18:31:35 +00008404#endif
bellard66fb9762003-03-23 01:06:05 +00008405 case TARGET_NR_rt_sigsuspend:
8406 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008407 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008408
8409 if (arg2 != sizeof(target_sigset_t)) {
8410 ret = -TARGET_EINVAL;
8411 break;
8412 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008413 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008414 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008415 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008416 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008417 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8418 SIGSET_T_SIZE));
8419 if (ret != -TARGET_ERESTARTSYS) {
8420 ts->in_sigsuspend = 1;
8421 }
bellard66fb9762003-03-23 01:06:05 +00008422 }
8423 break;
8424 case TARGET_NR_rt_sigtimedwait:
8425 {
bellard66fb9762003-03-23 01:06:05 +00008426 sigset_t set;
8427 struct timespec uts, *puts;
8428 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008429
Peter Maydellc8157012016-06-30 14:23:24 +01008430 if (arg4 != sizeof(target_sigset_t)) {
8431 ret = -TARGET_EINVAL;
8432 break;
8433 }
8434
Anthony Liguoric227f092009-10-01 16:12:16 -05008435 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008436 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008437 target_to_host_sigset(&set, p);
8438 unlock_user(p, arg1, 0);
8439 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008440 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008441 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008442 } else {
8443 puts = NULL;
8444 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008445 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8446 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008447 if (!is_error(ret)) {
8448 if (arg2) {
8449 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8450 0);
8451 if (!p) {
8452 goto efault;
8453 }
8454 host_to_target_siginfo(p, &uinfo);
8455 unlock_user(p, arg2, sizeof(target_siginfo_t));
8456 }
8457 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008458 }
8459 }
8460 break;
8461 case TARGET_NR_rt_sigqueueinfo:
8462 {
8463 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01008464
8465 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
8466 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00008467 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01008468 }
pbrook53a59602006-03-25 19:31:22 +00008469 target_to_host_siginfo(&uinfo, p);
8470 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00008471 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
8472 }
8473 break;
thse5febef2007-04-01 18:31:35 +00008474#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00008475 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008476 if (block_signals()) {
8477 ret = -TARGET_ERESTARTSYS;
8478 } else {
8479 ret = do_sigreturn(cpu_env);
8480 }
bellard66fb9762003-03-23 01:06:05 +00008481 break;
thse5febef2007-04-01 18:31:35 +00008482#endif
bellard66fb9762003-03-23 01:06:05 +00008483 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008484 if (block_signals()) {
8485 ret = -TARGET_ERESTARTSYS;
8486 } else {
8487 ret = do_rt_sigreturn(cpu_env);
8488 }
bellard66fb9762003-03-23 01:06:05 +00008489 break;
bellard31e31b82003-02-18 22:55:36 +00008490 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00008491 if (!(p = lock_user_string(arg1)))
8492 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008493 ret = get_errno(sethostname(p, arg2));
8494 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008495 break;
8496 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00008497 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008498 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008499 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008500 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00008501 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
8502 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008503 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
8504 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008505 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00008506 ret = get_errno(setrlimit(resource, &rlim));
8507 }
8508 break;
bellard31e31b82003-02-18 22:55:36 +00008509 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00008510 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008511 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008512 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008513 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008514
bellard9de5e442003-03-23 16:49:39 +00008515 ret = get_errno(getrlimit(resource, &rlim));
8516 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008517 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8518 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008519 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8520 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008521 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008522 }
8523 }
8524 break;
bellard31e31b82003-02-18 22:55:36 +00008525 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008526 {
8527 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008528 ret = get_errno(getrusage(arg1, &rusage));
8529 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008530 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008531 }
8532 }
8533 break;
bellard31e31b82003-02-18 22:55:36 +00008534 case TARGET_NR_gettimeofday:
8535 {
bellard31e31b82003-02-18 22:55:36 +00008536 struct timeval tv;
8537 ret = get_errno(gettimeofday(&tv, NULL));
8538 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008539 if (copy_to_user_timeval(arg1, &tv))
8540 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008541 }
8542 }
8543 break;
8544 case TARGET_NR_settimeofday:
8545 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008546 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008547 struct timezone tz, *ptz = NULL;
8548
Paul Burtonb67d8032014-06-22 11:25:41 +01008549 if (arg1) {
8550 if (copy_from_user_timeval(&tv, arg1)) {
8551 goto efault;
8552 }
8553 ptv = &tv;
8554 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008555
8556 if (arg2) {
8557 if (copy_from_user_timezone(&tz, arg2)) {
8558 goto efault;
8559 }
8560 ptz = &tz;
8561 }
8562
Paul Burtonb67d8032014-06-22 11:25:41 +01008563 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008564 }
8565 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008566#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008567 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008568#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
8569 ret = do_select(arg1, arg2, arg3, arg4, arg5);
8570#else
bellardf2674e32003-07-09 12:26:09 +00008571 {
pbrook53a59602006-03-25 19:31:22 +00008572 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00008573 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00008574 long nsel;
8575
bellard579a97f2007-11-11 14:26:47 +00008576 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
8577 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008578 nsel = tswapal(sel->n);
8579 inp = tswapal(sel->inp);
8580 outp = tswapal(sel->outp);
8581 exp = tswapal(sel->exp);
8582 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00008583 unlock_user_struct(sel, arg1, 0);
8584 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00008585 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008586#endif
bellardf2674e32003-07-09 12:26:09 +00008587 break;
bellard048f6b42005-11-26 18:47:20 +00008588#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008589#ifdef TARGET_NR_pselect6
8590 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008591 {
8592 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8593 fd_set rfds, wfds, efds;
8594 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8595 struct timespec ts, *ts_ptr;
8596
8597 /*
8598 * The 6th arg is actually two args smashed together,
8599 * so we cannot use the C library.
8600 */
8601 sigset_t set;
8602 struct {
8603 sigset_t *set;
8604 size_t size;
8605 } sig, *sig_ptr;
8606
8607 abi_ulong arg_sigset, arg_sigsize, *arg7;
8608 target_sigset_t *target_sigset;
8609
8610 n = arg1;
8611 rfd_addr = arg2;
8612 wfd_addr = arg3;
8613 efd_addr = arg4;
8614 ts_addr = arg5;
8615
8616 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8617 if (ret) {
8618 goto fail;
8619 }
8620 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8621 if (ret) {
8622 goto fail;
8623 }
8624 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8625 if (ret) {
8626 goto fail;
8627 }
8628
8629 /*
8630 * This takes a timespec, and not a timeval, so we cannot
8631 * use the do_select() helper ...
8632 */
8633 if (ts_addr) {
8634 if (target_to_host_timespec(&ts, ts_addr)) {
8635 goto efault;
8636 }
8637 ts_ptr = &ts;
8638 } else {
8639 ts_ptr = NULL;
8640 }
8641
8642 /* Extract the two packed args for the sigset */
8643 if (arg6) {
8644 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008645 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008646
8647 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8648 if (!arg7) {
8649 goto efault;
8650 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008651 arg_sigset = tswapal(arg7[0]);
8652 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008653 unlock_user(arg7, arg6, 0);
8654
8655 if (arg_sigset) {
8656 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008657 if (arg_sigsize != sizeof(*target_sigset)) {
8658 /* Like the kernel, we enforce correct size sigsets */
8659 ret = -TARGET_EINVAL;
8660 goto fail;
8661 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008662 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8663 sizeof(*target_sigset), 1);
8664 if (!target_sigset) {
8665 goto efault;
8666 }
8667 target_to_host_sigset(&set, target_sigset);
8668 unlock_user(target_sigset, arg_sigset, 0);
8669 } else {
8670 sig.set = NULL;
8671 }
8672 } else {
8673 sig_ptr = NULL;
8674 }
8675
Peter Maydell6df9d382016-05-12 18:47:51 +01008676 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8677 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008678
8679 if (!is_error(ret)) {
8680 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8681 goto efault;
8682 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8683 goto efault;
8684 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8685 goto efault;
8686
8687 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8688 goto efault;
8689 }
8690 }
8691 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008692#endif
Chen Gang704eff62015-08-21 05:37:33 +08008693#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008694 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008695 {
8696 void *p2;
8697 p = lock_user_string(arg1);
8698 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008699 if (!p || !p2)
8700 ret = -TARGET_EFAULT;
8701 else
8702 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008703 unlock_user(p2, arg2, 0);
8704 unlock_user(p, arg1, 0);
8705 }
bellard31e31b82003-02-18 22:55:36 +00008706 break;
Chen Gang704eff62015-08-21 05:37:33 +08008707#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008708#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008709 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008710 {
bellard579a97f2007-11-11 14:26:47 +00008711 void *p2;
thsf0b62432007-09-24 09:25:40 +00008712 p = lock_user_string(arg1);
8713 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008714 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008715 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008716 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008717 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008718 unlock_user(p2, arg3, 0);
8719 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008720 }
8721 break;
8722#endif
bellardebc05482003-09-30 21:08:41 +00008723#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008724 case TARGET_NR_oldlstat:
8725 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008726#endif
Chen Gang704eff62015-08-21 05:37:33 +08008727#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008728 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008729 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008730 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008731 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008732 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008733 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008734 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008735 } else if (!arg3) {
8736 /* Short circuit this for the magic exe check. */
8737 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008738 } else if (is_proc_myself((const char *)p, "exe")) {
8739 char real[PATH_MAX], *temp;
8740 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008741 /* Return value is # of bytes that we wrote to the buffer. */
8742 if (temp == NULL) {
8743 ret = get_errno(-1);
8744 } else {
8745 /* Don't worry about sign mismatch as earlier mapping
8746 * logic would have thrown a bad address error. */
8747 ret = MIN(strlen(real), arg3);
8748 /* We cannot NUL terminate the string. */
8749 memcpy(p2, real, ret);
8750 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008751 } else {
8752 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008753 }
pbrook53a59602006-03-25 19:31:22 +00008754 unlock_user(p2, arg2, ret);
8755 unlock_user(p, arg1, 0);
8756 }
bellard31e31b82003-02-18 22:55:36 +00008757 break;
Chen Gang704eff62015-08-21 05:37:33 +08008758#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008759#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008760 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008761 {
bellard579a97f2007-11-11 14:26:47 +00008762 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008763 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008764 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008765 if (!p || !p2) {
8766 ret = -TARGET_EFAULT;
8767 } else if (is_proc_myself((const char *)p, "exe")) {
8768 char real[PATH_MAX], *temp;
8769 temp = realpath(exec_path, real);
8770 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8771 snprintf((char *)p2, arg4, "%s", real);
8772 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008773 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008774 }
bellard579a97f2007-11-11 14:26:47 +00008775 unlock_user(p2, arg3, ret);
8776 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008777 }
8778 break;
8779#endif
thse5febef2007-04-01 18:31:35 +00008780#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008781 case TARGET_NR_uselib:
8782 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008783#endif
8784#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008785 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008786 if (!(p = lock_user_string(arg1)))
8787 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008788 ret = get_errno(swapon(p, arg2));
8789 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008790 break;
thse5febef2007-04-01 18:31:35 +00008791#endif
bellard31e31b82003-02-18 22:55:36 +00008792 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008793 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8794 /* arg4 must be ignored in all other cases */
8795 p = lock_user_string(arg4);
8796 if (!p) {
8797 goto efault;
8798 }
8799 ret = get_errno(reboot(arg1, arg2, arg3, p));
8800 unlock_user(p, arg4, 0);
8801 } else {
8802 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8803 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008804 break;
thse5febef2007-04-01 18:31:35 +00008805#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008806 case TARGET_NR_readdir:
8807 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008808#endif
8809#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008810 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008811#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8812 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008813 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8814 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008815 {
blueswir1992f48a2007-10-14 16:27:31 +00008816 abi_ulong *v;
8817 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008818 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8819 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008820 v1 = tswapal(v[0]);
8821 v2 = tswapal(v[1]);
8822 v3 = tswapal(v[2]);
8823 v4 = tswapal(v[3]);
8824 v5 = tswapal(v[4]);
8825 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008826 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008827 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008828 target_to_host_bitmask(v4, mmap_flags_tbl),
8829 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008830 }
bellard31e31b82003-02-18 22:55:36 +00008831#else
ths5fafdf22007-09-16 21:08:06 +00008832 ret = get_errno(target_mmap(arg1, arg2, arg3,
8833 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008834 arg5,
8835 arg6));
bellard31e31b82003-02-18 22:55:36 +00008836#endif
bellard6fb883e2003-07-09 17:12:39 +00008837 break;
thse5febef2007-04-01 18:31:35 +00008838#endif
bellarda315a142005-01-30 22:59:18 +00008839#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008840 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008841#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008842#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008843#endif
ths5fafdf22007-09-16 21:08:06 +00008844 ret = get_errno(target_mmap(arg1, arg2, arg3,
8845 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008846 arg5,
bellardc573ff62004-01-04 15:51:36 +00008847 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008848 break;
bellarda315a142005-01-30 22:59:18 +00008849#endif
bellard31e31b82003-02-18 22:55:36 +00008850 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008851 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008852 break;
bellard9de5e442003-03-23 16:49:39 +00008853 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008854 {
Andreas Färber0429a972013-08-26 18:14:44 +02008855 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008856 /* Special hack to detect libc making the stack executable. */
8857 if ((arg3 & PROT_GROWSDOWN)
8858 && arg1 >= ts->info->stack_limit
8859 && arg1 <= ts->info->start_stack) {
8860 arg3 &= ~PROT_GROWSDOWN;
8861 arg2 = arg2 + arg1 - ts->info->stack_limit;
8862 arg1 = ts->info->stack_limit;
8863 }
8864 }
bellard54936002003-05-13 00:25:15 +00008865 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008866 break;
thse5febef2007-04-01 18:31:35 +00008867#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008868 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008869 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008870 break;
thse5febef2007-04-01 18:31:35 +00008871#endif
pbrook53a59602006-03-25 19:31:22 +00008872 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008873#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008874 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008875 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008876 break;
thse5febef2007-04-01 18:31:35 +00008877#endif
8878#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008879 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008880 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008881 break;
thse5febef2007-04-01 18:31:35 +00008882#endif
8883#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008884 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008885 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008886 break;
thse5febef2007-04-01 18:31:35 +00008887#endif
8888#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008889 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008890 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008891 break;
thse5febef2007-04-01 18:31:35 +00008892#endif
8893#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008894 case TARGET_NR_munlockall:
8895 ret = get_errno(munlockall());
8896 break;
thse5febef2007-04-01 18:31:35 +00008897#endif
bellard31e31b82003-02-18 22:55:36 +00008898 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008899 if (!(p = lock_user_string(arg1)))
8900 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008901 ret = get_errno(truncate(p, arg2));
8902 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008903 break;
8904 case TARGET_NR_ftruncate:
8905 ret = get_errno(ftruncate(arg1, arg2));
8906 break;
8907 case TARGET_NR_fchmod:
8908 ret = get_errno(fchmod(arg1, arg2));
8909 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008910#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008911 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008912 if (!(p = lock_user_string(arg2)))
8913 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008914 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008915 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008916 break;
8917#endif
bellard31e31b82003-02-18 22:55:36 +00008918 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008919 /* Note that negative values are valid for getpriority, so we must
8920 differentiate based on errno settings. */
8921 errno = 0;
8922 ret = getpriority(arg1, arg2);
8923 if (ret == -1 && errno != 0) {
8924 ret = -host_to_target_errno(errno);
8925 break;
8926 }
8927#ifdef TARGET_ALPHA
8928 /* Return value is the unbiased priority. Signal no error. */
8929 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8930#else
8931 /* Return value is a biased priority to avoid negative numbers. */
8932 ret = 20 - ret;
8933#endif
bellard31e31b82003-02-18 22:55:36 +00008934 break;
8935 case TARGET_NR_setpriority:
8936 ret = get_errno(setpriority(arg1, arg2, arg3));
8937 break;
bellardebc05482003-09-30 21:08:41 +00008938#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008939 case TARGET_NR_profil:
8940 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008941#endif
bellard31e31b82003-02-18 22:55:36 +00008942 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008943 if (!(p = lock_user_string(arg1)))
8944 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008945 ret = get_errno(statfs(path(p), &stfs));
8946 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008947 convert_statfs:
8948 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008949 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008950
bellard579a97f2007-11-11 14:26:47 +00008951 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8952 goto efault;
8953 __put_user(stfs.f_type, &target_stfs->f_type);
8954 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8955 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8956 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8957 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8958 __put_user(stfs.f_files, &target_stfs->f_files);
8959 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8960 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8961 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8962 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008963 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8964 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008965 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008966 }
8967 break;
8968 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008969 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008970 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008971#ifdef TARGET_NR_statfs64
8972 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008973 if (!(p = lock_user_string(arg1)))
8974 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008975 ret = get_errno(statfs(path(p), &stfs));
8976 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008977 convert_statfs64:
8978 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008979 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008980
bellard579a97f2007-11-11 14:26:47 +00008981 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8982 goto efault;
8983 __put_user(stfs.f_type, &target_stfs->f_type);
8984 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8985 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8986 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8987 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8988 __put_user(stfs.f_files, &target_stfs->f_files);
8989 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8990 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8991 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8992 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008993 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8994 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008995 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008996 }
8997 break;
8998 case TARGET_NR_fstatfs64:
8999 ret = get_errno(fstatfs(arg1, &stfs));
9000 goto convert_statfs64;
9001#endif
bellardebc05482003-09-30 21:08:41 +00009002#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009003 case TARGET_NR_ioperm:
9004 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009005#endif
thse5febef2007-04-01 18:31:35 +00009006#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009007 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009008 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009009 break;
thse5febef2007-04-01 18:31:35 +00009010#endif
bellard3532fa72006-06-24 15:06:03 +00009011#ifdef TARGET_NR_accept
9012 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009013 ret = do_accept4(arg1, arg2, arg3, 0);
9014 break;
9015#endif
9016#ifdef TARGET_NR_accept4
9017 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009018 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009019 break;
9020#endif
9021#ifdef TARGET_NR_bind
9022 case TARGET_NR_bind:
9023 ret = do_bind(arg1, arg2, arg3);
9024 break;
9025#endif
9026#ifdef TARGET_NR_connect
9027 case TARGET_NR_connect:
9028 ret = do_connect(arg1, arg2, arg3);
9029 break;
9030#endif
9031#ifdef TARGET_NR_getpeername
9032 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009033 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009034 break;
9035#endif
9036#ifdef TARGET_NR_getsockname
9037 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009038 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009039 break;
9040#endif
9041#ifdef TARGET_NR_getsockopt
9042 case TARGET_NR_getsockopt:
9043 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9044 break;
9045#endif
9046#ifdef TARGET_NR_listen
9047 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009048 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009049 break;
9050#endif
9051#ifdef TARGET_NR_recv
9052 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009053 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009054 break;
9055#endif
9056#ifdef TARGET_NR_recvfrom
9057 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009058 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009059 break;
9060#endif
9061#ifdef TARGET_NR_recvmsg
9062 case TARGET_NR_recvmsg:
9063 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9064 break;
9065#endif
9066#ifdef TARGET_NR_send
9067 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009068 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009069 break;
9070#endif
9071#ifdef TARGET_NR_sendmsg
9072 case TARGET_NR_sendmsg:
9073 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9074 break;
9075#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009076#ifdef TARGET_NR_sendmmsg
9077 case TARGET_NR_sendmmsg:
9078 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9079 break;
9080 case TARGET_NR_recvmmsg:
9081 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9082 break;
9083#endif
bellard3532fa72006-06-24 15:06:03 +00009084#ifdef TARGET_NR_sendto
9085 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009086 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009087 break;
9088#endif
9089#ifdef TARGET_NR_shutdown
9090 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009091 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009092 break;
9093#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009094#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9095 case TARGET_NR_getrandom:
9096 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9097 if (!p) {
9098 goto efault;
9099 }
9100 ret = get_errno(getrandom(p, arg2, arg3));
9101 unlock_user(p, arg1, ret);
9102 break;
9103#endif
bellard3532fa72006-06-24 15:06:03 +00009104#ifdef TARGET_NR_socket
9105 case TARGET_NR_socket:
9106 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02009107 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00009108 break;
9109#endif
9110#ifdef TARGET_NR_socketpair
9111 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009112 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009113 break;
9114#endif
9115#ifdef TARGET_NR_setsockopt
9116 case TARGET_NR_setsockopt:
9117 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9118 break;
9119#endif
ths7494b0f2007-02-11 18:26:53 +00009120
bellard31e31b82003-02-18 22:55:36 +00009121 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00009122 if (!(p = lock_user_string(arg2)))
9123 goto efault;
thse5574482007-02-11 20:03:13 +00009124 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9125 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00009126 break;
9127
bellard31e31b82003-02-18 22:55:36 +00009128 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009129 {
bellard66fb9762003-03-23 01:06:05 +00009130 struct itimerval value, ovalue, *pvalue;
9131
pbrook53a59602006-03-25 19:31:22 +00009132 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009133 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009134 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9135 || copy_from_user_timeval(&pvalue->it_value,
9136 arg2 + sizeof(struct target_timeval)))
9137 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009138 } else {
9139 pvalue = NULL;
9140 }
9141 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009142 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009143 if (copy_to_user_timeval(arg3,
9144 &ovalue.it_interval)
9145 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9146 &ovalue.it_value))
9147 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009148 }
9149 }
9150 break;
bellard31e31b82003-02-18 22:55:36 +00009151 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009152 {
bellard66fb9762003-03-23 01:06:05 +00009153 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009154
bellard66fb9762003-03-23 01:06:05 +00009155 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009156 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009157 if (copy_to_user_timeval(arg2,
9158 &value.it_interval)
9159 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9160 &value.it_value))
9161 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009162 }
9163 }
9164 break;
Chen Gang704eff62015-08-21 05:37:33 +08009165#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009166 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009167 if (!(p = lock_user_string(arg1)))
9168 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009169 ret = get_errno(stat(path(p), &st));
9170 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009171 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009172#endif
9173#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009174 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009175 if (!(p = lock_user_string(arg1)))
9176 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009177 ret = get_errno(lstat(path(p), &st));
9178 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009179 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009180#endif
bellard31e31b82003-02-18 22:55:36 +00009181 case TARGET_NR_fstat:
9182 {
9183 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009184#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009185 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009186#endif
bellard31e31b82003-02-18 22:55:36 +00009187 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009188 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009189
bellard579a97f2007-11-11 14:26:47 +00009190 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9191 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009192 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009193 __put_user(st.st_dev, &target_st->st_dev);
9194 __put_user(st.st_ino, &target_st->st_ino);
9195 __put_user(st.st_mode, &target_st->st_mode);
9196 __put_user(st.st_uid, &target_st->st_uid);
9197 __put_user(st.st_gid, &target_st->st_gid);
9198 __put_user(st.st_nlink, &target_st->st_nlink);
9199 __put_user(st.st_rdev, &target_st->st_rdev);
9200 __put_user(st.st_size, &target_st->st_size);
9201 __put_user(st.st_blksize, &target_st->st_blksize);
9202 __put_user(st.st_blocks, &target_st->st_blocks);
9203 __put_user(st.st_atime, &target_st->target_st_atime);
9204 __put_user(st.st_mtime, &target_st->target_st_mtime);
9205 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009206 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009207 }
9208 }
9209 break;
bellardebc05482003-09-30 21:08:41 +00009210#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009211 case TARGET_NR_olduname:
9212 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009213#endif
9214#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009215 case TARGET_NR_iopl:
9216 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009217#endif
bellard31e31b82003-02-18 22:55:36 +00009218 case TARGET_NR_vhangup:
9219 ret = get_errno(vhangup());
9220 break;
bellardebc05482003-09-30 21:08:41 +00009221#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009222 case TARGET_NR_idle:
9223 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009224#endif
bellard42ad6ae2005-01-03 22:48:11 +00009225#ifdef TARGET_NR_syscall
9226 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009227 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9228 arg6, arg7, arg8, 0);
9229 break;
bellard42ad6ae2005-01-03 22:48:11 +00009230#endif
bellard31e31b82003-02-18 22:55:36 +00009231 case TARGET_NR_wait4:
9232 {
9233 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009234 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009235 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009236 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009237 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009238 if (target_rusage)
9239 rusage_ptr = &rusage;
9240 else
9241 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009242 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009243 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009244 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009245 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009246 if (put_user_s32(status, status_ptr))
9247 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009248 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009249 if (target_rusage) {
9250 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9251 if (rusage_err) {
9252 ret = rusage_err;
9253 }
9254 }
bellard31e31b82003-02-18 22:55:36 +00009255 }
9256 }
9257 break;
thse5febef2007-04-01 18:31:35 +00009258#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009259 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009260 if (!(p = lock_user_string(arg1)))
9261 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009262 ret = get_errno(swapoff(p));
9263 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009264 break;
thse5febef2007-04-01 18:31:35 +00009265#endif
bellard31e31b82003-02-18 22:55:36 +00009266 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009267 {
pbrook53a59602006-03-25 19:31:22 +00009268 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009269 struct sysinfo value;
9270 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009271 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009272 {
bellard579a97f2007-11-11 14:26:47 +00009273 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9274 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009275 __put_user(value.uptime, &target_value->uptime);
9276 __put_user(value.loads[0], &target_value->loads[0]);
9277 __put_user(value.loads[1], &target_value->loads[1]);
9278 __put_user(value.loads[2], &target_value->loads[2]);
9279 __put_user(value.totalram, &target_value->totalram);
9280 __put_user(value.freeram, &target_value->freeram);
9281 __put_user(value.sharedram, &target_value->sharedram);
9282 __put_user(value.bufferram, &target_value->bufferram);
9283 __put_user(value.totalswap, &target_value->totalswap);
9284 __put_user(value.freeswap, &target_value->freeswap);
9285 __put_user(value.procs, &target_value->procs);
9286 __put_user(value.totalhigh, &target_value->totalhigh);
9287 __put_user(value.freehigh, &target_value->freehigh);
9288 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009289 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009290 }
9291 }
9292 break;
thse5febef2007-04-01 18:31:35 +00009293#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009294 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00009295 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
9296 break;
thse5febef2007-04-01 18:31:35 +00009297#endif
aurel32e5289082009-04-18 16:16:12 +00009298#ifdef TARGET_NR_semget
9299 case TARGET_NR_semget:
9300 ret = get_errno(semget(arg1, arg2, arg3));
9301 break;
9302#endif
9303#ifdef TARGET_NR_semop
9304 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009305 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009306 break;
9307#endif
9308#ifdef TARGET_NR_semctl
9309 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009310 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009311 break;
9312#endif
aurel32eeb438c2008-10-13 21:08:55 +00009313#ifdef TARGET_NR_msgctl
9314 case TARGET_NR_msgctl:
9315 ret = do_msgctl(arg1, arg2, arg3);
9316 break;
9317#endif
9318#ifdef TARGET_NR_msgget
9319 case TARGET_NR_msgget:
9320 ret = get_errno(msgget(arg1, arg2));
9321 break;
9322#endif
9323#ifdef TARGET_NR_msgrcv
9324 case TARGET_NR_msgrcv:
9325 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9326 break;
9327#endif
9328#ifdef TARGET_NR_msgsnd
9329 case TARGET_NR_msgsnd:
9330 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9331 break;
9332#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009333#ifdef TARGET_NR_shmget
9334 case TARGET_NR_shmget:
9335 ret = get_errno(shmget(arg1, arg2, arg3));
9336 break;
9337#endif
9338#ifdef TARGET_NR_shmctl
9339 case TARGET_NR_shmctl:
9340 ret = do_shmctl(arg1, arg2, arg3);
9341 break;
9342#endif
9343#ifdef TARGET_NR_shmat
9344 case TARGET_NR_shmat:
9345 ret = do_shmat(arg1, arg2, arg3);
9346 break;
9347#endif
9348#ifdef TARGET_NR_shmdt
9349 case TARGET_NR_shmdt:
9350 ret = do_shmdt(arg1);
9351 break;
9352#endif
bellard31e31b82003-02-18 22:55:36 +00009353 case TARGET_NR_fsync:
9354 ret = get_errno(fsync(arg1));
9355 break;
bellard31e31b82003-02-18 22:55:36 +00009356 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009357 /* Linux manages to have three different orderings for its
9358 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9359 * match the kernel's CONFIG_CLONE_* settings.
9360 * Microblaze is further special in that it uses a sixth
9361 * implicit argument to clone for the TLS pointer.
9362 */
9363#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009364 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009365#elif defined(TARGET_CLONE_BACKWARDS)
9366 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9367#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009368 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009369#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009370 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009371#endif
bellard1b6b0292003-03-22 17:31:38 +00009372 break;
bellardec86b0f2003-04-11 00:15:04 +00009373#ifdef __NR_exit_group
9374 /* new thread calls */
9375 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02009376#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00009377 _mcleanup();
9378#endif
bellarde9009672005-04-26 20:42:36 +00009379 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00009380 ret = get_errno(exit_group(arg1));
9381 break;
9382#endif
bellard31e31b82003-02-18 22:55:36 +00009383 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009384 if (!(p = lock_user_string(arg1)))
9385 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009386 ret = get_errno(setdomainname(p, arg2));
9387 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009388 break;
9389 case TARGET_NR_uname:
9390 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009391 {
9392 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009393
bellard579a97f2007-11-11 14:26:47 +00009394 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
9395 goto efault;
bellard29e619b2004-09-13 21:41:04 +00009396 ret = get_errno(sys_uname(buf));
9397 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009398 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009399 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01009400 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00009401 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009402 if (qemu_uname_release && *qemu_uname_release) {
9403 g_strlcpy(buf->release, qemu_uname_release,
9404 sizeof(buf->release));
9405 }
bellard29e619b2004-09-13 21:41:04 +00009406 }
pbrook53a59602006-03-25 19:31:22 +00009407 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009408 }
bellard31e31b82003-02-18 22:55:36 +00009409 break;
bellard6dbad632003-03-16 18:05:05 +00009410#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009411 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00009412 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00009413 break;
j_mayer84409dd2007-04-06 08:56:50 +00009414#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009415 case TARGET_NR_vm86old:
9416 goto unimplemented;
9417 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00009418 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009419 break;
9420#endif
j_mayer84409dd2007-04-06 08:56:50 +00009421#endif
bellard31e31b82003-02-18 22:55:36 +00009422 case TARGET_NR_adjtimex:
9423 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009424#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00009425 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00009426#endif
bellard31e31b82003-02-18 22:55:36 +00009427 case TARGET_NR_init_module:
9428 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00009429#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00009430 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00009431#endif
bellard31e31b82003-02-18 22:55:36 +00009432 goto unimplemented;
9433 case TARGET_NR_quotactl:
9434 goto unimplemented;
9435 case TARGET_NR_getpgid:
9436 ret = get_errno(getpgid(arg1));
9437 break;
9438 case TARGET_NR_fchdir:
9439 ret = get_errno(fchdir(arg1));
9440 break;
j_mayer84409dd2007-04-06 08:56:50 +00009441#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00009442 case TARGET_NR_bdflush:
9443 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00009444#endif
thse5febef2007-04-01 18:31:35 +00009445#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00009446 case TARGET_NR_sysfs:
9447 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009448#endif
bellard31e31b82003-02-18 22:55:36 +00009449 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00009450 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00009451 break;
thse5febef2007-04-01 18:31:35 +00009452#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00009453 case TARGET_NR_afs_syscall:
9454 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009455#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009456#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009457 case TARGET_NR__llseek:
9458 {
9459 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009460#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +01009461 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +00009462 if (res == -1) {
9463 ret = get_errno(res);
9464 } else {
9465 ret = 0;
9466 }
9467#else
bellard31e31b82003-02-18 22:55:36 +00009468 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00009469#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00009470 if ((ret == 0) && put_user_s64(res, arg4)) {
9471 goto efault;
9472 }
bellard31e31b82003-02-18 22:55:36 +00009473 }
9474 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009475#endif
Chen Gang704eff62015-08-21 05:37:33 +08009476#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00009477 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01009478#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02009479#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00009480 {
pbrook53a59602006-03-25 19:31:22 +00009481 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00009482 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009483 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00009484
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309485 dirp = g_try_malloc(count);
9486 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00009487 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00009488 goto fail;
9489 }
ths3b46e622007-09-17 08:09:54 +00009490
bellard4add45b2003-06-05 01:52:59 +00009491 ret = get_errno(sys_getdents(arg1, dirp, count));
9492 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009493 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00009494 struct target_dirent *tde;
9495 int len = ret;
9496 int reclen, treclen;
9497 int count1, tnamelen;
9498
9499 count1 = 0;
9500 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00009501 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9502 goto efault;
bellard4add45b2003-06-05 01:52:59 +00009503 tde = target_dirp;
9504 while (len > 0) {
9505 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009506 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
9507 assert(tnamelen >= 0);
9508 treclen = tnamelen + offsetof(struct target_dirent, d_name);
9509 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00009510 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009511 tde->d_ino = tswapal(de->d_ino);
9512 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009513 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009514 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009515 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009516 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009517 count1 += treclen;
9518 }
9519 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009520 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009521 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309522 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009523 }
9524#else
bellard31e31b82003-02-18 22:55:36 +00009525 {
aurel326556a832008-10-13 21:08:17 +00009526 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009527 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009528
bellard579a97f2007-11-11 14:26:47 +00009529 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9530 goto efault;
bellard72f03902003-02-18 23:33:18 +00009531 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009532 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009533 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00009534 int len = ret;
9535 int reclen;
9536 de = dirp;
9537 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009538 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009539 if (reclen > len)
9540 break;
bellard8083a3e2003-03-24 23:12:16 +00009541 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009542 tswapls(&de->d_ino);
9543 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009544 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009545 len -= reclen;
9546 }
9547 }
pbrook53a59602006-03-25 19:31:22 +00009548 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009549 }
bellard4add45b2003-06-05 01:52:59 +00009550#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009551#else
9552 /* Implement getdents in terms of getdents64 */
9553 {
9554 struct linux_dirent64 *dirp;
9555 abi_long count = arg3;
9556
9557 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9558 if (!dirp) {
9559 goto efault;
9560 }
9561 ret = get_errno(sys_getdents64(arg1, dirp, count));
9562 if (!is_error(ret)) {
9563 /* Convert the dirent64 structs to target dirent. We do this
9564 * in-place, since we can guarantee that a target_dirent is no
9565 * larger than a dirent64; however this means we have to be
9566 * careful to read everything before writing in the new format.
9567 */
9568 struct linux_dirent64 *de;
9569 struct target_dirent *tde;
9570 int len = ret;
9571 int tlen = 0;
9572
9573 de = dirp;
9574 tde = (struct target_dirent *)dirp;
9575 while (len > 0) {
9576 int namelen, treclen;
9577 int reclen = de->d_reclen;
9578 uint64_t ino = de->d_ino;
9579 int64_t off = de->d_off;
9580 uint8_t type = de->d_type;
9581
9582 namelen = strlen(de->d_name);
9583 treclen = offsetof(struct target_dirent, d_name)
9584 + namelen + 2;
9585 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9586
9587 memmove(tde->d_name, de->d_name, namelen + 1);
9588 tde->d_ino = tswapal(ino);
9589 tde->d_off = tswapal(off);
9590 tde->d_reclen = tswap16(treclen);
9591 /* The target_dirent type is in what was formerly a padding
9592 * byte at the end of the structure:
9593 */
9594 *(((char *)tde) + treclen - 1) = type;
9595
9596 de = (struct linux_dirent64 *)((char *)de + reclen);
9597 tde = (struct target_dirent *)((char *)tde + treclen);
9598 len -= reclen;
9599 tlen += treclen;
9600 }
9601 ret = tlen;
9602 }
9603 unlock_user(dirp, arg2, ret);
9604 }
9605#endif
bellard31e31b82003-02-18 22:55:36 +00009606 break;
Chen Gang704eff62015-08-21 05:37:33 +08009607#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009608#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009609 case TARGET_NR_getdents64:
9610 {
aurel326556a832008-10-13 21:08:17 +00009611 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009612 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009613 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9614 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009615 ret = get_errno(sys_getdents64(arg1, dirp, count));
9616 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009617 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009618 int len = ret;
9619 int reclen;
9620 de = dirp;
9621 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009622 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009623 if (reclen > len)
9624 break;
bellard8083a3e2003-03-24 23:12:16 +00009625 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009626 tswap64s((uint64_t *)&de->d_ino);
9627 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009628 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009629 len -= reclen;
9630 }
9631 }
pbrook53a59602006-03-25 19:31:22 +00009632 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009633 }
9634 break;
bellarda541f292004-04-12 20:39:29 +00009635#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009636#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009637 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009638 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009639 break;
thse5febef2007-04-01 18:31:35 +00009640#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009641#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9642# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009643 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009644# endif
9645# ifdef TARGET_NR_ppoll
9646 case TARGET_NR_ppoll:
9647# endif
bellard9de5e442003-03-23 16:49:39 +00009648 {
pbrook53a59602006-03-25 19:31:22 +00009649 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009650 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009651 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009652 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009653
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009654 pfd = NULL;
9655 target_pfd = NULL;
9656 if (nfds) {
9657 target_pfd = lock_user(VERIFY_WRITE, arg1,
9658 sizeof(struct target_pollfd) * nfds, 1);
9659 if (!target_pfd) {
9660 goto efault;
9661 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009662
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009663 pfd = alloca(sizeof(struct pollfd) * nfds);
9664 for (i = 0; i < nfds; i++) {
9665 pfd[i].fd = tswap32(target_pfd[i].fd);
9666 pfd[i].events = tswap16(target_pfd[i].events);
9667 }
bellard9de5e442003-03-23 16:49:39 +00009668 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009669
Peter Maydella6130232016-06-06 19:58:10 +01009670 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009671# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009672 case TARGET_NR_ppoll:
9673 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009674 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9675 target_sigset_t *target_set;
9676 sigset_t _set, *set = &_set;
9677
9678 if (arg3) {
9679 if (target_to_host_timespec(timeout_ts, arg3)) {
9680 unlock_user(target_pfd, arg1, 0);
9681 goto efault;
9682 }
9683 } else {
9684 timeout_ts = NULL;
9685 }
9686
9687 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +01009688 if (arg5 != sizeof(target_sigset_t)) {
9689 unlock_user(target_pfd, arg1, 0);
9690 ret = -TARGET_EINVAL;
9691 break;
9692 }
9693
Mike Frysingerd8035d42011-02-07 01:05:51 -05009694 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9695 if (!target_set) {
9696 unlock_user(target_pfd, arg1, 0);
9697 goto efault;
9698 }
9699 target_to_host_sigset(set, target_set);
9700 } else {
9701 set = NULL;
9702 }
9703
Peter Maydella6130232016-06-06 19:58:10 +01009704 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9705 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009706
9707 if (!is_error(ret) && arg3) {
9708 host_to_target_timespec(arg3, timeout_ts);
9709 }
9710 if (arg4) {
9711 unlock_user(target_set, arg4, 0);
9712 }
Peter Maydella6130232016-06-06 19:58:10 +01009713 break;
9714 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009715# endif
Peter Maydella6130232016-06-06 19:58:10 +01009716# ifdef TARGET_NR_poll
9717 case TARGET_NR_poll:
9718 {
9719 struct timespec ts, *pts;
9720
9721 if (arg3 >= 0) {
9722 /* Convert ms to secs, ns */
9723 ts.tv_sec = arg3 / 1000;
9724 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9725 pts = &ts;
9726 } else {
9727 /* -ve poll() timeout means "infinite" */
9728 pts = NULL;
9729 }
9730 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9731 break;
9732 }
9733# endif
9734 default:
9735 g_assert_not_reached();
9736 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009737
bellard9de5e442003-03-23 16:49:39 +00009738 if (!is_error(ret)) {
9739 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009740 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009741 }
9742 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009743 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009744 }
9745 break;
thse5febef2007-04-01 18:31:35 +00009746#endif
bellard31e31b82003-02-18 22:55:36 +00009747 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009748 /* NOTE: the flock constant seems to be the same for every
9749 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009750 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009751 break;
9752 case TARGET_NR_readv:
9753 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009754 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9755 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009756 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009757 unlock_iovec(vec, arg2, arg3, 1);
9758 } else {
9759 ret = -host_to_target_errno(errno);
9760 }
bellard31e31b82003-02-18 22:55:36 +00009761 }
9762 break;
9763 case TARGET_NR_writev:
9764 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009765 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9766 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009767 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009768 unlock_iovec(vec, arg2, arg3, 0);
9769 } else {
9770 ret = -host_to_target_errno(errno);
9771 }
bellard31e31b82003-02-18 22:55:36 +00009772 }
9773 break;
9774 case TARGET_NR_getsid:
9775 ret = get_errno(getsid(arg1));
9776 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009777#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009778 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009779 ret = get_errno(fdatasync(arg1));
9780 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009781#endif
Chen Gang704eff62015-08-21 05:37:33 +08009782#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009783 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009784 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009785 return value. */
ths0da46a62007-10-20 20:23:07 +00009786 ret = -TARGET_ENOTDIR;
9787 break;
Chen Gang704eff62015-08-21 05:37:33 +08009788#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009789 case TARGET_NR_sched_getaffinity:
9790 {
9791 unsigned int mask_size;
9792 unsigned long *mask;
9793
9794 /*
9795 * sched_getaffinity needs multiples of ulong, so need to take
9796 * care of mismatches between target ulong and host ulong sizes.
9797 */
9798 if (arg2 & (sizeof(abi_ulong) - 1)) {
9799 ret = -TARGET_EINVAL;
9800 break;
9801 }
9802 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9803
9804 mask = alloca(mask_size);
9805 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9806
9807 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009808 if (ret > arg2) {
9809 /* More data returned than the caller's buffer will fit.
9810 * This only happens if sizeof(abi_long) < sizeof(long)
9811 * and the caller passed us a buffer holding an odd number
9812 * of abi_longs. If the host kernel is actually using the
9813 * extra 4 bytes then fail EINVAL; otherwise we can just
9814 * ignore them and only copy the interesting part.
9815 */
9816 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9817 if (numcpus > arg2 * 8) {
9818 ret = -TARGET_EINVAL;
9819 break;
9820 }
9821 ret = arg2;
9822 }
9823
Mike McCormackcd18f052011-04-18 14:43:36 +09009824 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009825 goto efault;
9826 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009827 }
9828 }
9829 break;
9830 case TARGET_NR_sched_setaffinity:
9831 {
9832 unsigned int mask_size;
9833 unsigned long *mask;
9834
9835 /*
9836 * sched_setaffinity needs multiples of ulong, so need to take
9837 * care of mismatches between target ulong and host ulong sizes.
9838 */
9839 if (arg2 & (sizeof(abi_ulong) - 1)) {
9840 ret = -TARGET_EINVAL;
9841 break;
9842 }
9843 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9844
9845 mask = alloca(mask_size);
9846 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9847 goto efault;
9848 }
9849 memcpy(mask, p, arg2);
9850 unlock_user_struct(p, arg2, 0);
9851
9852 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9853 }
9854 break;
bellard31e31b82003-02-18 22:55:36 +00009855 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009856 {
pbrook53a59602006-03-25 19:31:22 +00009857 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009858 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009859
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009860 if (arg2 == 0) {
9861 return -TARGET_EINVAL;
9862 }
bellard579a97f2007-11-11 14:26:47 +00009863 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9864 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009865 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009866 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009867 ret = get_errno(sched_setparam(arg1, &schp));
9868 }
9869 break;
bellard31e31b82003-02-18 22:55:36 +00009870 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009871 {
pbrook53a59602006-03-25 19:31:22 +00009872 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009873 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009874
9875 if (arg2 == 0) {
9876 return -TARGET_EINVAL;
9877 }
bellard5cd43932003-03-29 16:54:36 +00009878 ret = get_errno(sched_getparam(arg1, &schp));
9879 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009880 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9881 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009882 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009883 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009884 }
9885 }
9886 break;
bellard31e31b82003-02-18 22:55:36 +00009887 case TARGET_NR_sched_setscheduler:
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 if (arg3 == 0) {
9892 return -TARGET_EINVAL;
9893 }
bellard579a97f2007-11-11 14:26:47 +00009894 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9895 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009896 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009897 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009898 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9899 }
9900 break;
bellard31e31b82003-02-18 22:55:36 +00009901 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009902 ret = get_errno(sched_getscheduler(arg1));
9903 break;
bellard31e31b82003-02-18 22:55:36 +00009904 case TARGET_NR_sched_yield:
9905 ret = get_errno(sched_yield());
9906 break;
9907 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009908 ret = get_errno(sched_get_priority_max(arg1));
9909 break;
bellard31e31b82003-02-18 22:55:36 +00009910 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009911 ret = get_errno(sched_get_priority_min(arg1));
9912 break;
bellard31e31b82003-02-18 22:55:36 +00009913 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009914 {
bellard5cd43932003-03-29 16:54:36 +00009915 struct timespec ts;
9916 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9917 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009918 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009919 }
9920 }
9921 break;
bellard31e31b82003-02-18 22:55:36 +00009922 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009923 {
bellard1b6b0292003-03-22 17:31:38 +00009924 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009925 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009926 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009927 if (is_error(ret) && arg2) {
9928 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009929 }
9930 }
9931 break;
thse5febef2007-04-01 18:31:35 +00009932#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009933 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009934 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009935#endif
9936#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009937 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009938 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009939#endif
bellard31e31b82003-02-18 22:55:36 +00009940 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009941 switch (arg1) {
9942 case PR_GET_PDEATHSIG:
9943 {
9944 int deathsig;
9945 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9946 if (!is_error(ret) && arg2
9947 && put_user_ual(deathsig, arg2)) {
9948 goto efault;
thse5574482007-02-11 20:03:13 +00009949 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009950 break;
9951 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009952#ifdef PR_GET_NAME
9953 case PR_GET_NAME:
9954 {
9955 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9956 if (!name) {
9957 goto efault;
9958 }
9959 ret = get_errno(prctl(arg1, (unsigned long)name,
9960 arg3, arg4, arg5));
9961 unlock_user(name, arg2, 16);
9962 break;
9963 }
9964 case PR_SET_NAME:
9965 {
9966 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9967 if (!name) {
9968 goto efault;
9969 }
9970 ret = get_errno(prctl(arg1, (unsigned long)name,
9971 arg3, arg4, arg5));
9972 unlock_user(name, arg2, 0);
9973 break;
9974 }
9975#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009976 default:
9977 /* Most prctl options have no pointer arguments */
9978 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9979 break;
9980 }
ths39b9aae2007-02-11 18:36:44 +00009981 break;
bellardd2fd1af2007-11-14 18:08:56 +00009982#ifdef TARGET_NR_arch_prctl
9983 case TARGET_NR_arch_prctl:
9984#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9985 ret = do_arch_prctl(cpu_env, arg1, arg2);
9986 break;
9987#else
9988 goto unimplemented;
9989#endif
9990#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009991#ifdef TARGET_NR_pread64
9992 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009993 if (regpairs_aligned(cpu_env)) {
9994 arg4 = arg5;
9995 arg5 = arg6;
9996 }
aurel32f2c7ba12008-03-28 22:32:06 +00009997 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9998 goto efault;
9999 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10000 unlock_user(p, arg2, ret);
10001 break;
10002 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +000010003 if (regpairs_aligned(cpu_env)) {
10004 arg4 = arg5;
10005 arg5 = arg6;
10006 }
aurel32f2c7ba12008-03-28 22:32:06 +000010007 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10008 goto efault;
10009 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10010 unlock_user(p, arg2, 0);
10011 break;
10012#endif
bellard31e31b82003-02-18 22:55:36 +000010013 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010014 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10015 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010016 ret = get_errno(sys_getcwd1(p, arg2));
10017 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010018 break;
10019 case TARGET_NR_capget:
10020 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010021 {
10022 struct target_user_cap_header *target_header;
10023 struct target_user_cap_data *target_data = NULL;
10024 struct __user_cap_header_struct header;
10025 struct __user_cap_data_struct data[2];
10026 struct __user_cap_data_struct *dataptr = NULL;
10027 int i, target_datalen;
10028 int data_items = 1;
10029
10030 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10031 goto efault;
10032 }
10033 header.version = tswap32(target_header->version);
10034 header.pid = tswap32(target_header->pid);
10035
Peter Maydellec864872014-03-19 16:07:30 +000010036 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010037 /* Version 2 and up takes pointer to two user_data structs */
10038 data_items = 2;
10039 }
10040
10041 target_datalen = sizeof(*target_data) * data_items;
10042
10043 if (arg2) {
10044 if (num == TARGET_NR_capget) {
10045 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10046 } else {
10047 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10048 }
10049 if (!target_data) {
10050 unlock_user_struct(target_header, arg1, 0);
10051 goto efault;
10052 }
10053
10054 if (num == TARGET_NR_capset) {
10055 for (i = 0; i < data_items; i++) {
10056 data[i].effective = tswap32(target_data[i].effective);
10057 data[i].permitted = tswap32(target_data[i].permitted);
10058 data[i].inheritable = tswap32(target_data[i].inheritable);
10059 }
10060 }
10061
10062 dataptr = data;
10063 }
10064
10065 if (num == TARGET_NR_capget) {
10066 ret = get_errno(capget(&header, dataptr));
10067 } else {
10068 ret = get_errno(capset(&header, dataptr));
10069 }
10070
10071 /* The kernel always updates version for both capget and capset */
10072 target_header->version = tswap32(header.version);
10073 unlock_user_struct(target_header, arg1, 1);
10074
10075 if (arg2) {
10076 if (num == TARGET_NR_capget) {
10077 for (i = 0; i < data_items; i++) {
10078 target_data[i].effective = tswap32(data[i].effective);
10079 target_data[i].permitted = tswap32(data[i].permitted);
10080 target_data[i].inheritable = tswap32(data[i].inheritable);
10081 }
10082 unlock_user(target_data, arg2, target_datalen);
10083 } else {
10084 unlock_user(target_data, arg2, 0);
10085 }
10086 }
10087 break;
10088 }
bellard31e31b82003-02-18 22:55:36 +000010089 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010090 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010091 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010092
10093#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010094 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010095 {
10096 off_t *offp = NULL;
10097 off_t off;
10098 if (arg3) {
10099 ret = get_user_sal(off, arg3);
10100 if (is_error(ret)) {
10101 break;
10102 }
10103 offp = &off;
10104 }
10105 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10106 if (!is_error(ret) && arg3) {
10107 abi_long ret2 = put_user_sal(off, arg3);
10108 if (is_error(ret2)) {
10109 ret = ret2;
10110 }
10111 }
10112 break;
10113 }
10114#ifdef TARGET_NR_sendfile64
10115 case TARGET_NR_sendfile64:
10116 {
10117 off_t *offp = NULL;
10118 off_t off;
10119 if (arg3) {
10120 ret = get_user_s64(off, arg3);
10121 if (is_error(ret)) {
10122 break;
10123 }
10124 offp = &off;
10125 }
10126 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10127 if (!is_error(ret) && arg3) {
10128 abi_long ret2 = put_user_s64(off, arg3);
10129 if (is_error(ret2)) {
10130 ret = ret2;
10131 }
10132 }
10133 break;
10134 }
10135#endif
10136#else
10137 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010138#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010139 case TARGET_NR_sendfile64:
10140#endif
bellard5cd43932003-03-29 16:54:36 +000010141 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010142#endif
10143
bellardebc05482003-09-30 21:08:41 +000010144#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010145 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010146 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010147#endif
10148#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010149 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010150 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010151#endif
bellard048f6b42005-11-26 18:47:20 +000010152#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010153 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +000010154 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
10155 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010156 break;
bellard048f6b42005-11-26 18:47:20 +000010157#endif
bellardebc05482003-09-30 21:08:41 +000010158#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010159 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010160 {
10161 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010162 int resource = target_to_host_resource(arg1);
10163 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010164 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010165 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010166 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10167 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010168 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10169 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010170 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010171 }
10172 break;
10173 }
bellardebc05482003-09-30 21:08:41 +000010174#endif
bellarda315a142005-01-30 22:59:18 +000010175#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010176 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010177 if (!(p = lock_user_string(arg1)))
10178 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010179 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10180 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010181 break;
bellarda315a142005-01-30 22:59:18 +000010182#endif
10183#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010184 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010185 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010186 break;
bellarda315a142005-01-30 22:59:18 +000010187#endif
10188#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010189 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010190 if (!(p = lock_user_string(arg1)))
10191 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010192 ret = get_errno(stat(path(p), &st));
10193 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010194 if (!is_error(ret))
10195 ret = host_to_target_stat64(cpu_env, arg2, &st);
10196 break;
bellarda315a142005-01-30 22:59:18 +000010197#endif
10198#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010199 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010200 if (!(p = lock_user_string(arg1)))
10201 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010202 ret = get_errno(lstat(path(p), &st));
10203 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010204 if (!is_error(ret))
10205 ret = host_to_target_stat64(cpu_env, arg2, &st);
10206 break;
bellarda315a142005-01-30 22:59:18 +000010207#endif
10208#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010209 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010210 ret = get_errno(fstat(arg1, &st));
10211 if (!is_error(ret))
10212 ret = host_to_target_stat64(cpu_env, arg2, &st);
10213 break;
bellardec86b0f2003-04-11 00:15:04 +000010214#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010215#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010216#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010217 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010218#endif
10219#ifdef TARGET_NR_newfstatat
10220 case TARGET_NR_newfstatat:
10221#endif
balrog6a24a772008-09-20 02:23:36 +000010222 if (!(p = lock_user_string(arg2)))
10223 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010224 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010225 if (!is_error(ret))
10226 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010227 break;
bellarda315a142005-01-30 22:59:18 +000010228#endif
Chen Gang704eff62015-08-21 05:37:33 +080010229#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010230 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010231 if (!(p = lock_user_string(arg1)))
10232 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010233 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10234 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010235 break;
Chen Gang704eff62015-08-21 05:37:33 +080010236#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010237#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010238 case TARGET_NR_getuid:
10239 ret = get_errno(high2lowuid(getuid()));
10240 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010241#endif
10242#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010243 case TARGET_NR_getgid:
10244 ret = get_errno(high2lowgid(getgid()));
10245 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010246#endif
10247#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010248 case TARGET_NR_geteuid:
10249 ret = get_errno(high2lowuid(geteuid()));
10250 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010251#endif
10252#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010253 case TARGET_NR_getegid:
10254 ret = get_errno(high2lowgid(getegid()));
10255 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010256#endif
bellard67867302003-11-23 17:05:30 +000010257 case TARGET_NR_setreuid:
10258 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
10259 break;
10260 case TARGET_NR_setregid:
10261 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
10262 break;
10263 case TARGET_NR_getgroups:
10264 {
10265 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010266 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010267 gid_t *grouplist;
10268 int i;
10269
10270 grouplist = alloca(gidsetsize * sizeof(gid_t));
10271 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010272 if (gidsetsize == 0)
10273 break;
bellard67867302003-11-23 17:05:30 +000010274 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010275 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010276 if (!target_grouplist)
10277 goto efault;
balroga2155fc2008-09-20 02:12:08 +000010278 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010279 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010280 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010281 }
10282 }
10283 break;
10284 case TARGET_NR_setgroups:
10285 {
10286 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010287 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010288 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010289 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010290 if (gidsetsize) {
10291 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010292 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010293 if (!target_grouplist) {
10294 ret = -TARGET_EFAULT;
10295 goto fail;
10296 }
10297 for (i = 0; i < gidsetsize; i++) {
10298 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10299 }
10300 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010301 }
bellard67867302003-11-23 17:05:30 +000010302 ret = get_errno(setgroups(gidsetsize, grouplist));
10303 }
10304 break;
10305 case TARGET_NR_fchown:
10306 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
10307 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010308#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010309 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010310 if (!(p = lock_user_string(arg2)))
10311 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010312 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10313 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010314 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000010315 break;
10316#endif
bellard67867302003-11-23 17:05:30 +000010317#ifdef TARGET_NR_setresuid
10318 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010319 ret = get_errno(sys_setresuid(low2highuid(arg1),
10320 low2highuid(arg2),
10321 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010322 break;
10323#endif
10324#ifdef TARGET_NR_getresuid
10325 case TARGET_NR_getresuid:
10326 {
pbrook53a59602006-03-25 19:31:22 +000010327 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010328 ret = get_errno(getresuid(&ruid, &euid, &suid));
10329 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010330 if (put_user_id(high2lowuid(ruid), arg1)
10331 || put_user_id(high2lowuid(euid), arg2)
10332 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000010333 goto efault;
bellard67867302003-11-23 17:05:30 +000010334 }
10335 }
10336 break;
10337#endif
10338#ifdef TARGET_NR_getresgid
10339 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010340 ret = get_errno(sys_setresgid(low2highgid(arg1),
10341 low2highgid(arg2),
10342 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010343 break;
10344#endif
10345#ifdef TARGET_NR_getresgid
10346 case TARGET_NR_getresgid:
10347 {
pbrook53a59602006-03-25 19:31:22 +000010348 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010349 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10350 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010351 if (put_user_id(high2lowgid(rgid), arg1)
10352 || put_user_id(high2lowgid(egid), arg2)
10353 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000010354 goto efault;
bellard67867302003-11-23 17:05:30 +000010355 }
10356 }
10357 break;
10358#endif
Chen Gang704eff62015-08-21 05:37:33 +080010359#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000010360 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000010361 if (!(p = lock_user_string(arg1)))
10362 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010363 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
10364 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010365 break;
Chen Gang704eff62015-08-21 05:37:33 +080010366#endif
bellard67867302003-11-23 17:05:30 +000010367 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010368 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000010369 break;
10370 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010371 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000010372 break;
10373 case TARGET_NR_setfsuid:
10374 ret = get_errno(setfsuid(arg1));
10375 break;
10376 case TARGET_NR_setfsgid:
10377 ret = get_errno(setfsgid(arg1));
10378 break;
bellard67867302003-11-23 17:05:30 +000010379
bellarda315a142005-01-30 22:59:18 +000010380#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000010381 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000010382 if (!(p = lock_user_string(arg1)))
10383 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010384 ret = get_errno(lchown(p, arg2, arg3));
10385 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010386 break;
bellarda315a142005-01-30 22:59:18 +000010387#endif
10388#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000010389 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000010390 ret = get_errno(getuid());
10391 break;
bellarda315a142005-01-30 22:59:18 +000010392#endif
aurel3264b4d282008-11-14 17:20:15 +000010393
10394#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
10395 /* Alpha specific */
10396 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010397 {
10398 uid_t euid;
10399 euid=geteuid();
10400 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
10401 }
aurel3264b4d282008-11-14 17:20:15 +000010402 ret = get_errno(getuid());
10403 break;
10404#endif
10405#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
10406 /* Alpha specific */
10407 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010408 {
10409 uid_t egid;
10410 egid=getegid();
10411 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
10412 }
aurel3264b4d282008-11-14 17:20:15 +000010413 ret = get_errno(getgid());
10414 break;
10415#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080010416#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
10417 /* Alpha specific */
10418 case TARGET_NR_osf_getsysinfo:
10419 ret = -TARGET_EOPNOTSUPP;
10420 switch (arg1) {
10421 case TARGET_GSI_IEEE_FP_CONTROL:
10422 {
10423 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
10424
10425 /* Copied from linux ieee_fpcr_to_swcr. */
10426 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
10427 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
10428 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
10429 | SWCR_TRAP_ENABLE_DZE
10430 | SWCR_TRAP_ENABLE_OVF);
10431 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
10432 | SWCR_TRAP_ENABLE_INE);
10433 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
10434 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
10435
10436 if (put_user_u64 (swcr, arg2))
10437 goto efault;
10438 ret = 0;
10439 }
10440 break;
10441
10442 /* case GSI_IEEE_STATE_AT_SIGNAL:
10443 -- Not implemented in linux kernel.
10444 case GSI_UACPROC:
10445 -- Retrieves current unaligned access state; not much used.
10446 case GSI_PROC_TYPE:
10447 -- Retrieves implver information; surely not used.
10448 case GSI_GET_HWRPB:
10449 -- Grabs a copy of the HWRPB; surely not used.
10450 */
10451 }
10452 break;
10453#endif
10454#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
10455 /* Alpha specific */
10456 case TARGET_NR_osf_setsysinfo:
10457 ret = -TARGET_EOPNOTSUPP;
10458 switch (arg1) {
10459 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010460 {
10461 uint64_t swcr, fpcr, orig_fpcr;
10462
Richard Henderson6e06d512012-06-01 09:08:21 -070010463 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080010464 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070010465 }
10466 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010467 fpcr = orig_fpcr & FPCR_DYN_MASK;
10468
10469 /* Copied from linux ieee_swcr_to_fpcr. */
10470 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
10471 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
10472 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
10473 | SWCR_TRAP_ENABLE_DZE
10474 | SWCR_TRAP_ENABLE_OVF)) << 48;
10475 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
10476 | SWCR_TRAP_ENABLE_INE)) << 57;
10477 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
10478 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
10479
Richard Henderson6e06d512012-06-01 09:08:21 -070010480 cpu_alpha_store_fpcr(cpu_env, fpcr);
10481 ret = 0;
10482 }
10483 break;
10484
10485 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
10486 {
10487 uint64_t exc, fpcr, orig_fpcr;
10488 int si_code;
10489
10490 if (get_user_u64(exc, arg2)) {
10491 goto efault;
10492 }
10493
10494 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
10495
10496 /* We only add to the exception status here. */
10497 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
10498
10499 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010500 ret = 0;
10501
Richard Henderson6e06d512012-06-01 09:08:21 -070010502 /* Old exceptions are not signaled. */
10503 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010504
Richard Henderson6e06d512012-06-01 09:08:21 -070010505 /* If any exceptions set by this call,
10506 and are unmasked, send a signal. */
10507 si_code = 0;
10508 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
10509 si_code = TARGET_FPE_FLTRES;
10510 }
10511 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
10512 si_code = TARGET_FPE_FLTUND;
10513 }
10514 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
10515 si_code = TARGET_FPE_FLTOVF;
10516 }
10517 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
10518 si_code = TARGET_FPE_FLTDIV;
10519 }
10520 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
10521 si_code = TARGET_FPE_FLTINV;
10522 }
10523 if (si_code != 0) {
10524 target_siginfo_t info;
10525 info.si_signo = SIGFPE;
10526 info.si_errno = 0;
10527 info.si_code = si_code;
10528 info._sifields._sigfault._addr
10529 = ((CPUArchState *)cpu_env)->pc;
10530 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010531 }
10532 }
10533 break;
10534
10535 /* case SSI_NVPAIRS:
10536 -- Used with SSIN_UACPROC to enable unaligned accesses.
10537 case SSI_IEEE_STATE_AT_SIGNAL:
10538 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
10539 -- Not implemented in linux kernel
10540 */
10541 }
10542 break;
10543#endif
10544#ifdef TARGET_NR_osf_sigprocmask
10545 /* Alpha specific. */
10546 case TARGET_NR_osf_sigprocmask:
10547 {
10548 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010549 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010550 sigset_t set, oldset;
10551
10552 switch(arg1) {
10553 case TARGET_SIG_BLOCK:
10554 how = SIG_BLOCK;
10555 break;
10556 case TARGET_SIG_UNBLOCK:
10557 how = SIG_UNBLOCK;
10558 break;
10559 case TARGET_SIG_SETMASK:
10560 how = SIG_SETMASK;
10561 break;
10562 default:
10563 ret = -TARGET_EINVAL;
10564 goto fail;
10565 }
10566 mask = arg2;
10567 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010568 ret = do_sigprocmask(how, &set, &oldset);
10569 if (!ret) {
10570 host_to_target_old_sigset(&mask, &oldset);
10571 ret = mask;
10572 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010573 }
10574 break;
10575#endif
aurel3264b4d282008-11-14 17:20:15 +000010576
bellarda315a142005-01-30 22:59:18 +000010577#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010578 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000010579 ret = get_errno(getgid());
10580 break;
bellarda315a142005-01-30 22:59:18 +000010581#endif
10582#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010583 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000010584 ret = get_errno(geteuid());
10585 break;
bellarda315a142005-01-30 22:59:18 +000010586#endif
10587#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010588 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010589 ret = get_errno(getegid());
10590 break;
bellarda315a142005-01-30 22:59:18 +000010591#endif
10592#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010593 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010594 ret = get_errno(setreuid(arg1, arg2));
10595 break;
bellarda315a142005-01-30 22:59:18 +000010596#endif
10597#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010598 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010599 ret = get_errno(setregid(arg1, arg2));
10600 break;
bellarda315a142005-01-30 22:59:18 +000010601#endif
10602#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010603 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010604 {
10605 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010606 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010607 gid_t *grouplist;
10608 int i;
10609
10610 grouplist = alloca(gidsetsize * sizeof(gid_t));
10611 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010612 if (gidsetsize == 0)
10613 break;
bellard99c475a2005-01-31 20:45:13 +000010614 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010615 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10616 if (!target_grouplist) {
10617 ret = -TARGET_EFAULT;
10618 goto fail;
10619 }
balroga2155fc2008-09-20 02:12:08 +000010620 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010621 target_grouplist[i] = tswap32(grouplist[i]);
10622 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010623 }
10624 }
10625 break;
bellarda315a142005-01-30 22:59:18 +000010626#endif
10627#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010628 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010629 {
10630 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010631 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010632 gid_t *grouplist;
10633 int i;
ths3b46e622007-09-17 08:09:54 +000010634
bellard99c475a2005-01-31 20:45:13 +000010635 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010636 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10637 if (!target_grouplist) {
10638 ret = -TARGET_EFAULT;
10639 goto fail;
10640 }
bellard99c475a2005-01-31 20:45:13 +000010641 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010642 grouplist[i] = tswap32(target_grouplist[i]);
10643 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010644 ret = get_errno(setgroups(gidsetsize, grouplist));
10645 }
10646 break;
bellarda315a142005-01-30 22:59:18 +000010647#endif
10648#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010649 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010650 ret = get_errno(fchown(arg1, arg2, arg3));
10651 break;
bellarda315a142005-01-30 22:59:18 +000010652#endif
10653#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010654 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010655 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010656 break;
bellarda315a142005-01-30 22:59:18 +000010657#endif
10658#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010659 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010660 {
pbrook53a59602006-03-25 19:31:22 +000010661 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010662 ret = get_errno(getresuid(&ruid, &euid, &suid));
10663 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010664 if (put_user_u32(ruid, arg1)
10665 || put_user_u32(euid, arg2)
10666 || put_user_u32(suid, arg3))
10667 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010668 }
10669 }
10670 break;
bellarda315a142005-01-30 22:59:18 +000010671#endif
10672#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010673 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010674 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010675 break;
bellarda315a142005-01-30 22:59:18 +000010676#endif
10677#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010678 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010679 {
pbrook53a59602006-03-25 19:31:22 +000010680 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010681 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10682 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010683 if (put_user_u32(rgid, arg1)
10684 || put_user_u32(egid, arg2)
10685 || put_user_u32(sgid, arg3))
10686 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010687 }
10688 }
10689 break;
bellarda315a142005-01-30 22:59:18 +000010690#endif
10691#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010692 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010693 if (!(p = lock_user_string(arg1)))
10694 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010695 ret = get_errno(chown(p, arg2, arg3));
10696 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010697 break;
bellarda315a142005-01-30 22:59:18 +000010698#endif
10699#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010700 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010701 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010702 break;
bellarda315a142005-01-30 22:59:18 +000010703#endif
10704#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010705 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010706 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010707 break;
bellarda315a142005-01-30 22:59:18 +000010708#endif
10709#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010710 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010711 ret = get_errno(setfsuid(arg1));
10712 break;
bellarda315a142005-01-30 22:59:18 +000010713#endif
10714#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010715 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010716 ret = get_errno(setfsgid(arg1));
10717 break;
bellarda315a142005-01-30 22:59:18 +000010718#endif
bellard67867302003-11-23 17:05:30 +000010719
bellard31e31b82003-02-18 22:55:36 +000010720 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010721 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010722#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010723 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010724 {
10725 void *a;
10726 ret = -TARGET_EFAULT;
10727 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10728 goto efault;
10729 if (!(p = lock_user_string(arg3)))
10730 goto mincore_fail;
10731 ret = get_errno(mincore(a, arg2, p));
10732 unlock_user(p, arg3, ret);
10733 mincore_fail:
10734 unlock_user(a, arg1, 0);
10735 }
10736 break;
bellardffa65c32004-01-04 23:57:22 +000010737#endif
aurel32408321b2008-10-01 21:46:32 +000010738#ifdef TARGET_NR_arm_fadvise64_64
10739 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010740 /* arm_fadvise64_64 looks like fadvise64_64 but
10741 * with different argument order: fd, advice, offset, len
10742 * rather than the usual fd, offset, len, advice.
10743 * Note that offset and len are both 64-bit so appear as
10744 * pairs of 32-bit registers.
10745 */
10746 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10747 target_offset64(arg5, arg6), arg2);
10748 ret = -host_to_target_errno(ret);
10749 break;
aurel32408321b2008-10-01 21:46:32 +000010750#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010751
10752#if TARGET_ABI_BITS == 32
10753
10754#ifdef TARGET_NR_fadvise64_64
10755 case TARGET_NR_fadvise64_64:
10756 /* 6 args: fd, offset (high, low), len (high, low), advice */
10757 if (regpairs_aligned(cpu_env)) {
10758 /* offset is in (3,4), len in (5,6) and advice in 7 */
10759 arg2 = arg3;
10760 arg3 = arg4;
10761 arg4 = arg5;
10762 arg5 = arg6;
10763 arg6 = arg7;
10764 }
10765 ret = -host_to_target_errno(posix_fadvise(arg1,
10766 target_offset64(arg2, arg3),
10767 target_offset64(arg4, arg5),
10768 arg6));
10769 break;
10770#endif
10771
10772#ifdef TARGET_NR_fadvise64
10773 case TARGET_NR_fadvise64:
10774 /* 5 args: fd, offset (high, low), len, advice */
10775 if (regpairs_aligned(cpu_env)) {
10776 /* offset is in (3,4), len in 5 and advice in 6 */
10777 arg2 = arg3;
10778 arg3 = arg4;
10779 arg4 = arg5;
10780 arg5 = arg6;
10781 }
10782 ret = -host_to_target_errno(posix_fadvise(arg1,
10783 target_offset64(arg2, arg3),
10784 arg4, arg5));
10785 break;
10786#endif
10787
10788#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010789#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010790#ifdef TARGET_NR_fadvise64_64
10791 case TARGET_NR_fadvise64_64:
10792#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010793#ifdef TARGET_NR_fadvise64
10794 case TARGET_NR_fadvise64:
10795#endif
10796#ifdef TARGET_S390X
10797 switch (arg4) {
10798 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10799 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10800 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10801 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10802 default: break;
10803 }
10804#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010805 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10806 break;
aurel32408321b2008-10-01 21:46:32 +000010807#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010808#endif /* end of 64-bit ABI fadvise handling */
10809
bellardffa65c32004-01-04 23:57:22 +000010810#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010811 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010812 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010813 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010814 This will break MADV_DONTNEED.
10815 This is a hint, so ignoring and returning success is ok. */
10816 ret = get_errno(0);
10817 break;
bellardffa65c32004-01-04 23:57:22 +000010818#endif
blueswir1992f48a2007-10-14 16:27:31 +000010819#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010820 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010821 {
thsb1e341e2007-03-20 21:50:52 +000010822 int cmd;
bellard77e46722003-04-29 20:39:06 +000010823 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010824 from_flock64_fn *copyfrom = copy_from_user_flock64;
10825 to_flock64_fn *copyto = copy_to_user_flock64;
10826
pbrookce4defa2006-02-09 16:49:55 +000010827#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010828 if (((CPUARMState *)cpu_env)->eabi) {
10829 copyfrom = copy_from_user_eabi_flock64;
10830 copyto = copy_to_user_eabi_flock64;
10831 }
pbrookce4defa2006-02-09 16:49:55 +000010832#endif
bellard77e46722003-04-29 20:39:06 +000010833
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010834 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010835 if (cmd == -TARGET_EINVAL) {
10836 ret = cmd;
10837 break;
10838 }
thsb1e341e2007-03-20 21:50:52 +000010839
bellard60cd49d2003-03-16 22:53:56 +000010840 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010841 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010842 ret = copyfrom(&fl, arg3);
10843 if (ret) {
10844 break;
ths58134272007-03-31 18:59:32 +000010845 }
thsb1e341e2007-03-20 21:50:52 +000010846 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010847 if (ret == 0) {
10848 ret = copyto(arg3, &fl);
10849 }
bellard77e46722003-04-29 20:39:06 +000010850 break;
10851
thsb1e341e2007-03-20 21:50:52 +000010852 case TARGET_F_SETLK64:
10853 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010854 ret = copyfrom(&fl, arg3);
10855 if (ret) {
10856 break;
pbrookce4defa2006-02-09 16:49:55 +000010857 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010858 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010859 break;
bellard60cd49d2003-03-16 22:53:56 +000010860 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010861 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010862 break;
10863 }
bellard77e46722003-04-29 20:39:06 +000010864 break;
10865 }
bellard60cd49d2003-03-16 22:53:56 +000010866#endif
ths7d600c82006-12-08 01:32:58 +000010867#ifdef TARGET_NR_cacheflush
10868 case TARGET_NR_cacheflush:
10869 /* self-modifying code is handled automatically, so nothing needed */
10870 ret = 0;
10871 break;
10872#endif
bellardebc05482003-09-30 21:08:41 +000010873#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010874 case TARGET_NR_security:
10875 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010876#endif
bellardc573ff62004-01-04 15:51:36 +000010877#ifdef TARGET_NR_getpagesize
10878 case TARGET_NR_getpagesize:
10879 ret = TARGET_PAGE_SIZE;
10880 break;
10881#endif
bellard31e31b82003-02-18 22:55:36 +000010882 case TARGET_NR_gettid:
10883 ret = get_errno(gettid());
10884 break;
thse5febef2007-04-01 18:31:35 +000010885#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010886 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010887#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010888 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010889 arg2 = arg3;
10890 arg3 = arg4;
10891 arg4 = arg5;
10892 }
aurel322054ac92008-10-13 21:08:07 +000010893 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10894#else
10895 ret = get_errno(readahead(arg1, arg2, arg3));
10896#endif
10897 break;
thse5febef2007-04-01 18:31:35 +000010898#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010899#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010900#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010901 case TARGET_NR_listxattr:
10902 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010903 {
10904 void *p, *b = 0;
10905 if (arg2) {
10906 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10907 if (!b) {
10908 ret = -TARGET_EFAULT;
10909 break;
10910 }
10911 }
10912 p = lock_user_string(arg1);
10913 if (p) {
10914 if (num == TARGET_NR_listxattr) {
10915 ret = get_errno(listxattr(p, b, arg3));
10916 } else {
10917 ret = get_errno(llistxattr(p, b, arg3));
10918 }
10919 } else {
10920 ret = -TARGET_EFAULT;
10921 }
10922 unlock_user(p, arg1, 0);
10923 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010924 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010925 }
10926 case TARGET_NR_flistxattr:
10927 {
10928 void *b = 0;
10929 if (arg2) {
10930 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10931 if (!b) {
10932 ret = -TARGET_EFAULT;
10933 break;
10934 }
10935 }
10936 ret = get_errno(flistxattr(arg1, b, arg3));
10937 unlock_user(b, arg2, arg3);
10938 break;
10939 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010940 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010941 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010942 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010943 void *p, *n, *v = 0;
10944 if (arg3) {
10945 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10946 if (!v) {
10947 ret = -TARGET_EFAULT;
10948 break;
10949 }
10950 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010951 p = lock_user_string(arg1);
10952 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010953 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010954 if (num == TARGET_NR_setxattr) {
10955 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10956 } else {
10957 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10958 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010959 } else {
10960 ret = -TARGET_EFAULT;
10961 }
10962 unlock_user(p, arg1, 0);
10963 unlock_user(n, arg2, 0);
10964 unlock_user(v, arg3, 0);
10965 }
10966 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010967 case TARGET_NR_fsetxattr:
10968 {
10969 void *n, *v = 0;
10970 if (arg3) {
10971 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10972 if (!v) {
10973 ret = -TARGET_EFAULT;
10974 break;
10975 }
10976 }
10977 n = lock_user_string(arg2);
10978 if (n) {
10979 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10980 } else {
10981 ret = -TARGET_EFAULT;
10982 }
10983 unlock_user(n, arg2, 0);
10984 unlock_user(v, arg3, 0);
10985 }
10986 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010987 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010988 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010989 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010990 void *p, *n, *v = 0;
10991 if (arg3) {
10992 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10993 if (!v) {
10994 ret = -TARGET_EFAULT;
10995 break;
10996 }
10997 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010998 p = lock_user_string(arg1);
10999 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011000 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011001 if (num == TARGET_NR_getxattr) {
11002 ret = get_errno(getxattr(p, n, v, arg4));
11003 } else {
11004 ret = get_errno(lgetxattr(p, n, v, arg4));
11005 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011006 } else {
11007 ret = -TARGET_EFAULT;
11008 }
11009 unlock_user(p, arg1, 0);
11010 unlock_user(n, arg2, 0);
11011 unlock_user(v, arg3, arg4);
11012 }
11013 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011014 case TARGET_NR_fgetxattr:
11015 {
11016 void *n, *v = 0;
11017 if (arg3) {
11018 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11019 if (!v) {
11020 ret = -TARGET_EFAULT;
11021 break;
11022 }
11023 }
11024 n = lock_user_string(arg2);
11025 if (n) {
11026 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11027 } else {
11028 ret = -TARGET_EFAULT;
11029 }
11030 unlock_user(n, arg2, 0);
11031 unlock_user(v, arg3, arg4);
11032 }
11033 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011034 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011035 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011036 {
11037 void *p, *n;
11038 p = lock_user_string(arg1);
11039 n = lock_user_string(arg2);
11040 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011041 if (num == TARGET_NR_removexattr) {
11042 ret = get_errno(removexattr(p, n));
11043 } else {
11044 ret = get_errno(lremovexattr(p, n));
11045 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011046 } else {
11047 ret = -TARGET_EFAULT;
11048 }
11049 unlock_user(p, arg1, 0);
11050 unlock_user(n, arg2, 0);
11051 }
11052 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011053 case TARGET_NR_fremovexattr:
11054 {
11055 void *n;
11056 n = lock_user_string(arg2);
11057 if (n) {
11058 ret = get_errno(fremovexattr(arg1, n));
11059 } else {
11060 ret = -TARGET_EFAULT;
11061 }
11062 unlock_user(n, arg2, 0);
11063 }
11064 break;
bellardebc05482003-09-30 21:08:41 +000011065#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011066#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011067#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011068 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011069#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011070 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011071 ret = 0;
11072 break;
edgar_iglef967792009-01-07 14:19:38 +000011073#elif defined(TARGET_CRIS)
11074 if (arg1 & 0xff)
11075 ret = -TARGET_EINVAL;
11076 else {
11077 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11078 ret = 0;
11079 }
11080 break;
bellard8d18e892007-11-14 15:18:40 +000011081#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11082 ret = do_set_thread_area(cpu_env, arg1);
11083 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011084#elif defined(TARGET_M68K)
11085 {
Andreas Färber0429a972013-08-26 18:14:44 +020011086 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011087 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011088 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011089 break;
11090 }
ths6f5b89a2007-03-02 20:48:00 +000011091#else
11092 goto unimplemented_nowarn;
11093#endif
11094#endif
11095#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011096 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011097#if defined(TARGET_I386) && defined(TARGET_ABI32)
11098 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011099 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011100#elif defined(TARGET_M68K)
11101 {
Andreas Färber0429a972013-08-26 18:14:44 +020011102 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011103 ret = ts->tp_value;
11104 break;
11105 }
bellard8d18e892007-11-14 15:18:40 +000011106#else
bellard5cd43932003-03-29 16:54:36 +000011107 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011108#endif
bellard8d18e892007-11-14 15:18:40 +000011109#endif
bellard48dc41e2006-06-21 18:15:50 +000011110#ifdef TARGET_NR_getdomainname
11111 case TARGET_NR_getdomainname:
11112 goto unimplemented_nowarn;
11113#endif
ths6f5b89a2007-03-02 20:48:00 +000011114
thsb5906f92007-03-19 13:32:45 +000011115#ifdef TARGET_NR_clock_gettime
11116 case TARGET_NR_clock_gettime:
11117 {
11118 struct timespec ts;
11119 ret = get_errno(clock_gettime(arg1, &ts));
11120 if (!is_error(ret)) {
11121 host_to_target_timespec(arg2, &ts);
11122 }
11123 break;
11124 }
11125#endif
11126#ifdef TARGET_NR_clock_getres
11127 case TARGET_NR_clock_getres:
11128 {
11129 struct timespec ts;
11130 ret = get_errno(clock_getres(arg1, &ts));
11131 if (!is_error(ret)) {
11132 host_to_target_timespec(arg2, &ts);
11133 }
11134 break;
11135 }
11136#endif
pbrook63d76512008-05-29 13:43:29 +000011137#ifdef TARGET_NR_clock_nanosleep
11138 case TARGET_NR_clock_nanosleep:
11139 {
11140 struct timespec ts;
11141 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011142 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11143 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011144 if (arg4)
11145 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011146
11147#if defined(TARGET_PPC)
11148 /* clock_nanosleep is odd in that it returns positive errno values.
11149 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011150 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011151 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11152 }
11153#endif
pbrook63d76512008-05-29 13:43:29 +000011154 break;
11155 }
11156#endif
thsb5906f92007-03-19 13:32:45 +000011157
ths6f5b89a2007-03-02 20:48:00 +000011158#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11159 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011160 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11161 break;
ths6f5b89a2007-03-02 20:48:00 +000011162#endif
11163
ths4cae1d12007-07-12 11:06:53 +000011164 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011165 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011166 break;
ths4cae1d12007-07-12 11:06:53 +000011167
ths71455572007-06-21 21:45:30 +000011168 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011169 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011170 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011171 break;
ths71455572007-06-21 21:45:30 +000011172
ths4f2b1fe2007-06-21 21:57:12 +000011173#ifdef TARGET_NR_set_robust_list
11174 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011175 case TARGET_NR_get_robust_list:
11176 /* The ABI for supporting robust futexes has userspace pass
11177 * the kernel a pointer to a linked list which is updated by
11178 * userspace after the syscall; the list is walked by the kernel
11179 * when the thread exits. Since the linked list in QEMU guest
11180 * memory isn't a valid linked list for the host and we have
11181 * no way to reliably intercept the thread-death event, we can't
11182 * support these. Silently return ENOSYS so that guest userspace
11183 * falls back to a non-robust futex implementation (which should
11184 * be OK except in the corner case of the guest crashing while
11185 * holding a mutex that is shared with another process via
11186 * shared memory).
11187 */
11188 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011189#endif
11190
Peter Maydell1acae9f2013-07-02 14:04:12 +010011191#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011192 case TARGET_NR_utimensat:
11193 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011194 struct timespec *tsp, ts[2];
11195 if (!arg3) {
11196 tsp = NULL;
11197 } else {
11198 target_to_host_timespec(ts, arg3);
11199 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11200 tsp = ts;
11201 }
ths9007f0e2007-09-25 17:50:37 +000011202 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011203 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011204 else {
bellard579a97f2007-11-11 14:26:47 +000011205 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011206 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011207 goto fail;
11208 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011209 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011210 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011211 }
11212 }
11213 break;
11214#endif
pbrookbd0c5662008-05-29 14:34:11 +000011215 case TARGET_NR_futex:
11216 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11217 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011218#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011219 case TARGET_NR_inotify_init:
11220 ret = get_errno(sys_inotify_init());
11221 break;
11222#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011223#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011224#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11225 case TARGET_NR_inotify_init1:
11226 ret = get_errno(sys_inotify_init1(arg1));
11227 break;
11228#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011229#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011230#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011231 case TARGET_NR_inotify_add_watch:
11232 p = lock_user_string(arg2);
11233 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11234 unlock_user(p, arg2, 0);
11235 break;
11236#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011237#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011238 case TARGET_NR_inotify_rm_watch:
11239 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
11240 break;
11241#endif
ths9007f0e2007-09-25 17:50:37 +000011242
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011243#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011244 case TARGET_NR_mq_open:
11245 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050011246 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000011247
11248 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050011249 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000011250 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050011251 attrp = &posix_mq_attr;
11252 } else {
11253 attrp = 0;
11254 }
11255 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000011256 unlock_user (p, arg1, 0);
11257 }
11258 break;
11259
11260 case TARGET_NR_mq_unlink:
11261 p = lock_user_string(arg1 - 1);
11262 ret = get_errno(mq_unlink(p));
11263 unlock_user (p, arg1, 0);
11264 break;
11265
11266 case TARGET_NR_mq_timedsend:
11267 {
11268 struct timespec ts;
11269
11270 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11271 if (arg5 != 0) {
11272 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011273 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011274 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011275 } else {
11276 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011277 }
aurel3224e10032009-04-15 16:11:43 +000011278 unlock_user (p, arg2, arg3);
11279 }
11280 break;
11281
11282 case TARGET_NR_mq_timedreceive:
11283 {
11284 struct timespec ts;
11285 unsigned int prio;
11286
11287 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11288 if (arg5 != 0) {
11289 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011290 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11291 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011292 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011293 } else {
11294 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11295 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011296 }
aurel3224e10032009-04-15 16:11:43 +000011297 unlock_user (p, arg2, arg3);
11298 if (arg4 != 0)
11299 put_user_u32(prio, arg4);
11300 }
11301 break;
11302
11303 /* Not implemented for now... */
11304/* case TARGET_NR_mq_notify: */
11305/* break; */
11306
11307 case TARGET_NR_mq_getsetattr:
11308 {
11309 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11310 ret = 0;
11311 if (arg3 != 0) {
11312 ret = mq_getattr(arg1, &posix_mq_attr_out);
11313 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11314 }
11315 if (arg2 != 0) {
11316 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
11317 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
11318 }
11319
11320 }
11321 break;
11322#endif
11323
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011324#ifdef CONFIG_SPLICE
11325#ifdef TARGET_NR_tee
11326 case TARGET_NR_tee:
11327 {
11328 ret = get_errno(tee(arg1,arg2,arg3,arg4));
11329 }
11330 break;
11331#endif
11332#ifdef TARGET_NR_splice
11333 case TARGET_NR_splice:
11334 {
11335 loff_t loff_in, loff_out;
11336 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010011337 if (arg2) {
11338 if (get_user_u64(loff_in, arg2)) {
11339 goto efault;
11340 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011341 ploff_in = &loff_in;
11342 }
Andreas Schwab17644b32015-03-10 17:11:35 +010011343 if (arg4) {
11344 if (get_user_u64(loff_out, arg4)) {
11345 goto efault;
11346 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011347 ploff_out = &loff_out;
11348 }
11349 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010011350 if (arg2) {
11351 if (put_user_u64(loff_in, arg2)) {
11352 goto efault;
11353 }
11354 }
11355 if (arg4) {
11356 if (put_user_u64(loff_out, arg4)) {
11357 goto efault;
11358 }
11359 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011360 }
11361 break;
11362#endif
11363#ifdef TARGET_NR_vmsplice
11364 case TARGET_NR_vmsplice:
11365 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011366 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11367 if (vec != NULL) {
11368 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
11369 unlock_iovec(vec, arg2, arg3, 0);
11370 } else {
11371 ret = -host_to_target_errno(errno);
11372 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011373 }
11374 break;
11375#endif
11376#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030011377#ifdef CONFIG_EVENTFD
11378#if defined(TARGET_NR_eventfd)
11379 case TARGET_NR_eventfd:
11380 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020011381 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011382 break;
11383#endif
11384#if defined(TARGET_NR_eventfd2)
11385 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020011386 {
11387 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
11388 if (arg2 & TARGET_O_NONBLOCK) {
11389 host_flags |= O_NONBLOCK;
11390 }
11391 if (arg2 & TARGET_O_CLOEXEC) {
11392 host_flags |= O_CLOEXEC;
11393 }
11394 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020011395 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011396 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020011397 }
Riku Voipioc2882b92009-08-12 15:08:24 +030011398#endif
11399#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030011400#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
11401 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010011402#if TARGET_ABI_BITS == 32
11403 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
11404 target_offset64(arg5, arg6)));
11405#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030011406 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010011407#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030011408 break;
11409#endif
Peter Maydellc727f472011-01-06 11:05:10 +000011410#if defined(CONFIG_SYNC_FILE_RANGE)
11411#if defined(TARGET_NR_sync_file_range)
11412 case TARGET_NR_sync_file_range:
11413#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030011414#if defined(TARGET_MIPS)
11415 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11416 target_offset64(arg5, arg6), arg7));
11417#else
Peter Maydellc727f472011-01-06 11:05:10 +000011418 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
11419 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030011420#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000011421#else
11422 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
11423#endif
11424 break;
11425#endif
11426#if defined(TARGET_NR_sync_file_range2)
11427 case TARGET_NR_sync_file_range2:
11428 /* This is like sync_file_range but the arguments are reordered */
11429#if TARGET_ABI_BITS == 32
11430 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11431 target_offset64(arg5, arg6), arg2));
11432#else
11433 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
11434#endif
11435 break;
11436#endif
11437#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020011438#if defined(TARGET_NR_signalfd4)
11439 case TARGET_NR_signalfd4:
11440 ret = do_signalfd4(arg1, arg2, arg4);
11441 break;
11442#endif
11443#if defined(TARGET_NR_signalfd)
11444 case TARGET_NR_signalfd:
11445 ret = do_signalfd4(arg1, arg2, 0);
11446 break;
11447#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000011448#if defined(CONFIG_EPOLL)
11449#if defined(TARGET_NR_epoll_create)
11450 case TARGET_NR_epoll_create:
11451 ret = get_errno(epoll_create(arg1));
11452 break;
11453#endif
11454#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
11455 case TARGET_NR_epoll_create1:
11456 ret = get_errno(epoll_create1(arg1));
11457 break;
11458#endif
11459#if defined(TARGET_NR_epoll_ctl)
11460 case TARGET_NR_epoll_ctl:
11461 {
11462 struct epoll_event ep;
11463 struct epoll_event *epp = 0;
11464 if (arg4) {
11465 struct target_epoll_event *target_ep;
11466 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
11467 goto efault;
11468 }
11469 ep.events = tswap32(target_ep->events);
11470 /* The epoll_data_t union is just opaque data to the kernel,
11471 * so we transfer all 64 bits across and need not worry what
11472 * actual data type it is.
11473 */
11474 ep.data.u64 = tswap64(target_ep->data.u64);
11475 unlock_user_struct(target_ep, arg4, 0);
11476 epp = &ep;
11477 }
11478 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
11479 break;
11480 }
11481#endif
11482
Peter Maydell227f0212016-06-06 19:58:11 +010011483#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011484#if defined(TARGET_NR_epoll_wait)
11485 case TARGET_NR_epoll_wait:
11486#endif
Peter Maydell227f0212016-06-06 19:58:11 +010011487#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011488 case TARGET_NR_epoll_pwait:
11489#endif
11490 {
11491 struct target_epoll_event *target_ep;
11492 struct epoll_event *ep;
11493 int epfd = arg1;
11494 int maxevents = arg3;
11495 int timeout = arg4;
11496
11497 target_ep = lock_user(VERIFY_WRITE, arg2,
11498 maxevents * sizeof(struct target_epoll_event), 1);
11499 if (!target_ep) {
11500 goto efault;
11501 }
11502
11503 ep = alloca(maxevents * sizeof(struct epoll_event));
11504
11505 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010011506#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011507 case TARGET_NR_epoll_pwait:
11508 {
11509 target_sigset_t *target_set;
11510 sigset_t _set, *set = &_set;
11511
11512 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010011513 if (arg6 != sizeof(target_sigset_t)) {
11514 ret = -TARGET_EINVAL;
11515 break;
11516 }
11517
Peter Maydell3b6edd12011-02-15 18:35:05 +000011518 target_set = lock_user(VERIFY_READ, arg5,
11519 sizeof(target_sigset_t), 1);
11520 if (!target_set) {
11521 unlock_user(target_ep, arg2, 0);
11522 goto efault;
11523 }
11524 target_to_host_sigset(set, target_set);
11525 unlock_user(target_set, arg5, 0);
11526 } else {
11527 set = NULL;
11528 }
11529
Peter Maydell227f0212016-06-06 19:58:11 +010011530 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11531 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011532 break;
11533 }
11534#endif
11535#if defined(TARGET_NR_epoll_wait)
11536 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010011537 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11538 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011539 break;
11540#endif
11541 default:
11542 ret = -TARGET_ENOSYS;
11543 }
11544 if (!is_error(ret)) {
11545 int i;
11546 for (i = 0; i < ret; i++) {
11547 target_ep[i].events = tswap32(ep[i].events);
11548 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11549 }
11550 }
11551 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
11552 break;
11553 }
11554#endif
11555#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011556#ifdef TARGET_NR_prlimit64
11557 case TARGET_NR_prlimit64:
11558 {
11559 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11560 struct target_rlimit64 *target_rnew, *target_rold;
11561 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011562 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011563 if (arg3) {
11564 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
11565 goto efault;
11566 }
11567 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11568 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11569 unlock_user_struct(target_rnew, arg3, 0);
11570 rnewp = &rnew;
11571 }
11572
Felix Janda95018012014-12-02 22:11:17 +010011573 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011574 if (!is_error(ret) && arg4) {
11575 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
11576 goto efault;
11577 }
11578 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11579 target_rold->rlim_max = tswap64(rold.rlim_max);
11580 unlock_user_struct(target_rold, arg4, 1);
11581 }
11582 break;
11583 }
11584#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011585#ifdef TARGET_NR_gethostname
11586 case TARGET_NR_gethostname:
11587 {
11588 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11589 if (name) {
11590 ret = get_errno(gethostname(name, arg2));
11591 unlock_user(name, arg1, arg2);
11592 } else {
11593 ret = -TARGET_EFAULT;
11594 }
11595 break;
11596 }
11597#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011598#ifdef TARGET_NR_atomic_cmpxchg_32
11599 case TARGET_NR_atomic_cmpxchg_32:
11600 {
11601 /* should use start_exclusive from main.c */
11602 abi_ulong mem_value;
11603 if (get_user_u32(mem_value, arg6)) {
11604 target_siginfo_t info;
11605 info.si_signo = SIGSEGV;
11606 info.si_errno = 0;
11607 info.si_code = TARGET_SEGV_MAPERR;
11608 info._sifields._sigfault._addr = arg6;
11609 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11610 ret = 0xdeadbeef;
11611
11612 }
11613 if (mem_value == arg2)
11614 put_user_u32(arg1, arg6);
11615 ret = mem_value;
11616 break;
11617 }
11618#endif
11619#ifdef TARGET_NR_atomic_barrier
11620 case TARGET_NR_atomic_barrier:
11621 {
11622 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011623 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011624 break;
11625 }
11626#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011627
11628#ifdef TARGET_NR_timer_create
11629 case TARGET_NR_timer_create:
11630 {
11631 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11632
11633 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011634
11635 int clkid = arg1;
11636 int timer_index = next_free_host_timer();
11637
11638 if (timer_index < 0) {
11639 ret = -TARGET_EAGAIN;
11640 } else {
11641 timer_t *phtimer = g_posix_timers + timer_index;
11642
11643 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011644 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011645 ret = target_to_host_sigevent(phost_sevp, arg2);
11646 if (ret != 0) {
11647 break;
11648 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011649 }
11650
11651 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11652 if (ret) {
11653 phtimer = NULL;
11654 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011655 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011656 goto efault;
11657 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011658 }
11659 }
11660 break;
11661 }
11662#endif
11663
11664#ifdef TARGET_NR_timer_settime
11665 case TARGET_NR_timer_settime:
11666 {
11667 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11668 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011669 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011670
Alexander Grafaecc8862014-11-10 21:33:03 +010011671 if (timerid < 0) {
11672 ret = timerid;
11673 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011674 ret = -TARGET_EINVAL;
11675 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011676 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011677 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11678
11679 target_to_host_itimerspec(&hspec_new, arg3);
11680 ret = get_errno(
11681 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11682 host_to_target_itimerspec(arg2, &hspec_old);
11683 }
11684 break;
11685 }
11686#endif
11687
11688#ifdef TARGET_NR_timer_gettime
11689 case TARGET_NR_timer_gettime:
11690 {
11691 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011692 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011693
Alexander Grafaecc8862014-11-10 21:33:03 +010011694 if (timerid < 0) {
11695 ret = timerid;
11696 } else if (!arg2) {
11697 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011698 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011699 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011700 struct itimerspec hspec;
11701 ret = get_errno(timer_gettime(htimer, &hspec));
11702
11703 if (host_to_target_itimerspec(arg2, &hspec)) {
11704 ret = -TARGET_EFAULT;
11705 }
11706 }
11707 break;
11708 }
11709#endif
11710
11711#ifdef TARGET_NR_timer_getoverrun
11712 case TARGET_NR_timer_getoverrun:
11713 {
11714 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011715 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011716
Alexander Grafaecc8862014-11-10 21:33:03 +010011717 if (timerid < 0) {
11718 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011719 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011720 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011721 ret = get_errno(timer_getoverrun(htimer));
11722 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011723 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011724 break;
11725 }
11726#endif
11727
11728#ifdef TARGET_NR_timer_delete
11729 case TARGET_NR_timer_delete:
11730 {
11731 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011732 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011733
Alexander Grafaecc8862014-11-10 21:33:03 +010011734 if (timerid < 0) {
11735 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011736 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011737 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011738 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011739 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011740 }
11741 break;
11742 }
11743#endif
11744
Riku Voipio51834342014-06-22 11:25:42 +010011745#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11746 case TARGET_NR_timerfd_create:
11747 ret = get_errno(timerfd_create(arg1,
11748 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11749 break;
11750#endif
11751
11752#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11753 case TARGET_NR_timerfd_gettime:
11754 {
11755 struct itimerspec its_curr;
11756
11757 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11758
11759 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11760 goto efault;
11761 }
11762 }
11763 break;
11764#endif
11765
11766#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11767 case TARGET_NR_timerfd_settime:
11768 {
11769 struct itimerspec its_new, its_old, *p_new;
11770
11771 if (arg3) {
11772 if (target_to_host_itimerspec(&its_new, arg3)) {
11773 goto efault;
11774 }
11775 p_new = &its_new;
11776 } else {
11777 p_new = NULL;
11778 }
11779
11780 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11781
11782 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11783 goto efault;
11784 }
11785 }
11786 break;
11787#endif
11788
Paul Burtonab31cda2014-06-22 11:25:43 +010011789#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11790 case TARGET_NR_ioprio_get:
11791 ret = get_errno(ioprio_get(arg1, arg2));
11792 break;
11793#endif
11794
11795#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11796 case TARGET_NR_ioprio_set:
11797 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11798 break;
11799#endif
11800
Riku Voipio9af5c902014-08-12 15:58:57 +030011801#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11802 case TARGET_NR_setns:
11803 ret = get_errno(setns(arg1, arg2));
11804 break;
11805#endif
11806#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11807 case TARGET_NR_unshare:
11808 ret = get_errno(unshare(arg1));
11809 break;
11810#endif
11811
bellard31e31b82003-02-18 22:55:36 +000011812 default:
11813 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011814 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011815#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 +000011816 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011817#endif
ths0da46a62007-10-20 20:23:07 +000011818 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011819 break;
11820 }
bellard579a97f2007-11-11 14:26:47 +000011821fail:
bellardc573ff62004-01-04 15:51:36 +000011822#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011823 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011824#endif
thsb92c47c2007-11-01 00:07:38 +000011825 if(do_strace)
11826 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020011827 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000011828 return ret;
bellard579a97f2007-11-11 14:26:47 +000011829efault:
11830 ret = -TARGET_EFAULT;
11831 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011832}