blob: d2749a6648aa8213d262dd45e88d5e426be01c7e [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>
35#include <sys/mman.h>
36#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000037#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000038#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020039#ifdef __ia64__
40int __clone2(int (*fn)(void *), void *child_stack_base,
41 size_t stack_size, int flags, void *arg, ...);
42#endif
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000044#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000045#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000046#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000047#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000048#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000049#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000050#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000051#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000052#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020053#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000054//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000055#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000056#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020057#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000058#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020059#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030060#ifdef CONFIG_TIMERFD
61#include <sys/timerfd.h>
62#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020063#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000064#include <sys/gmon.h>
65#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030066#ifdef CONFIG_EVENTFD
67#include <sys/eventfd.h>
68#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000069#ifdef CONFIG_EPOLL
70#include <sys/epoll.h>
71#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070072#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010073#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070074#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000075#ifdef CONFIG_SENDFILE
76#include <sys/sendfile.h>
77#endif
bellard31e31b82003-02-18 22:55:36 +000078
79#define termios host_termios
80#define winsize host_winsize
81#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000082#define sgttyb host_sgttyb /* same as target */
83#define tchars host_tchars /* same as target */
84#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000085
86#include <linux/termios.h>
87#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000088#include <linux/cdrom.h>
89#include <linux/hdreg.h>
90#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000091#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000092#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030093#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000094#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000095#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000096#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020097#include <linux/fb.h>
98#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010099#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000100#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100101#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200102#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100103#include <linux/blkpg.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 Vivier575b22b2016-06-02 22:14:15 +0200107#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200108#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000109#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200110#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000111
bellard3ef693a2003-03-23 20:17:16 +0000112#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000113
pbrookd865bab2008-06-07 22:12:17 +0000114#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
115 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000116
bellard72f03902003-02-18 23:33:18 +0000117//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100118/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
119 * once. This exercises the codepaths for restart.
120 */
121//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000122
bellard1a9353d2003-03-16 20:28:50 +0000123//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000124#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
125#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000126
Peter Maydellb28a1f32016-05-27 15:51:47 +0100127/* This is the size of the host kernel's sigset_t, needed where we make
128 * direct system calls that take a sigset_t pointer and a size.
129 */
130#define SIGSET_T_SIZE (_NSIG / 8)
bellard70a194b2003-08-11 22:20:16 +0000131
bellard70a194b2003-08-11 22:20:16 +0000132#undef _syscall0
133#undef _syscall1
134#undef _syscall2
135#undef _syscall3
136#undef _syscall4
137#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000138#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000162}
163
bellard83fcb512006-06-14 13:37:16 +0000164#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000165static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000168}
169
bellard83fcb512006-06-14 13:37:16 +0000170#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
171 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000172static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000173{ \
174 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000175}
bellard83fcb512006-06-14 13:37:16 +0000176
177
178#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
179 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000180static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
181 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000182{ \
183 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
184}
185
bellard70a194b2003-08-11 22:20:16 +0000186
bellard31e31b82003-02-18 22:55:36 +0000187#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000188#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000189#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000190#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000191#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000192#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000193#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000194#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000195#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000196#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000197#define __NR_sys_inotify_init __NR_inotify_init
198#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
199#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000200
Alexander Graf42a39fb2011-04-15 17:32:45 +0200201#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
202 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000203#define __NR__llseek __NR_lseek
204#endif
205
James Hogana29e5ba2014-03-25 21:51:08 +0000206/* Newer kernel ports have llseek() instead of _llseek() */
207#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
208#define TARGET_NR__llseek TARGET_NR_llseek
209#endif
210
bellard72f03902003-02-18 23:33:18 +0000211#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000212_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000213#else
ths0da46a62007-10-20 20:23:07 +0000214/* This is a replacement for the host gettid() and must return a host
215 errno. */
bellard72f03902003-02-18 23:33:18 +0000216static int gettid(void) {
217 return -ENOSYS;
218}
219#endif
Chen Gang704eff62015-08-21 05:37:33 +0800220#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000221_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100222#endif
223#if !defined(__NR_getdents) || \
224 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000225_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
226#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700227#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000228_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
229 loff_t *, res, uint, wh);
230#endif
231_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
232_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
233#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
234_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
235#endif
236#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
237_syscall2(int,sys_tkill,int,tid,int,sig)
238#endif
239#ifdef __NR_exit_group
240_syscall1(int,exit_group,int,error_code)
241#endif
242#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
243_syscall1(int,set_tid_address,int *,tidptr)
244#endif
aurel323b3f24a2009-04-15 16:12:13 +0000245#if defined(TARGET_NR_futex) && defined(__NR_futex)
246_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
247 const struct timespec *,timeout,int *,uaddr2,int,val3)
248#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500249#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
250_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
251 unsigned long *, user_mask_ptr);
252#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
253_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
254 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200255_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
256 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000257_syscall2(int, capget, struct __user_cap_header_struct *, header,
258 struct __user_cap_data_struct *, data);
259_syscall2(int, capset, struct __user_cap_header_struct *, header,
260 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100261#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
262_syscall2(int, ioprio_get, int, which, int, who)
263#endif
264#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
265_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
266#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100267#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
268_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
269#endif
aurel323b3f24a2009-04-15 16:12:13 +0000270
271static bitmask_transtbl fcntl_flags_tbl[] = {
272 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
273 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
274 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
275 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
276 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
277 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
278 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
279 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700280 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000281 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
282 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
283 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
284 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000285#if defined(O_DIRECT)
286 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
287#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700288#if defined(O_NOATIME)
289 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
290#endif
291#if defined(O_CLOEXEC)
292 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
293#endif
294#if defined(O_PATH)
295 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
296#endif
297 /* Don't terminate the list prematurely on 64-bit host+guest. */
298#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
299 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
300#endif
aurel323b3f24a2009-04-15 16:12:13 +0000301 { 0, 0, 0, 0 }
302};
303
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100304typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100305typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200306typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100307 TargetFdDataFunc host_to_target_data;
308 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100309 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200310} TargetFdTrans;
311
312static TargetFdTrans **target_fd_trans;
313
314static unsigned int target_fd_max;
315
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200316static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
317{
318 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
319 return target_fd_trans[fd]->target_to_host_data;
320 }
321 return NULL;
322}
323
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100324static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200325{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100326 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100327 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200328 }
329 return NULL;
330}
331
Laurent Vivier7b36f782015-10-28 21:40:44 +0100332static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
333{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100334 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100335 return target_fd_trans[fd]->target_to_host_addr;
336 }
337 return NULL;
338}
339
Laurent Viviere36800c2015-10-02 14:48:09 +0200340static void fd_trans_register(int fd, TargetFdTrans *trans)
341{
342 unsigned int oldmax;
343
344 if (fd >= target_fd_max) {
345 oldmax = target_fd_max;
346 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100347 target_fd_trans = g_renew(TargetFdTrans *,
348 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200349 memset((void *)(target_fd_trans + oldmax), 0,
350 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
351 }
352 target_fd_trans[fd] = trans;
353}
354
355static void fd_trans_unregister(int fd)
356{
357 if (fd >= 0 && fd < target_fd_max) {
358 target_fd_trans[fd] = NULL;
359 }
360}
361
362static void fd_trans_dup(int oldfd, int newfd)
363{
364 fd_trans_unregister(newfd);
365 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
366 fd_trans_register(newfd, target_fd_trans[oldfd]);
367 }
368}
369
aurel323b3f24a2009-04-15 16:12:13 +0000370static int sys_getcwd1(char *buf, size_t size)
371{
372 if (getcwd(buf, size) == NULL) {
373 /* getcwd() sets errno */
374 return (-1);
375 }
aurel32aaf4ad32009-04-16 14:17:14 +0000376 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000377}
378
Peter Maydell1acae9f2013-07-02 14:04:12 +0100379#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300380#ifdef CONFIG_UTIMENSAT
381static int sys_utimensat(int dirfd, const char *pathname,
382 const struct timespec times[2], int flags)
383{
384 if (pathname == NULL)
385 return futimens(dirfd, times);
386 else
387 return utimensat(dirfd, pathname, times, flags);
388}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100389#elif defined(__NR_utimensat)
390#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000391_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
392 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100393#else
394static int sys_utimensat(int dirfd, const char *pathname,
395 const struct timespec times[2], int flags)
396{
397 errno = ENOSYS;
398 return -1;
399}
ths9007f0e2007-09-25 17:50:37 +0000400#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100401#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000402
403#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000404#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000405
aurel3239b59762008-10-01 21:46:50 +0000406#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000407static int sys_inotify_init(void)
408{
409 return (inotify_init());
410}
aurel3239b59762008-10-01 21:46:50 +0000411#endif
412#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000413static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
414{
415 return (inotify_add_watch(fd, pathname, mask));
416}
aurel3239b59762008-10-01 21:46:50 +0000417#endif
418#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000419static int sys_inotify_rm_watch(int fd, int32_t wd)
420{
aurel328690e422009-04-17 13:50:32 +0000421 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000422}
aurel3239b59762008-10-01 21:46:50 +0000423#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000424#ifdef CONFIG_INOTIFY1
425#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
426static int sys_inotify_init1(int flags)
427{
428 return (inotify_init1(flags));
429}
430#endif
431#endif
aurel323b3f24a2009-04-15 16:12:13 +0000432#else
433/* Userspace can usually survive runtime without inotify */
434#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000435#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000436#undef TARGET_NR_inotify_add_watch
437#undef TARGET_NR_inotify_rm_watch
438#endif /* CONFIG_INOTIFY */
439
Mike Frysingerd8035d42011-02-07 01:05:51 -0500440#if defined(TARGET_NR_ppoll)
441#ifndef __NR_ppoll
442# define __NR_ppoll -1
443#endif
444#define __NR_sys_ppoll __NR_ppoll
445_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200446 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500447 size_t, sigsetsize)
448#endif
bellard66fb9762003-03-23 01:06:05 +0000449
Peter Maydell163a05a2011-06-27 17:44:52 +0100450#if defined(TARGET_NR_prlimit64)
451#ifndef __NR_prlimit64
452# define __NR_prlimit64 -1
453#endif
454#define __NR_sys_prlimit64 __NR_prlimit64
455/* The glibc rlimit structure may not be that used by the underlying syscall */
456struct host_rlimit64 {
457 uint64_t rlim_cur;
458 uint64_t rlim_max;
459};
460_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
461 const struct host_rlimit64 *, new_limit,
462 struct host_rlimit64 *, old_limit)
463#endif
464
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100465
466#if defined(TARGET_NR_timer_create)
467/* Maxiumum of 32 active POSIX timers allowed at any one time. */
468static timer_t g_posix_timers[32] = { 0, } ;
469
470static inline int next_free_host_timer(void)
471{
472 int k ;
473 /* FIXME: Does finding the next free slot require a lock? */
474 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
475 if (g_posix_timers[k] == 0) {
476 g_posix_timers[k] = (timer_t) 1;
477 return k;
478 }
479 }
480 return -1;
481}
482#endif
483
Riku Voipio48e515d2011-07-12 15:40:51 +0300484/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000485#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300486static inline int regpairs_aligned(void *cpu_env) {
487 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
488}
489#elif defined(TARGET_MIPS)
490static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000491#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
492/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
493 * of registers which translates to the same as ARM/MIPS, because we start with
494 * r3 as arg1 */
495static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300496#else
497static inline int regpairs_aligned(void *cpu_env) { return 0; }
498#endif
499
thsb92c47c2007-11-01 00:07:38 +0000500#define ERRNO_TABLE_SIZE 1200
501
502/* target_to_host_errno_table[] is initialized from
503 * host_to_target_errno_table[] in syscall_init(). */
504static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
505};
506
ths637947f2007-06-01 12:09:19 +0000507/*
thsfe8f0962007-07-12 10:59:21 +0000508 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000509 * minus the errnos that are not actually generic to all archs.
510 */
thsb92c47c2007-11-01 00:07:38 +0000511static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800512 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000513 [EIDRM] = TARGET_EIDRM,
514 [ECHRNG] = TARGET_ECHRNG,
515 [EL2NSYNC] = TARGET_EL2NSYNC,
516 [EL3HLT] = TARGET_EL3HLT,
517 [EL3RST] = TARGET_EL3RST,
518 [ELNRNG] = TARGET_ELNRNG,
519 [EUNATCH] = TARGET_EUNATCH,
520 [ENOCSI] = TARGET_ENOCSI,
521 [EL2HLT] = TARGET_EL2HLT,
522 [EDEADLK] = TARGET_EDEADLK,
523 [ENOLCK] = TARGET_ENOLCK,
524 [EBADE] = TARGET_EBADE,
525 [EBADR] = TARGET_EBADR,
526 [EXFULL] = TARGET_EXFULL,
527 [ENOANO] = TARGET_ENOANO,
528 [EBADRQC] = TARGET_EBADRQC,
529 [EBADSLT] = TARGET_EBADSLT,
530 [EBFONT] = TARGET_EBFONT,
531 [ENOSTR] = TARGET_ENOSTR,
532 [ENODATA] = TARGET_ENODATA,
533 [ETIME] = TARGET_ETIME,
534 [ENOSR] = TARGET_ENOSR,
535 [ENONET] = TARGET_ENONET,
536 [ENOPKG] = TARGET_ENOPKG,
537 [EREMOTE] = TARGET_EREMOTE,
538 [ENOLINK] = TARGET_ENOLINK,
539 [EADV] = TARGET_EADV,
540 [ESRMNT] = TARGET_ESRMNT,
541 [ECOMM] = TARGET_ECOMM,
542 [EPROTO] = TARGET_EPROTO,
543 [EDOTDOT] = TARGET_EDOTDOT,
544 [EMULTIHOP] = TARGET_EMULTIHOP,
545 [EBADMSG] = TARGET_EBADMSG,
546 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
547 [EOVERFLOW] = TARGET_EOVERFLOW,
548 [ENOTUNIQ] = TARGET_ENOTUNIQ,
549 [EBADFD] = TARGET_EBADFD,
550 [EREMCHG] = TARGET_EREMCHG,
551 [ELIBACC] = TARGET_ELIBACC,
552 [ELIBBAD] = TARGET_ELIBBAD,
553 [ELIBSCN] = TARGET_ELIBSCN,
554 [ELIBMAX] = TARGET_ELIBMAX,
555 [ELIBEXEC] = TARGET_ELIBEXEC,
556 [EILSEQ] = TARGET_EILSEQ,
557 [ENOSYS] = TARGET_ENOSYS,
558 [ELOOP] = TARGET_ELOOP,
559 [ERESTART] = TARGET_ERESTART,
560 [ESTRPIPE] = TARGET_ESTRPIPE,
561 [ENOTEMPTY] = TARGET_ENOTEMPTY,
562 [EUSERS] = TARGET_EUSERS,
563 [ENOTSOCK] = TARGET_ENOTSOCK,
564 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
565 [EMSGSIZE] = TARGET_EMSGSIZE,
566 [EPROTOTYPE] = TARGET_EPROTOTYPE,
567 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
568 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
569 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
570 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
571 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
572 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
573 [EADDRINUSE] = TARGET_EADDRINUSE,
574 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
575 [ENETDOWN] = TARGET_ENETDOWN,
576 [ENETUNREACH] = TARGET_ENETUNREACH,
577 [ENETRESET] = TARGET_ENETRESET,
578 [ECONNABORTED] = TARGET_ECONNABORTED,
579 [ECONNRESET] = TARGET_ECONNRESET,
580 [ENOBUFS] = TARGET_ENOBUFS,
581 [EISCONN] = TARGET_EISCONN,
582 [ENOTCONN] = TARGET_ENOTCONN,
583 [EUCLEAN] = TARGET_EUCLEAN,
584 [ENOTNAM] = TARGET_ENOTNAM,
585 [ENAVAIL] = TARGET_ENAVAIL,
586 [EISNAM] = TARGET_EISNAM,
587 [EREMOTEIO] = TARGET_EREMOTEIO,
588 [ESHUTDOWN] = TARGET_ESHUTDOWN,
589 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
590 [ETIMEDOUT] = TARGET_ETIMEDOUT,
591 [ECONNREFUSED] = TARGET_ECONNREFUSED,
592 [EHOSTDOWN] = TARGET_EHOSTDOWN,
593 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
594 [EALREADY] = TARGET_EALREADY,
595 [EINPROGRESS] = TARGET_EINPROGRESS,
596 [ESTALE] = TARGET_ESTALE,
597 [ECANCELED] = TARGET_ECANCELED,
598 [ENOMEDIUM] = TARGET_ENOMEDIUM,
599 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000600#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000601 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000602#endif
603#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000604 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000605#endif
606#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000607 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000608#endif
609#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000610 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000611#endif
612#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000613 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000614#endif
615#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000616 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000617#endif
thsb92c47c2007-11-01 00:07:38 +0000618};
ths637947f2007-06-01 12:09:19 +0000619
620static inline int host_to_target_errno(int err)
621{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100622 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
623 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000624 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100625 }
ths637947f2007-06-01 12:09:19 +0000626 return err;
627}
628
thsb92c47c2007-11-01 00:07:38 +0000629static inline int target_to_host_errno(int err)
630{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100631 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
632 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000633 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100634 }
thsb92c47c2007-11-01 00:07:38 +0000635 return err;
636}
637
blueswir1992f48a2007-10-14 16:27:31 +0000638static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000639{
640 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000641 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000642 else
643 return ret;
644}
645
blueswir1992f48a2007-10-14 16:27:31 +0000646static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000647{
blueswir1992f48a2007-10-14 16:27:31 +0000648 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000649}
650
thsb92c47c2007-11-01 00:07:38 +0000651char *target_strerror(int err)
652{
Alexander Graf962b2892011-11-21 12:04:07 +0100653 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
654 return NULL;
655 }
thsb92c47c2007-11-01 00:07:38 +0000656 return strerror(target_to_host_errno(err));
657}
658
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100659#define safe_syscall0(type, name) \
660static type safe_##name(void) \
661{ \
662 return safe_syscall(__NR_##name); \
663}
664
665#define safe_syscall1(type, name, type1, arg1) \
666static type safe_##name(type1 arg1) \
667{ \
668 return safe_syscall(__NR_##name, arg1); \
669}
670
671#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
672static type safe_##name(type1 arg1, type2 arg2) \
673{ \
674 return safe_syscall(__NR_##name, arg1, arg2); \
675}
676
677#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
678static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
679{ \
680 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
681}
682
683#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
684 type4, arg4) \
685static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
686{ \
687 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
688}
689
690#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
691 type4, arg4, type5, arg5) \
692static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
693 type5 arg5) \
694{ \
695 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
696}
697
698#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
699 type4, arg4, type5, arg5, type6, arg6) \
700static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
701 type5 arg5, type6 arg6) \
702{ \
703 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
704}
705
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100706safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
707safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100708safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
709 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100710safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
711 struct rusage *, rusage)
712safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
713 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100714safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100715safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
716 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100717safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
718 const struct timespec *,timeout,int *,uaddr2,int,val3)
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100719
Paul Burton8289d112014-06-22 11:25:33 +0100720static inline int host_to_target_sock_type(int host_type)
721{
722 int target_type;
723
724 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
725 case SOCK_DGRAM:
726 target_type = TARGET_SOCK_DGRAM;
727 break;
728 case SOCK_STREAM:
729 target_type = TARGET_SOCK_STREAM;
730 break;
731 default:
732 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
733 break;
734 }
735
736#if defined(SOCK_CLOEXEC)
737 if (host_type & SOCK_CLOEXEC) {
738 target_type |= TARGET_SOCK_CLOEXEC;
739 }
740#endif
741
742#if defined(SOCK_NONBLOCK)
743 if (host_type & SOCK_NONBLOCK) {
744 target_type |= TARGET_SOCK_NONBLOCK;
745 }
746#endif
747
748 return target_type;
749}
750
blueswir1992f48a2007-10-14 16:27:31 +0000751static abi_ulong target_brk;
752static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000753static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000754
blueswir1992f48a2007-10-14 16:27:31 +0000755void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000756{
blueswir14c1de732007-07-07 20:45:44 +0000757 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000758 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000759}
760
vincent4d1de872011-06-14 21:56:33 +0000761//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
762#define DEBUGF_BRK(message, args...)
763
ths0da46a62007-10-20 20:23:07 +0000764/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000765abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000766{
blueswir1992f48a2007-10-14 16:27:31 +0000767 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000768 int new_alloc_size;
769
Paul Brook3a0c6c42012-02-09 19:04:27 +0000770 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000771
vincent4d1de872011-06-14 21:56:33 +0000772 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000773 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000774 return target_brk;
775 }
776 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000777 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
778 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000779 return target_brk;
780 }
bellard31e31b82003-02-18 22:55:36 +0000781
vincent4d1de872011-06-14 21:56:33 +0000782 /* If the new brk is less than the highest page reserved to the
783 * target heap allocation, set it and we're almost done... */
784 if (new_brk <= brk_page) {
785 /* Heap contents are initialized to zero, as for anonymous
786 * mapped pages. */
787 if (new_brk > target_brk) {
788 memset(g2h(target_brk), 0, new_brk - target_brk);
789 }
bellard31e31b82003-02-18 22:55:36 +0000790 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000791 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000792 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000793 }
794
Peter Maydell00faf082011-04-18 16:34:24 +0100795 /* We need to allocate more memory after the brk... Note that
796 * we don't use MAP_FIXED because that will map over the top of
797 * any existing mapping (like the one with the host libc or qemu
798 * itself); instead we treat "mapped but at wrong address" as
799 * a failure and unmap again.
800 */
vincent4d1de872011-06-14 21:56:33 +0000801 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000802 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000803 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100804 MAP_ANON|MAP_PRIVATE, 0, 0));
805
806 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200807 /* Heap contents are initialized to zero, as for anonymous
808 * mapped pages. Technically the new pages are already
809 * initialized to zero since they *are* anonymous mapped
810 * pages, however we have to take care with the contents that
811 * come from the remaining part of the previous page: it may
812 * contains garbage data due to a previous heap usage (grown
813 * then shrunken). */
814 memset(g2h(target_brk), 0, brk_page - target_brk);
815
Peter Maydell00faf082011-04-18 16:34:24 +0100816 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000817 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000818 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
819 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100820 return target_brk;
821 } else if (mapped_addr != -1) {
822 /* Mapped but at wrong address, meaning there wasn't actually
823 * enough space for this brk.
824 */
825 target_munmap(mapped_addr, new_alloc_size);
826 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000827 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000828 }
829 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000830 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100831 }
balrog7ab240a2008-04-26 12:17:34 +0000832
Richard Henderson7dd46c02010-05-03 10:07:49 -0700833#if defined(TARGET_ALPHA)
834 /* We (partially) emulate OSF/1 on Alpha, which requires we
835 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100836 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700837#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100838 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000839 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000840}
841
ths26edcf42007-12-09 02:25:24 +0000842static inline abi_long copy_from_user_fdset(fd_set *fds,
843 abi_ulong target_fds_addr,
844 int n)
bellard31e31b82003-02-18 22:55:36 +0000845{
ths26edcf42007-12-09 02:25:24 +0000846 int i, nw, j, k;
847 abi_ulong b, *target_fds;
848
849 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
850 if (!(target_fds = lock_user(VERIFY_READ,
851 target_fds_addr,
852 sizeof(abi_ulong) * nw,
853 1)))
854 return -TARGET_EFAULT;
855
856 FD_ZERO(fds);
857 k = 0;
858 for (i = 0; i < nw; i++) {
859 /* grab the abi_ulong */
860 __get_user(b, &target_fds[i]);
861 for (j = 0; j < TARGET_ABI_BITS; j++) {
862 /* check the bit inside the abi_ulong */
863 if ((b >> j) & 1)
864 FD_SET(k, fds);
865 k++;
bellard31e31b82003-02-18 22:55:36 +0000866 }
bellard31e31b82003-02-18 22:55:36 +0000867 }
ths26edcf42007-12-09 02:25:24 +0000868
869 unlock_user(target_fds, target_fds_addr, 0);
870
871 return 0;
bellard31e31b82003-02-18 22:55:36 +0000872}
873
Mike Frysinger055e0902011-06-03 17:01:49 -0400874static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
875 abi_ulong target_fds_addr,
876 int n)
877{
878 if (target_fds_addr) {
879 if (copy_from_user_fdset(fds, target_fds_addr, n))
880 return -TARGET_EFAULT;
881 *fds_ptr = fds;
882 } else {
883 *fds_ptr = NULL;
884 }
885 return 0;
886}
887
ths26edcf42007-12-09 02:25:24 +0000888static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
889 const fd_set *fds,
890 int n)
bellard31e31b82003-02-18 22:55:36 +0000891{
bellard31e31b82003-02-18 22:55:36 +0000892 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000893 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000894 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000895
ths26edcf42007-12-09 02:25:24 +0000896 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
897 if (!(target_fds = lock_user(VERIFY_WRITE,
898 target_fds_addr,
899 sizeof(abi_ulong) * nw,
900 0)))
901 return -TARGET_EFAULT;
902
903 k = 0;
904 for (i = 0; i < nw; i++) {
905 v = 0;
906 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000907 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000908 k++;
bellard31e31b82003-02-18 22:55:36 +0000909 }
ths26edcf42007-12-09 02:25:24 +0000910 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000911 }
ths26edcf42007-12-09 02:25:24 +0000912
913 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
914
915 return 0;
bellard31e31b82003-02-18 22:55:36 +0000916}
917
bellardc596ed12003-07-13 17:32:31 +0000918#if defined(__alpha__)
919#define HOST_HZ 1024
920#else
921#define HOST_HZ 100
922#endif
923
blueswir1992f48a2007-10-14 16:27:31 +0000924static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000925{
926#if HOST_HZ == TARGET_HZ
927 return ticks;
928#else
929 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
930#endif
931}
932
bellard579a97f2007-11-11 14:26:47 +0000933static inline abi_long host_to_target_rusage(abi_ulong target_addr,
934 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000935{
pbrook53a59602006-03-25 19:31:22 +0000936 struct target_rusage *target_rusage;
937
bellard579a97f2007-11-11 14:26:47 +0000938 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
939 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200940 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
941 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
942 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
943 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
944 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
945 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
946 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
947 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
948 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
949 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
950 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
951 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
952 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
953 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
954 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
955 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
956 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
957 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000958 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000959
960 return 0;
bellardb4091862003-05-16 15:39:34 +0000961}
962
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200963static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900964{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200965 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300966 rlim_t result;
967
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200968 target_rlim_swap = tswapal(target_rlim);
969 if (target_rlim_swap == TARGET_RLIM_INFINITY)
970 return RLIM_INFINITY;
971
972 result = target_rlim_swap;
973 if (target_rlim_swap != (rlim_t)result)
974 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300975
976 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900977}
978
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200979static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900980{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200981 abi_ulong target_rlim_swap;
982 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300983
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200984 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300985 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900986 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300987 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200988 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300989
990 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900991}
992
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300993static inline int target_to_host_resource(int code)
994{
995 switch (code) {
996 case TARGET_RLIMIT_AS:
997 return RLIMIT_AS;
998 case TARGET_RLIMIT_CORE:
999 return RLIMIT_CORE;
1000 case TARGET_RLIMIT_CPU:
1001 return RLIMIT_CPU;
1002 case TARGET_RLIMIT_DATA:
1003 return RLIMIT_DATA;
1004 case TARGET_RLIMIT_FSIZE:
1005 return RLIMIT_FSIZE;
1006 case TARGET_RLIMIT_LOCKS:
1007 return RLIMIT_LOCKS;
1008 case TARGET_RLIMIT_MEMLOCK:
1009 return RLIMIT_MEMLOCK;
1010 case TARGET_RLIMIT_MSGQUEUE:
1011 return RLIMIT_MSGQUEUE;
1012 case TARGET_RLIMIT_NICE:
1013 return RLIMIT_NICE;
1014 case TARGET_RLIMIT_NOFILE:
1015 return RLIMIT_NOFILE;
1016 case TARGET_RLIMIT_NPROC:
1017 return RLIMIT_NPROC;
1018 case TARGET_RLIMIT_RSS:
1019 return RLIMIT_RSS;
1020 case TARGET_RLIMIT_RTPRIO:
1021 return RLIMIT_RTPRIO;
1022 case TARGET_RLIMIT_SIGPENDING:
1023 return RLIMIT_SIGPENDING;
1024 case TARGET_RLIMIT_STACK:
1025 return RLIMIT_STACK;
1026 default:
1027 return code;
1028 }
1029}
1030
ths788f5ec2007-12-09 02:37:05 +00001031static inline abi_long copy_from_user_timeval(struct timeval *tv,
1032 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001033{
pbrook53a59602006-03-25 19:31:22 +00001034 struct target_timeval *target_tv;
1035
ths788f5ec2007-12-09 02:37:05 +00001036 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001037 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001038
1039 __get_user(tv->tv_sec, &target_tv->tv_sec);
1040 __get_user(tv->tv_usec, &target_tv->tv_usec);
1041
1042 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001043
1044 return 0;
bellard31e31b82003-02-18 22:55:36 +00001045}
1046
ths788f5ec2007-12-09 02:37:05 +00001047static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1048 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001049{
pbrook53a59602006-03-25 19:31:22 +00001050 struct target_timeval *target_tv;
1051
ths788f5ec2007-12-09 02:37:05 +00001052 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001053 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001054
1055 __put_user(tv->tv_sec, &target_tv->tv_sec);
1056 __put_user(tv->tv_usec, &target_tv->tv_usec);
1057
1058 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001059
1060 return 0;
bellard31e31b82003-02-18 22:55:36 +00001061}
1062
Paul Burtonef4467e2014-06-22 11:25:40 +01001063static inline abi_long copy_from_user_timezone(struct timezone *tz,
1064 abi_ulong target_tz_addr)
1065{
1066 struct target_timezone *target_tz;
1067
1068 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1069 return -TARGET_EFAULT;
1070 }
1071
1072 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1073 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1074
1075 unlock_user_struct(target_tz, target_tz_addr, 0);
1076
1077 return 0;
1078}
1079
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001080#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1081#include <mqueue.h>
1082
aurel3224e10032009-04-15 16:11:43 +00001083static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1084 abi_ulong target_mq_attr_addr)
1085{
1086 struct target_mq_attr *target_mq_attr;
1087
1088 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1089 target_mq_attr_addr, 1))
1090 return -TARGET_EFAULT;
1091
1092 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1093 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1094 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1095 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1096
1097 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1098
1099 return 0;
1100}
1101
1102static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1103 const struct mq_attr *attr)
1104{
1105 struct target_mq_attr *target_mq_attr;
1106
1107 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1108 target_mq_attr_addr, 0))
1109 return -TARGET_EFAULT;
1110
1111 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1112 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1113 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1114 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1115
1116 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1117
1118 return 0;
1119}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001120#endif
bellard31e31b82003-02-18 22:55:36 +00001121
Mike Frysinger055e0902011-06-03 17:01:49 -04001122#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001123/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001124static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001125 abi_ulong rfd_addr, abi_ulong wfd_addr,
1126 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001127{
1128 fd_set rfds, wfds, efds;
1129 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001130 struct timeval tv;
1131 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001132 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001133
Mike Frysinger055e0902011-06-03 17:01:49 -04001134 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1135 if (ret) {
1136 return ret;
pbrook53a59602006-03-25 19:31:22 +00001137 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001138 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1139 if (ret) {
1140 return ret;
pbrook53a59602006-03-25 19:31:22 +00001141 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001142 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1143 if (ret) {
1144 return ret;
pbrook53a59602006-03-25 19:31:22 +00001145 }
ths3b46e622007-09-17 08:09:54 +00001146
ths26edcf42007-12-09 02:25:24 +00001147 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001148 if (copy_from_user_timeval(&tv, target_tv_addr))
1149 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001150 ts.tv_sec = tv.tv_sec;
1151 ts.tv_nsec = tv.tv_usec * 1000;
1152 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001153 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001154 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001155 }
ths26edcf42007-12-09 02:25:24 +00001156
Peter Maydell6df9d382016-05-12 18:47:51 +01001157 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1158 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001159
ths26edcf42007-12-09 02:25:24 +00001160 if (!is_error(ret)) {
1161 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1162 return -TARGET_EFAULT;
1163 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1164 return -TARGET_EFAULT;
1165 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1166 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001167
Peter Maydell6df9d382016-05-12 18:47:51 +01001168 if (target_tv_addr) {
1169 tv.tv_sec = ts.tv_sec;
1170 tv.tv_usec = ts.tv_nsec / 1000;
1171 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1172 return -TARGET_EFAULT;
1173 }
1174 }
bellard31e31b82003-02-18 22:55:36 +00001175 }
bellard579a97f2007-11-11 14:26:47 +00001176
bellard31e31b82003-02-18 22:55:36 +00001177 return ret;
1178}
Mike Frysinger055e0902011-06-03 17:01:49 -04001179#endif
bellard31e31b82003-02-18 22:55:36 +00001180
Riku Voipio099d6b02009-05-05 12:10:04 +03001181static abi_long do_pipe2(int host_pipe[], int flags)
1182{
1183#ifdef CONFIG_PIPE2
1184 return pipe2(host_pipe, flags);
1185#else
1186 return -ENOSYS;
1187#endif
1188}
1189
Richard Hendersonfb41a662010-05-03 10:07:52 -07001190static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1191 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001192{
1193 int host_pipe[2];
1194 abi_long ret;
1195 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1196
1197 if (is_error(ret))
1198 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001199
1200 /* Several targets have special calling conventions for the original
1201 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1202 if (!is_pipe2) {
1203#if defined(TARGET_ALPHA)
1204 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1205 return host_pipe[0];
1206#elif defined(TARGET_MIPS)
1207 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1208 return host_pipe[0];
1209#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001210 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001211 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001212#elif defined(TARGET_SPARC)
1213 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1214 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001215#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001216 }
1217
Riku Voipio099d6b02009-05-05 12:10:04 +03001218 if (put_user_s32(host_pipe[0], pipedes)
1219 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1220 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001221 return get_errno(ret);
1222}
1223
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001224static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1225 abi_ulong target_addr,
1226 socklen_t len)
1227{
1228 struct target_ip_mreqn *target_smreqn;
1229
1230 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1231 if (!target_smreqn)
1232 return -TARGET_EFAULT;
1233 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1234 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1235 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001236 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001237 unlock_user(target_smreqn, target_addr, 0);
1238
1239 return 0;
1240}
1241
Laurent Vivier7b36f782015-10-28 21:40:44 +01001242static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001243 abi_ulong target_addr,
1244 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001245{
aurel32607175e2009-04-15 16:11:59 +00001246 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1247 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001248 struct target_sockaddr *target_saddr;
1249
Laurent Vivier7b36f782015-10-28 21:40:44 +01001250 if (fd_trans_target_to_host_addr(fd)) {
1251 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1252 }
1253
bellard579a97f2007-11-11 14:26:47 +00001254 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1255 if (!target_saddr)
1256 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001257
1258 sa_family = tswap16(target_saddr->sa_family);
1259
1260 /* Oops. The caller might send a incomplete sun_path; sun_path
1261 * must be terminated by \0 (see the manual page), but
1262 * unfortunately it is quite common to specify sockaddr_un
1263 * length as "strlen(x->sun_path)" while it should be
1264 * "strlen(...) + 1". We'll fix that here if needed.
1265 * Linux kernel has a similar feature.
1266 */
1267
1268 if (sa_family == AF_UNIX) {
1269 if (len < unix_maxlen && len > 0) {
1270 char *cp = (char*)target_saddr;
1271
1272 if ( cp[len-1] && !cp[len] )
1273 len++;
1274 }
1275 if (len > unix_maxlen)
1276 len = unix_maxlen;
1277 }
1278
pbrook53a59602006-03-25 19:31:22 +00001279 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001280 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001281 if (sa_family == AF_NETLINK) {
1282 struct sockaddr_nl *nladdr;
1283
1284 nladdr = (struct sockaddr_nl *)addr;
1285 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1286 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1287 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001288 struct target_sockaddr_ll *lladdr;
1289
1290 lladdr = (struct target_sockaddr_ll *)addr;
1291 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1292 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1293 }
pbrook53a59602006-03-25 19:31:22 +00001294 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001295
1296 return 0;
bellard7854b052003-03-29 17:22:23 +00001297}
1298
bellard579a97f2007-11-11 14:26:47 +00001299static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1300 struct sockaddr *addr,
1301 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001302{
pbrook53a59602006-03-25 19:31:22 +00001303 struct target_sockaddr *target_saddr;
1304
bellard579a97f2007-11-11 14:26:47 +00001305 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1306 if (!target_saddr)
1307 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001308 memcpy(target_saddr, addr, len);
1309 target_saddr->sa_family = tswap16(addr->sa_family);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001310 if (addr->sa_family == AF_NETLINK) {
1311 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1312 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1313 target_nl->nl_groups = tswap32(target_nl->nl_groups);
1314 }
pbrook53a59602006-03-25 19:31:22 +00001315 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001316
1317 return 0;
bellard7854b052003-03-29 17:22:23 +00001318}
1319
bellard5a4a8982007-11-11 17:39:18 +00001320static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1321 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001322{
1323 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001324 abi_long msg_controllen;
1325 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001326 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001327 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001328
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001329 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001330 if (msg_controllen < sizeof (struct target_cmsghdr))
1331 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001332 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001333 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001334 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001335 if (!target_cmsg)
1336 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001337
1338 while (cmsg && target_cmsg) {
1339 void *data = CMSG_DATA(cmsg);
1340 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1341
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001342 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001343 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1344
1345 space += CMSG_SPACE(len);
1346 if (space > msgh->msg_controllen) {
1347 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001348 /* This is a QEMU bug, since we allocated the payload
1349 * area ourselves (unlike overflow in host-to-target
1350 * conversion, which is just the guest giving us a buffer
1351 * that's too small). It can't happen for the payload types
1352 * we currently support; if it becomes an issue in future
1353 * we would need to improve our allocation strategy to
1354 * something more intelligent than "twice the size of the
1355 * target buffer we're reading from".
1356 */
bellard31febb72005-12-18 20:03:27 +00001357 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001358 break;
1359 }
1360
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001361 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1362 cmsg->cmsg_level = SOL_SOCKET;
1363 } else {
1364 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1365 }
bellard7854b052003-03-29 17:22:23 +00001366 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1367 cmsg->cmsg_len = CMSG_LEN(len);
1368
Alex Suykov30b8b682014-12-23 07:52:58 +02001369 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001370 int *fd = (int *)data;
1371 int *target_fd = (int *)target_data;
1372 int i, numfds = len / sizeof(int);
1373
Peter Maydell876e23c2015-05-26 19:46:32 +01001374 for (i = 0; i < numfds; i++) {
1375 __get_user(fd[i], target_fd + i);
1376 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001377 } else if (cmsg->cmsg_level == SOL_SOCKET
1378 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1379 struct ucred *cred = (struct ucred *)data;
1380 struct target_ucred *target_cred =
1381 (struct target_ucred *)target_data;
1382
Peter Maydell876e23c2015-05-26 19:46:32 +01001383 __get_user(cred->pid, &target_cred->pid);
1384 __get_user(cred->uid, &target_cred->uid);
1385 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001386 } else {
1387 gemu_log("Unsupported ancillary data: %d/%d\n",
1388 cmsg->cmsg_level, cmsg->cmsg_type);
1389 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001390 }
1391
1392 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001393 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1394 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001395 }
bellard5a4a8982007-11-11 17:39:18 +00001396 unlock_user(target_cmsg, target_cmsg_addr, 0);
1397 the_end:
bellard7854b052003-03-29 17:22:23 +00001398 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001399 return 0;
bellard7854b052003-03-29 17:22:23 +00001400}
1401
bellard5a4a8982007-11-11 17:39:18 +00001402static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1403 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001404{
1405 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001406 abi_long msg_controllen;
1407 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001408 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001409 socklen_t space = 0;
1410
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001411 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001412 if (msg_controllen < sizeof (struct target_cmsghdr))
1413 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001414 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001415 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001416 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001417 if (!target_cmsg)
1418 return -TARGET_EFAULT;
1419
bellard7854b052003-03-29 17:22:23 +00001420 while (cmsg && target_cmsg) {
1421 void *data = CMSG_DATA(cmsg);
1422 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1423
1424 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001425 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001426
Peter Maydellc2aeb252015-05-26 19:46:31 +01001427 /* We never copy a half-header but may copy half-data;
1428 * this is Linux's behaviour in put_cmsg(). Note that
1429 * truncation here is a guest problem (which we report
1430 * to the guest via the CTRUNC bit), unlike truncation
1431 * in target_to_host_cmsg, which is a QEMU bug.
1432 */
1433 if (msg_controllen < sizeof(struct cmsghdr)) {
1434 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001435 break;
1436 }
1437
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001438 if (cmsg->cmsg_level == SOL_SOCKET) {
1439 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1440 } else {
1441 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1442 }
bellard7854b052003-03-29 17:22:23 +00001443 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001444
Peter Maydellc2aeb252015-05-26 19:46:31 +01001445 tgt_len = TARGET_CMSG_LEN(len);
1446
1447 /* Payload types which need a different size of payload on
1448 * the target must adjust tgt_len here.
1449 */
1450 switch (cmsg->cmsg_level) {
1451 case SOL_SOCKET:
1452 switch (cmsg->cmsg_type) {
1453 case SO_TIMESTAMP:
1454 tgt_len = sizeof(struct target_timeval);
1455 break;
1456 default:
1457 break;
1458 }
1459 default:
1460 break;
1461 }
1462
1463 if (msg_controllen < tgt_len) {
1464 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1465 tgt_len = msg_controllen;
1466 }
1467
1468 /* We must now copy-and-convert len bytes of payload
1469 * into tgt_len bytes of destination space. Bear in mind
1470 * that in both source and destination we may be dealing
1471 * with a truncated value!
1472 */
Huw Davies52b65492014-04-17 14:02:47 +01001473 switch (cmsg->cmsg_level) {
1474 case SOL_SOCKET:
1475 switch (cmsg->cmsg_type) {
1476 case SCM_RIGHTS:
1477 {
1478 int *fd = (int *)data;
1479 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001480 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001481
Peter Maydell876e23c2015-05-26 19:46:32 +01001482 for (i = 0; i < numfds; i++) {
1483 __put_user(fd[i], target_fd + i);
1484 }
Huw Davies52b65492014-04-17 14:02:47 +01001485 break;
1486 }
1487 case SO_TIMESTAMP:
1488 {
1489 struct timeval *tv = (struct timeval *)data;
1490 struct target_timeval *target_tv =
1491 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001492
Peter Maydellc2aeb252015-05-26 19:46:31 +01001493 if (len != sizeof(struct timeval) ||
1494 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001495 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001496 }
Huw Davies52b65492014-04-17 14:02:47 +01001497
1498 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001499 __put_user(tv->tv_sec, &target_tv->tv_sec);
1500 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001501 break;
1502 }
Huw Davies4bc29752014-04-17 14:02:48 +01001503 case SCM_CREDENTIALS:
1504 {
1505 struct ucred *cred = (struct ucred *)data;
1506 struct target_ucred *target_cred =
1507 (struct target_ucred *)target_data;
1508
1509 __put_user(cred->pid, &target_cred->pid);
1510 __put_user(cred->uid, &target_cred->uid);
1511 __put_user(cred->gid, &target_cred->gid);
1512 break;
1513 }
Huw Davies52b65492014-04-17 14:02:47 +01001514 default:
1515 goto unimplemented;
1516 }
1517 break;
1518
1519 default:
1520 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001521 gemu_log("Unsupported ancillary data: %d/%d\n",
1522 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001523 memcpy(target_data, data, MIN(len, tgt_len));
1524 if (tgt_len > len) {
1525 memset(target_data + len, 0, tgt_len - len);
1526 }
bellard7854b052003-03-29 17:22:23 +00001527 }
1528
Peter Maydellc2aeb252015-05-26 19:46:31 +01001529 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001530 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001531 if (msg_controllen < tgt_space) {
1532 tgt_space = msg_controllen;
1533 }
1534 msg_controllen -= tgt_space;
1535 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001536 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001537 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1538 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001539 }
bellard5a4a8982007-11-11 17:39:18 +00001540 unlock_user(target_cmsg, target_cmsg_addr, space);
1541 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001542 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001543 return 0;
bellard7854b052003-03-29 17:22:23 +00001544}
1545
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001546static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1547{
1548 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1549 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1550 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1551 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1552 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1553}
1554
1555static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1556 size_t len,
1557 abi_long (*host_to_target_nlmsg)
1558 (struct nlmsghdr *))
1559{
1560 uint32_t nlmsg_len;
1561 abi_long ret;
1562
1563 while (len > sizeof(struct nlmsghdr)) {
1564
1565 nlmsg_len = nlh->nlmsg_len;
1566 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1567 nlmsg_len > len) {
1568 break;
1569 }
1570
1571 switch (nlh->nlmsg_type) {
1572 case NLMSG_DONE:
1573 tswap_nlmsghdr(nlh);
1574 return 0;
1575 case NLMSG_NOOP:
1576 break;
1577 case NLMSG_ERROR:
1578 {
1579 struct nlmsgerr *e = NLMSG_DATA(nlh);
1580 e->error = tswap32(e->error);
1581 tswap_nlmsghdr(&e->msg);
1582 tswap_nlmsghdr(nlh);
1583 return 0;
1584 }
1585 default:
1586 ret = host_to_target_nlmsg(nlh);
1587 if (ret < 0) {
1588 tswap_nlmsghdr(nlh);
1589 return ret;
1590 }
1591 break;
1592 }
1593 tswap_nlmsghdr(nlh);
1594 len -= NLMSG_ALIGN(nlmsg_len);
1595 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1596 }
1597 return 0;
1598}
1599
1600static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1601 size_t len,
1602 abi_long (*target_to_host_nlmsg)
1603 (struct nlmsghdr *))
1604{
1605 int ret;
1606
1607 while (len > sizeof(struct nlmsghdr)) {
1608 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1609 tswap32(nlh->nlmsg_len) > len) {
1610 break;
1611 }
1612 tswap_nlmsghdr(nlh);
1613 switch (nlh->nlmsg_type) {
1614 case NLMSG_DONE:
1615 return 0;
1616 case NLMSG_NOOP:
1617 break;
1618 case NLMSG_ERROR:
1619 {
1620 struct nlmsgerr *e = NLMSG_DATA(nlh);
1621 e->error = tswap32(e->error);
1622 tswap_nlmsghdr(&e->msg);
1623 }
1624 default:
1625 ret = target_to_host_nlmsg(nlh);
1626 if (ret < 0) {
1627 return ret;
1628 }
1629 }
1630 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1631 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1632 }
1633 return 0;
1634}
1635
Laurent Vivier575b22b2016-06-02 22:14:15 +02001636#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001637static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1638 size_t len,
1639 abi_long (*host_to_target_rtattr)
1640 (struct rtattr *))
1641{
1642 unsigned short rta_len;
1643 abi_long ret;
1644
1645 while (len > sizeof(struct rtattr)) {
1646 rta_len = rtattr->rta_len;
1647 if (rta_len < sizeof(struct rtattr) ||
1648 rta_len > len) {
1649 break;
1650 }
1651 ret = host_to_target_rtattr(rtattr);
1652 rtattr->rta_len = tswap16(rtattr->rta_len);
1653 rtattr->rta_type = tswap16(rtattr->rta_type);
1654 if (ret < 0) {
1655 return ret;
1656 }
1657 len -= RTA_ALIGN(rta_len);
1658 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1659 }
1660 return 0;
1661}
1662
1663static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
1664{
1665 uint32_t *u32;
1666 struct rtnl_link_stats *st;
1667 struct rtnl_link_stats64 *st64;
1668 struct rtnl_link_ifmap *map;
1669
1670 switch (rtattr->rta_type) {
1671 /* binary stream */
1672 case IFLA_ADDRESS:
1673 case IFLA_BROADCAST:
1674 /* string */
1675 case IFLA_IFNAME:
1676 case IFLA_QDISC:
1677 break;
1678 /* uin8_t */
1679 case IFLA_OPERSTATE:
1680 case IFLA_LINKMODE:
1681 case IFLA_CARRIER:
1682 case IFLA_PROTO_DOWN:
1683 break;
1684 /* uint32_t */
1685 case IFLA_MTU:
1686 case IFLA_LINK:
1687 case IFLA_WEIGHT:
1688 case IFLA_TXQLEN:
1689 case IFLA_CARRIER_CHANGES:
1690 case IFLA_NUM_RX_QUEUES:
1691 case IFLA_NUM_TX_QUEUES:
1692 case IFLA_PROMISCUITY:
1693 case IFLA_EXT_MASK:
1694 case IFLA_LINK_NETNSID:
1695 case IFLA_GROUP:
1696 case IFLA_MASTER:
1697 case IFLA_NUM_VF:
1698 u32 = RTA_DATA(rtattr);
1699 *u32 = tswap32(*u32);
1700 break;
1701 /* struct rtnl_link_stats */
1702 case IFLA_STATS:
1703 st = RTA_DATA(rtattr);
1704 st->rx_packets = tswap32(st->rx_packets);
1705 st->tx_packets = tswap32(st->tx_packets);
1706 st->rx_bytes = tswap32(st->rx_bytes);
1707 st->tx_bytes = tswap32(st->tx_bytes);
1708 st->rx_errors = tswap32(st->rx_errors);
1709 st->tx_errors = tswap32(st->tx_errors);
1710 st->rx_dropped = tswap32(st->rx_dropped);
1711 st->tx_dropped = tswap32(st->tx_dropped);
1712 st->multicast = tswap32(st->multicast);
1713 st->collisions = tswap32(st->collisions);
1714
1715 /* detailed rx_errors: */
1716 st->rx_length_errors = tswap32(st->rx_length_errors);
1717 st->rx_over_errors = tswap32(st->rx_over_errors);
1718 st->rx_crc_errors = tswap32(st->rx_crc_errors);
1719 st->rx_frame_errors = tswap32(st->rx_frame_errors);
1720 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
1721 st->rx_missed_errors = tswap32(st->rx_missed_errors);
1722
1723 /* detailed tx_errors */
1724 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
1725 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
1726 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
1727 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
1728 st->tx_window_errors = tswap32(st->tx_window_errors);
1729
1730 /* for cslip etc */
1731 st->rx_compressed = tswap32(st->rx_compressed);
1732 st->tx_compressed = tswap32(st->tx_compressed);
1733 break;
1734 /* struct rtnl_link_stats64 */
1735 case IFLA_STATS64:
1736 st64 = RTA_DATA(rtattr);
1737 st64->rx_packets = tswap64(st64->rx_packets);
1738 st64->tx_packets = tswap64(st64->tx_packets);
1739 st64->rx_bytes = tswap64(st64->rx_bytes);
1740 st64->tx_bytes = tswap64(st64->tx_bytes);
1741 st64->rx_errors = tswap64(st64->rx_errors);
1742 st64->tx_errors = tswap64(st64->tx_errors);
1743 st64->rx_dropped = tswap64(st64->rx_dropped);
1744 st64->tx_dropped = tswap64(st64->tx_dropped);
1745 st64->multicast = tswap64(st64->multicast);
1746 st64->collisions = tswap64(st64->collisions);
1747
1748 /* detailed rx_errors: */
1749 st64->rx_length_errors = tswap64(st64->rx_length_errors);
1750 st64->rx_over_errors = tswap64(st64->rx_over_errors);
1751 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
1752 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
1753 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
1754 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
1755
1756 /* detailed tx_errors */
1757 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
1758 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
1759 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
1760 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
1761 st64->tx_window_errors = tswap64(st64->tx_window_errors);
1762
1763 /* for cslip etc */
1764 st64->rx_compressed = tswap64(st64->rx_compressed);
1765 st64->tx_compressed = tswap64(st64->tx_compressed);
1766 break;
1767 /* struct rtnl_link_ifmap */
1768 case IFLA_MAP:
1769 map = RTA_DATA(rtattr);
1770 map->mem_start = tswap64(map->mem_start);
1771 map->mem_end = tswap64(map->mem_end);
1772 map->base_addr = tswap64(map->base_addr);
1773 map->irq = tswap16(map->irq);
1774 break;
1775 /* nested */
1776 case IFLA_AF_SPEC:
1777 case IFLA_LINKINFO:
1778 /* FIXME: implement nested type */
1779 gemu_log("Unimplemented nested type %d\n", rtattr->rta_type);
1780 break;
1781 default:
1782 gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type);
1783 break;
1784 }
1785 return 0;
1786}
1787
1788static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
1789{
1790 uint32_t *u32;
1791 struct ifa_cacheinfo *ci;
1792
1793 switch (rtattr->rta_type) {
1794 /* binary: depends on family type */
1795 case IFA_ADDRESS:
1796 case IFA_LOCAL:
1797 break;
1798 /* string */
1799 case IFA_LABEL:
1800 break;
1801 /* u32 */
1802 case IFA_FLAGS:
1803 case IFA_BROADCAST:
1804 u32 = RTA_DATA(rtattr);
1805 *u32 = tswap32(*u32);
1806 break;
1807 /* struct ifa_cacheinfo */
1808 case IFA_CACHEINFO:
1809 ci = RTA_DATA(rtattr);
1810 ci->ifa_prefered = tswap32(ci->ifa_prefered);
1811 ci->ifa_valid = tswap32(ci->ifa_valid);
1812 ci->cstamp = tswap32(ci->cstamp);
1813 ci->tstamp = tswap32(ci->tstamp);
1814 break;
1815 default:
1816 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
1817 break;
1818 }
1819 return 0;
1820}
1821
1822static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
1823{
1824 uint32_t *u32;
1825 switch (rtattr->rta_type) {
1826 /* binary: depends on family type */
1827 case RTA_GATEWAY:
1828 case RTA_DST:
1829 case RTA_PREFSRC:
1830 break;
1831 /* u32 */
1832 case RTA_PRIORITY:
1833 case RTA_TABLE:
1834 case RTA_OIF:
1835 u32 = RTA_DATA(rtattr);
1836 *u32 = tswap32(*u32);
1837 break;
1838 default:
1839 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
1840 break;
1841 }
1842 return 0;
1843}
1844
1845static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
1846 uint32_t rtattr_len)
1847{
1848 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1849 host_to_target_data_link_rtattr);
1850}
1851
1852static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
1853 uint32_t rtattr_len)
1854{
1855 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1856 host_to_target_data_addr_rtattr);
1857}
1858
1859static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
1860 uint32_t rtattr_len)
1861{
1862 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1863 host_to_target_data_route_rtattr);
1864}
1865
1866static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
1867{
1868 uint32_t nlmsg_len;
1869 struct ifinfomsg *ifi;
1870 struct ifaddrmsg *ifa;
1871 struct rtmsg *rtm;
1872
1873 nlmsg_len = nlh->nlmsg_len;
1874 switch (nlh->nlmsg_type) {
1875 case RTM_NEWLINK:
1876 case RTM_DELLINK:
1877 case RTM_GETLINK:
1878 ifi = NLMSG_DATA(nlh);
1879 ifi->ifi_type = tswap16(ifi->ifi_type);
1880 ifi->ifi_index = tswap32(ifi->ifi_index);
1881 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1882 ifi->ifi_change = tswap32(ifi->ifi_change);
1883 host_to_target_link_rtattr(IFLA_RTA(ifi),
1884 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1885 break;
1886 case RTM_NEWADDR:
1887 case RTM_DELADDR:
1888 case RTM_GETADDR:
1889 ifa = NLMSG_DATA(nlh);
1890 ifa->ifa_index = tswap32(ifa->ifa_index);
1891 host_to_target_addr_rtattr(IFA_RTA(ifa),
1892 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1893 break;
1894 case RTM_NEWROUTE:
1895 case RTM_DELROUTE:
1896 case RTM_GETROUTE:
1897 rtm = NLMSG_DATA(nlh);
1898 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1899 host_to_target_route_rtattr(RTM_RTA(rtm),
1900 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1901 break;
1902 default:
1903 return -TARGET_EINVAL;
1904 }
1905 return 0;
1906}
1907
1908static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1909 size_t len)
1910{
1911 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1912}
1913
1914static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1915 size_t len,
1916 abi_long (*target_to_host_rtattr)
1917 (struct rtattr *))
1918{
1919 abi_long ret;
1920
1921 while (len >= sizeof(struct rtattr)) {
1922 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
1923 tswap16(rtattr->rta_len) > len) {
1924 break;
1925 }
1926 rtattr->rta_len = tswap16(rtattr->rta_len);
1927 rtattr->rta_type = tswap16(rtattr->rta_type);
1928 ret = target_to_host_rtattr(rtattr);
1929 if (ret < 0) {
1930 return ret;
1931 }
1932 len -= RTA_ALIGN(rtattr->rta_len);
1933 rtattr = (struct rtattr *)(((char *)rtattr) +
1934 RTA_ALIGN(rtattr->rta_len));
1935 }
1936 return 0;
1937}
1938
1939static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
1940{
1941 switch (rtattr->rta_type) {
1942 default:
1943 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
1944 break;
1945 }
1946 return 0;
1947}
1948
1949static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
1950{
1951 switch (rtattr->rta_type) {
1952 /* binary: depends on family type */
1953 case IFA_LOCAL:
1954 case IFA_ADDRESS:
1955 break;
1956 default:
1957 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
1958 break;
1959 }
1960 return 0;
1961}
1962
1963static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
1964{
1965 uint32_t *u32;
1966 switch (rtattr->rta_type) {
1967 /* binary: depends on family type */
1968 case RTA_DST:
1969 case RTA_SRC:
1970 case RTA_GATEWAY:
1971 break;
1972 /* u32 */
1973 case RTA_OIF:
1974 u32 = RTA_DATA(rtattr);
1975 *u32 = tswap32(*u32);
1976 break;
1977 default:
1978 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
1979 break;
1980 }
1981 return 0;
1982}
1983
1984static void target_to_host_link_rtattr(struct rtattr *rtattr,
1985 uint32_t rtattr_len)
1986{
1987 target_to_host_for_each_rtattr(rtattr, rtattr_len,
1988 target_to_host_data_link_rtattr);
1989}
1990
1991static void target_to_host_addr_rtattr(struct rtattr *rtattr,
1992 uint32_t rtattr_len)
1993{
1994 target_to_host_for_each_rtattr(rtattr, rtattr_len,
1995 target_to_host_data_addr_rtattr);
1996}
1997
1998static void target_to_host_route_rtattr(struct rtattr *rtattr,
1999 uint32_t rtattr_len)
2000{
2001 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2002 target_to_host_data_route_rtattr);
2003}
2004
2005static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2006{
2007 struct ifinfomsg *ifi;
2008 struct ifaddrmsg *ifa;
2009 struct rtmsg *rtm;
2010
2011 switch (nlh->nlmsg_type) {
2012 case RTM_GETLINK:
2013 break;
2014 case RTM_NEWLINK:
2015 case RTM_DELLINK:
2016 ifi = NLMSG_DATA(nlh);
2017 ifi->ifi_type = tswap16(ifi->ifi_type);
2018 ifi->ifi_index = tswap32(ifi->ifi_index);
2019 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2020 ifi->ifi_change = tswap32(ifi->ifi_change);
2021 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2022 NLMSG_LENGTH(sizeof(*ifi)));
2023 break;
2024 case RTM_GETADDR:
2025 case RTM_NEWADDR:
2026 case RTM_DELADDR:
2027 ifa = NLMSG_DATA(nlh);
2028 ifa->ifa_index = tswap32(ifa->ifa_index);
2029 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2030 NLMSG_LENGTH(sizeof(*ifa)));
2031 break;
2032 case RTM_GETROUTE:
2033 break;
2034 case RTM_NEWROUTE:
2035 case RTM_DELROUTE:
2036 rtm = NLMSG_DATA(nlh);
2037 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2038 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2039 NLMSG_LENGTH(sizeof(*rtm)));
2040 break;
2041 default:
2042 return -TARGET_EOPNOTSUPP;
2043 }
2044 return 0;
2045}
2046
2047static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2048{
2049 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2050}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002051#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002052
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002053static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2054{
2055 switch (nlh->nlmsg_type) {
2056 default:
2057 gemu_log("Unknown host audit message type %d\n",
2058 nlh->nlmsg_type);
2059 return -TARGET_EINVAL;
2060 }
2061 return 0;
2062}
2063
2064static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2065 size_t len)
2066{
2067 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2068}
2069
2070static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2071{
2072 switch (nlh->nlmsg_type) {
2073 case AUDIT_USER:
2074 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2075 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2076 break;
2077 default:
2078 gemu_log("Unknown target audit message type %d\n",
2079 nlh->nlmsg_type);
2080 return -TARGET_EINVAL;
2081 }
2082
2083 return 0;
2084}
2085
2086static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2087{
2088 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2089}
2090
ths0da46a62007-10-20 20:23:07 +00002091/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002092static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002093 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002094{
blueswir1992f48a2007-10-14 16:27:31 +00002095 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002096 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002097 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002098 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002099
bellard8853f862004-02-22 14:57:26 +00002100 switch(level) {
2101 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002102 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002103 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002104 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002105
bellard2f619692007-11-16 10:46:05 +00002106 if (get_user_u32(val, optval_addr))
2107 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002108 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2109 break;
2110 case SOL_IP:
2111 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002112 case IP_TOS:
2113 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002114 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002115 case IP_ROUTER_ALERT:
2116 case IP_RECVOPTS:
2117 case IP_RETOPTS:
2118 case IP_PKTINFO:
2119 case IP_MTU_DISCOVER:
2120 case IP_RECVERR:
2121 case IP_RECVTOS:
2122#ifdef IP_FREEBIND
2123 case IP_FREEBIND:
2124#endif
2125 case IP_MULTICAST_TTL:
2126 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002127 val = 0;
2128 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002129 if (get_user_u32(val, optval_addr))
2130 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002131 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002132 if (get_user_u8(val, optval_addr))
2133 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002134 }
2135 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2136 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002137 case IP_ADD_MEMBERSHIP:
2138 case IP_DROP_MEMBERSHIP:
2139 if (optlen < sizeof (struct target_ip_mreq) ||
2140 optlen > sizeof (struct target_ip_mreqn))
2141 return -TARGET_EINVAL;
2142
2143 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2144 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2145 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2146 break;
2147
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002148 case IP_BLOCK_SOURCE:
2149 case IP_UNBLOCK_SOURCE:
2150 case IP_ADD_SOURCE_MEMBERSHIP:
2151 case IP_DROP_SOURCE_MEMBERSHIP:
2152 if (optlen != sizeof (struct target_ip_mreq_source))
2153 return -TARGET_EINVAL;
2154
2155 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2156 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2157 unlock_user (ip_mreq_source, optval_addr, 0);
2158 break;
2159
bellard8853f862004-02-22 14:57:26 +00002160 default:
2161 goto unimplemented;
2162 }
2163 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002164 case SOL_IPV6:
2165 switch (optname) {
2166 case IPV6_MTU_DISCOVER:
2167 case IPV6_MTU:
2168 case IPV6_V6ONLY:
2169 case IPV6_RECVPKTINFO:
2170 val = 0;
2171 if (optlen < sizeof(uint32_t)) {
2172 return -TARGET_EINVAL;
2173 }
2174 if (get_user_u32(val, optval_addr)) {
2175 return -TARGET_EFAULT;
2176 }
2177 ret = get_errno(setsockopt(sockfd, level, optname,
2178 &val, sizeof(val)));
2179 break;
2180 default:
2181 goto unimplemented;
2182 }
2183 break;
Jing Huang920394d2012-07-24 13:59:23 +00002184 case SOL_RAW:
2185 switch (optname) {
2186 case ICMP_FILTER:
2187 /* struct icmp_filter takes an u32 value */
2188 if (optlen < sizeof(uint32_t)) {
2189 return -TARGET_EINVAL;
2190 }
2191
2192 if (get_user_u32(val, optval_addr)) {
2193 return -TARGET_EFAULT;
2194 }
2195 ret = get_errno(setsockopt(sockfd, level, optname,
2196 &val, sizeof(val)));
2197 break;
2198
2199 default:
2200 goto unimplemented;
2201 }
2202 break;
bellard3532fa72006-06-24 15:06:03 +00002203 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002204 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002205 case TARGET_SO_RCVTIMEO:
2206 {
2207 struct timeval tv;
2208
2209 optname = SO_RCVTIMEO;
2210
2211set_timeout:
2212 if (optlen != sizeof(struct target_timeval)) {
2213 return -TARGET_EINVAL;
2214 }
2215
2216 if (copy_from_user_timeval(&tv, optval_addr)) {
2217 return -TARGET_EFAULT;
2218 }
2219
2220 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2221 &tv, sizeof(tv)));
2222 return ret;
2223 }
2224 case TARGET_SO_SNDTIMEO:
2225 optname = SO_SNDTIMEO;
2226 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002227 case TARGET_SO_ATTACH_FILTER:
2228 {
2229 struct target_sock_fprog *tfprog;
2230 struct target_sock_filter *tfilter;
2231 struct sock_fprog fprog;
2232 struct sock_filter *filter;
2233 int i;
2234
2235 if (optlen != sizeof(*tfprog)) {
2236 return -TARGET_EINVAL;
2237 }
2238 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2239 return -TARGET_EFAULT;
2240 }
2241 if (!lock_user_struct(VERIFY_READ, tfilter,
2242 tswapal(tfprog->filter), 0)) {
2243 unlock_user_struct(tfprog, optval_addr, 1);
2244 return -TARGET_EFAULT;
2245 }
2246
2247 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302248 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002249 if (filter == NULL) {
2250 unlock_user_struct(tfilter, tfprog->filter, 1);
2251 unlock_user_struct(tfprog, optval_addr, 1);
2252 return -TARGET_ENOMEM;
2253 }
2254 for (i = 0; i < fprog.len; i++) {
2255 filter[i].code = tswap16(tfilter[i].code);
2256 filter[i].jt = tfilter[i].jt;
2257 filter[i].jf = tfilter[i].jf;
2258 filter[i].k = tswap32(tfilter[i].k);
2259 }
2260 fprog.filter = filter;
2261
2262 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2263 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302264 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002265
2266 unlock_user_struct(tfilter, tfprog->filter, 1);
2267 unlock_user_struct(tfprog, optval_addr, 1);
2268 return ret;
2269 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002270 case TARGET_SO_BINDTODEVICE:
2271 {
2272 char *dev_ifname, *addr_ifname;
2273
2274 if (optlen > IFNAMSIZ - 1) {
2275 optlen = IFNAMSIZ - 1;
2276 }
2277 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2278 if (!dev_ifname) {
2279 return -TARGET_EFAULT;
2280 }
2281 optname = SO_BINDTODEVICE;
2282 addr_ifname = alloca(IFNAMSIZ);
2283 memcpy(addr_ifname, dev_ifname, optlen);
2284 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002285 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2286 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002287 unlock_user (dev_ifname, optval_addr, 0);
2288 return ret;
2289 }
bellard8853f862004-02-22 14:57:26 +00002290 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002291 case TARGET_SO_DEBUG:
2292 optname = SO_DEBUG;
2293 break;
2294 case TARGET_SO_REUSEADDR:
2295 optname = SO_REUSEADDR;
2296 break;
2297 case TARGET_SO_TYPE:
2298 optname = SO_TYPE;
2299 break;
2300 case TARGET_SO_ERROR:
2301 optname = SO_ERROR;
2302 break;
2303 case TARGET_SO_DONTROUTE:
2304 optname = SO_DONTROUTE;
2305 break;
2306 case TARGET_SO_BROADCAST:
2307 optname = SO_BROADCAST;
2308 break;
2309 case TARGET_SO_SNDBUF:
2310 optname = SO_SNDBUF;
2311 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002312 case TARGET_SO_SNDBUFFORCE:
2313 optname = SO_SNDBUFFORCE;
2314 break;
bellard3532fa72006-06-24 15:06:03 +00002315 case TARGET_SO_RCVBUF:
2316 optname = SO_RCVBUF;
2317 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002318 case TARGET_SO_RCVBUFFORCE:
2319 optname = SO_RCVBUFFORCE;
2320 break;
bellard3532fa72006-06-24 15:06:03 +00002321 case TARGET_SO_KEEPALIVE:
2322 optname = SO_KEEPALIVE;
2323 break;
2324 case TARGET_SO_OOBINLINE:
2325 optname = SO_OOBINLINE;
2326 break;
2327 case TARGET_SO_NO_CHECK:
2328 optname = SO_NO_CHECK;
2329 break;
2330 case TARGET_SO_PRIORITY:
2331 optname = SO_PRIORITY;
2332 break;
bellard5e83e8e2005-03-01 22:32:06 +00002333#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002334 case TARGET_SO_BSDCOMPAT:
2335 optname = SO_BSDCOMPAT;
2336 break;
bellard5e83e8e2005-03-01 22:32:06 +00002337#endif
bellard3532fa72006-06-24 15:06:03 +00002338 case TARGET_SO_PASSCRED:
2339 optname = SO_PASSCRED;
2340 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002341 case TARGET_SO_PASSSEC:
2342 optname = SO_PASSSEC;
2343 break;
bellard3532fa72006-06-24 15:06:03 +00002344 case TARGET_SO_TIMESTAMP:
2345 optname = SO_TIMESTAMP;
2346 break;
2347 case TARGET_SO_RCVLOWAT:
2348 optname = SO_RCVLOWAT;
2349 break;
bellard8853f862004-02-22 14:57:26 +00002350 break;
2351 default:
2352 goto unimplemented;
2353 }
bellard3532fa72006-06-24 15:06:03 +00002354 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002355 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002356
bellard2f619692007-11-16 10:46:05 +00002357 if (get_user_u32(val, optval_addr))
2358 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002359 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002360 break;
bellard7854b052003-03-29 17:22:23 +00002361 default:
bellard8853f862004-02-22 14:57:26 +00002362 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002363 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002364 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002365 }
bellard8853f862004-02-22 14:57:26 +00002366 return ret;
bellard7854b052003-03-29 17:22:23 +00002367}
2368
ths0da46a62007-10-20 20:23:07 +00002369/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002370static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002371 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002372{
blueswir1992f48a2007-10-14 16:27:31 +00002373 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002374 int len, val;
2375 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002376
2377 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002378 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002379 level = SOL_SOCKET;
2380 switch (optname) {
2381 /* These don't just return a single integer */
2382 case TARGET_SO_LINGER:
2383 case TARGET_SO_RCVTIMEO:
2384 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002385 case TARGET_SO_PEERNAME:
2386 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002387 case TARGET_SO_PEERCRED: {
2388 struct ucred cr;
2389 socklen_t crlen;
2390 struct target_ucred *tcr;
2391
2392 if (get_user_u32(len, optlen)) {
2393 return -TARGET_EFAULT;
2394 }
2395 if (len < 0) {
2396 return -TARGET_EINVAL;
2397 }
2398
2399 crlen = sizeof(cr);
2400 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2401 &cr, &crlen));
2402 if (ret < 0) {
2403 return ret;
2404 }
2405 if (len > crlen) {
2406 len = crlen;
2407 }
2408 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2409 return -TARGET_EFAULT;
2410 }
2411 __put_user(cr.pid, &tcr->pid);
2412 __put_user(cr.uid, &tcr->uid);
2413 __put_user(cr.gid, &tcr->gid);
2414 unlock_user_struct(tcr, optval_addr, 1);
2415 if (put_user_u32(len, optlen)) {
2416 return -TARGET_EFAULT;
2417 }
2418 break;
2419 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002420 /* Options with 'int' argument. */
2421 case TARGET_SO_DEBUG:
2422 optname = SO_DEBUG;
2423 goto int_case;
2424 case TARGET_SO_REUSEADDR:
2425 optname = SO_REUSEADDR;
2426 goto int_case;
2427 case TARGET_SO_TYPE:
2428 optname = SO_TYPE;
2429 goto int_case;
2430 case TARGET_SO_ERROR:
2431 optname = SO_ERROR;
2432 goto int_case;
2433 case TARGET_SO_DONTROUTE:
2434 optname = SO_DONTROUTE;
2435 goto int_case;
2436 case TARGET_SO_BROADCAST:
2437 optname = SO_BROADCAST;
2438 goto int_case;
2439 case TARGET_SO_SNDBUF:
2440 optname = SO_SNDBUF;
2441 goto int_case;
2442 case TARGET_SO_RCVBUF:
2443 optname = SO_RCVBUF;
2444 goto int_case;
2445 case TARGET_SO_KEEPALIVE:
2446 optname = SO_KEEPALIVE;
2447 goto int_case;
2448 case TARGET_SO_OOBINLINE:
2449 optname = SO_OOBINLINE;
2450 goto int_case;
2451 case TARGET_SO_NO_CHECK:
2452 optname = SO_NO_CHECK;
2453 goto int_case;
2454 case TARGET_SO_PRIORITY:
2455 optname = SO_PRIORITY;
2456 goto int_case;
2457#ifdef SO_BSDCOMPAT
2458 case TARGET_SO_BSDCOMPAT:
2459 optname = SO_BSDCOMPAT;
2460 goto int_case;
2461#endif
2462 case TARGET_SO_PASSCRED:
2463 optname = SO_PASSCRED;
2464 goto int_case;
2465 case TARGET_SO_TIMESTAMP:
2466 optname = SO_TIMESTAMP;
2467 goto int_case;
2468 case TARGET_SO_RCVLOWAT:
2469 optname = SO_RCVLOWAT;
2470 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002471 case TARGET_SO_ACCEPTCONN:
2472 optname = SO_ACCEPTCONN;
2473 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002474 default:
bellard2efbe912005-07-23 15:10:20 +00002475 goto int_case;
2476 }
2477 break;
2478 case SOL_TCP:
2479 /* TCP options all take an 'int' value. */
2480 int_case:
bellard2f619692007-11-16 10:46:05 +00002481 if (get_user_u32(len, optlen))
2482 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002483 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002484 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002485 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002486 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2487 if (ret < 0)
2488 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002489 if (optname == SO_TYPE) {
2490 val = host_to_target_sock_type(val);
2491 }
bellard2efbe912005-07-23 15:10:20 +00002492 if (len > lv)
2493 len = lv;
bellard2f619692007-11-16 10:46:05 +00002494 if (len == 4) {
2495 if (put_user_u32(val, optval_addr))
2496 return -TARGET_EFAULT;
2497 } else {
2498 if (put_user_u8(val, optval_addr))
2499 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002500 }
bellard2f619692007-11-16 10:46:05 +00002501 if (put_user_u32(len, optlen))
2502 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002503 break;
2504 case SOL_IP:
2505 switch(optname) {
2506 case IP_TOS:
2507 case IP_TTL:
2508 case IP_HDRINCL:
2509 case IP_ROUTER_ALERT:
2510 case IP_RECVOPTS:
2511 case IP_RETOPTS:
2512 case IP_PKTINFO:
2513 case IP_MTU_DISCOVER:
2514 case IP_RECVERR:
2515 case IP_RECVTOS:
2516#ifdef IP_FREEBIND
2517 case IP_FREEBIND:
2518#endif
2519 case IP_MULTICAST_TTL:
2520 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002521 if (get_user_u32(len, optlen))
2522 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002523 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002524 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002525 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002526 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2527 if (ret < 0)
2528 return ret;
bellard2efbe912005-07-23 15:10:20 +00002529 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002530 len = 1;
bellard2f619692007-11-16 10:46:05 +00002531 if (put_user_u32(len, optlen)
2532 || put_user_u8(val, optval_addr))
2533 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002534 } else {
bellard2efbe912005-07-23 15:10:20 +00002535 if (len > sizeof(int))
2536 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002537 if (put_user_u32(len, optlen)
2538 || put_user_u32(val, optval_addr))
2539 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002540 }
bellard8853f862004-02-22 14:57:26 +00002541 break;
bellard2efbe912005-07-23 15:10:20 +00002542 default:
thsc02f4992007-12-18 02:39:59 +00002543 ret = -TARGET_ENOPROTOOPT;
2544 break;
bellard8853f862004-02-22 14:57:26 +00002545 }
2546 break;
2547 default:
2548 unimplemented:
2549 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2550 level, optname);
thsc02f4992007-12-18 02:39:59 +00002551 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002552 break;
2553 }
2554 return ret;
bellard7854b052003-03-29 17:22:23 +00002555}
2556
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002557static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2558 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002559{
2560 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002561 struct iovec *vec;
2562 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002563 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002564 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002565 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002566
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002567 if (count == 0) {
2568 errno = 0;
2569 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002570 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002571 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002572 errno = EINVAL;
2573 return NULL;
2574 }
2575
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302576 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002577 if (vec == NULL) {
2578 errno = ENOMEM;
2579 return NULL;
2580 }
2581
2582 target_vec = lock_user(VERIFY_READ, target_addr,
2583 count * sizeof(struct target_iovec), 1);
2584 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002585 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002586 goto fail2;
2587 }
2588
2589 /* ??? If host page size > target page size, this will result in a
2590 value larger than what we can actually support. */
2591 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2592 total_len = 0;
2593
2594 for (i = 0; i < count; i++) {
2595 abi_ulong base = tswapal(target_vec[i].iov_base);
2596 abi_long len = tswapal(target_vec[i].iov_len);
2597
2598 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002599 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002600 goto fail;
2601 } else if (len == 0) {
2602 /* Zero length pointer is ignored. */
2603 vec[i].iov_base = 0;
2604 } else {
2605 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002606 /* If the first buffer pointer is bad, this is a fault. But
2607 * subsequent bad buffers will result in a partial write; this
2608 * is realized by filling the vector with null pointers and
2609 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002610 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002611 if (i == 0) {
2612 err = EFAULT;
2613 goto fail;
2614 } else {
2615 bad_address = true;
2616 }
2617 }
2618 if (bad_address) {
2619 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002620 }
2621 if (len > max_len - total_len) {
2622 len = max_len - total_len;
2623 }
2624 }
2625 vec[i].iov_len = len;
2626 total_len += len;
2627 }
2628
2629 unlock_user(target_vec, target_addr, 0);
2630 return vec;
2631
2632 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002633 while (--i >= 0) {
2634 if (tswapal(target_vec[i].iov_len) > 0) {
2635 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2636 }
2637 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002638 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002639 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302640 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002641 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002642 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002643}
2644
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002645static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2646 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002647{
2648 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002649 int i;
2650
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002651 target_vec = lock_user(VERIFY_READ, target_addr,
2652 count * sizeof(struct target_iovec), 1);
2653 if (target_vec) {
2654 for (i = 0; i < count; i++) {
2655 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002656 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002657 if (len < 0) {
2658 break;
2659 }
balrogd732dcb2008-10-28 10:21:03 +00002660 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2661 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002662 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002663 }
bellard579a97f2007-11-11 14:26:47 +00002664
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302665 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002666}
2667
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002668static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002669{
2670 int host_type = 0;
2671 int target_type = *type;
2672
2673 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2674 case TARGET_SOCK_DGRAM:
2675 host_type = SOCK_DGRAM;
2676 break;
2677 case TARGET_SOCK_STREAM:
2678 host_type = SOCK_STREAM;
2679 break;
2680 default:
2681 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2682 break;
2683 }
2684 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002685#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002686 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002687#else
2688 return -TARGET_EINVAL;
2689#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002690 }
2691 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002692#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002693 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002694#elif !defined(O_NONBLOCK)
2695 return -TARGET_EINVAL;
2696#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002697 }
2698 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002699 return 0;
2700}
2701
2702/* Try to emulate socket type flags after socket creation. */
2703static int sock_flags_fixup(int fd, int target_type)
2704{
2705#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2706 if (target_type & TARGET_SOCK_NONBLOCK) {
2707 int flags = fcntl(fd, F_GETFL);
2708 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2709 close(fd);
2710 return -TARGET_EINVAL;
2711 }
2712 }
2713#endif
2714 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002715}
2716
Laurent Vivier0cf22722015-10-28 21:40:45 +01002717static abi_long packet_target_to_host_sockaddr(void *host_addr,
2718 abi_ulong target_addr,
2719 socklen_t len)
2720{
2721 struct sockaddr *addr = host_addr;
2722 struct target_sockaddr *target_saddr;
2723
2724 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2725 if (!target_saddr) {
2726 return -TARGET_EFAULT;
2727 }
2728
2729 memcpy(addr, target_saddr, len);
2730 addr->sa_family = tswap16(target_saddr->sa_family);
2731 /* spkt_protocol is big-endian */
2732
2733 unlock_user(target_saddr, target_addr, 0);
2734 return 0;
2735}
2736
2737static TargetFdTrans target_packet_trans = {
2738 .target_to_host_addr = packet_target_to_host_sockaddr,
2739};
2740
Laurent Vivier575b22b2016-06-02 22:14:15 +02002741#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002742static abi_long netlink_route_target_to_host(void *buf, size_t len)
2743{
2744 return target_to_host_nlmsg_route(buf, len);
2745}
2746
2747static abi_long netlink_route_host_to_target(void *buf, size_t len)
2748{
2749 return host_to_target_nlmsg_route(buf, len);
2750}
2751
2752static TargetFdTrans target_netlink_route_trans = {
2753 .target_to_host_data = netlink_route_target_to_host,
2754 .host_to_target_data = netlink_route_host_to_target,
2755};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002756#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002757
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002758static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2759{
2760 return target_to_host_nlmsg_audit(buf, len);
2761}
2762
2763static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2764{
2765 return host_to_target_nlmsg_audit(buf, len);
2766}
2767
2768static TargetFdTrans target_netlink_audit_trans = {
2769 .target_to_host_data = netlink_audit_target_to_host,
2770 .host_to_target_data = netlink_audit_host_to_target,
2771};
2772
ths0da46a62007-10-20 20:23:07 +00002773/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002774static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002775{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002776 int target_type = type;
2777 int ret;
2778
2779 ret = target_to_host_sock_type(&type);
2780 if (ret) {
2781 return ret;
2782 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002783
Laurent Vivier575b22b2016-06-02 22:14:15 +02002784 if (domain == PF_NETLINK && !(
2785#ifdef CONFIG_RTNETLINK
2786 protocol == NETLINK_ROUTE ||
2787#endif
2788 protocol == NETLINK_KOBJECT_UEVENT ||
2789 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002790 return -EPFNOSUPPORT;
2791 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002792
2793 if (domain == AF_PACKET ||
2794 (domain == AF_INET && type == SOCK_PACKET)) {
2795 protocol = tswap16(protocol);
2796 }
2797
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002798 ret = get_errno(socket(domain, type, protocol));
2799 if (ret >= 0) {
2800 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002801 if (type == SOCK_PACKET) {
2802 /* Manage an obsolete case :
2803 * if socket type is SOCK_PACKET, bind by name
2804 */
2805 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002806 } else if (domain == PF_NETLINK) {
2807 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002808#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002809 case NETLINK_ROUTE:
2810 fd_trans_register(ret, &target_netlink_route_trans);
2811 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002812#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002813 case NETLINK_KOBJECT_UEVENT:
2814 /* nothing to do: messages are strings */
2815 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002816 case NETLINK_AUDIT:
2817 fd_trans_register(ret, &target_netlink_audit_trans);
2818 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002819 default:
2820 g_assert_not_reached();
2821 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002822 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002823 }
2824 return ret;
bellard3532fa72006-06-24 15:06:03 +00002825}
2826
ths0da46a62007-10-20 20:23:07 +00002827/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002828static abi_long do_bind(int sockfd, abi_ulong target_addr,
2829 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002830{
aurel328f7aeaf2009-01-30 19:47:57 +00002831 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002832 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002833
Blue Swirl38724252010-09-18 05:53:14 +00002834 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002835 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002836 }
aurel328f7aeaf2009-01-30 19:47:57 +00002837
aurel32607175e2009-04-15 16:11:59 +00002838 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002839
Laurent Vivier7b36f782015-10-28 21:40:44 +01002840 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002841 if (ret)
2842 return ret;
2843
bellard3532fa72006-06-24 15:06:03 +00002844 return get_errno(bind(sockfd, addr, addrlen));
2845}
2846
ths0da46a62007-10-20 20:23:07 +00002847/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002848static abi_long do_connect(int sockfd, abi_ulong target_addr,
2849 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002850{
aurel328f7aeaf2009-01-30 19:47:57 +00002851 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002852 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002853
Blue Swirl38724252010-09-18 05:53:14 +00002854 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002855 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002856 }
aurel328f7aeaf2009-01-30 19:47:57 +00002857
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002858 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002859
Laurent Vivier7b36f782015-10-28 21:40:44 +01002860 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002861 if (ret)
2862 return ret;
2863
bellard3532fa72006-06-24 15:06:03 +00002864 return get_errno(connect(sockfd, addr, addrlen));
2865}
2866
Alexander Graff19e00d2014-03-02 19:36:42 +00002867/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2868static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2869 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002870{
balrog6de645c2008-10-28 10:26:29 +00002871 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002872 struct msghdr msg;
2873 int count;
2874 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002875 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002876
bellard3532fa72006-06-24 15:06:03 +00002877 if (msgp->msg_name) {
2878 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002879 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002880 ret = target_to_host_sockaddr(fd, msg.msg_name,
2881 tswapal(msgp->msg_name),
2882 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002883 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002884 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002885 }
bellard3532fa72006-06-24 15:06:03 +00002886 } else {
2887 msg.msg_name = NULL;
2888 msg.msg_namelen = 0;
2889 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002890 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002891 msg.msg_control = alloca(msg.msg_controllen);
2892 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002893
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002894 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002895 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002896 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2897 target_vec, count, send);
2898 if (vec == NULL) {
2899 ret = -host_to_target_errno(errno);
2900 goto out2;
2901 }
bellard3532fa72006-06-24 15:06:03 +00002902 msg.msg_iovlen = count;
2903 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002904
bellard3532fa72006-06-24 15:06:03 +00002905 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002906 if (fd_trans_target_to_host_data(fd)) {
2907 ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base,
2908 msg.msg_iov->iov_len);
2909 } else {
2910 ret = target_to_host_cmsg(&msg, msgp);
2911 }
2912 if (ret == 0) {
bellard5a4a8982007-11-11 17:39:18 +00002913 ret = get_errno(sendmsg(fd, &msg, flags));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002914 }
bellard3532fa72006-06-24 15:06:03 +00002915 } else {
2916 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002917 if (!is_error(ret)) {
2918 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002919 if (fd_trans_host_to_target_data(fd)) {
2920 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
2921 msg.msg_iov->iov_len);
2922 } else {
2923 ret = host_to_target_cmsg(msgp, &msg);
2924 }
Jing Huangca619062012-07-24 13:58:02 +00002925 if (!is_error(ret)) {
2926 msgp->msg_namelen = tswap32(msg.msg_namelen);
2927 if (msg.msg_name != NULL) {
2928 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2929 msg.msg_name, msg.msg_namelen);
2930 if (ret) {
2931 goto out;
2932 }
2933 }
2934
balrog6de645c2008-10-28 10:26:29 +00002935 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002936 }
balrog6de645c2008-10-28 10:26:29 +00002937 }
bellard3532fa72006-06-24 15:06:03 +00002938 }
Jing Huangca619062012-07-24 13:58:02 +00002939
2940out:
bellard3532fa72006-06-24 15:06:03 +00002941 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002942out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002943 return ret;
2944}
2945
2946static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2947 int flags, int send)
2948{
2949 abi_long ret;
2950 struct target_msghdr *msgp;
2951
2952 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2953 msgp,
2954 target_msg,
2955 send ? 1 : 0)) {
2956 return -TARGET_EFAULT;
2957 }
2958 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002959 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002960 return ret;
2961}
2962
Alexander Graff19e00d2014-03-02 19:36:42 +00002963/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2964 * so it might not have this *mmsg-specific flag either.
2965 */
2966#ifndef MSG_WAITFORONE
2967#define MSG_WAITFORONE 0x10000
2968#endif
2969
2970static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2971 unsigned int vlen, unsigned int flags,
2972 int send)
2973{
2974 struct target_mmsghdr *mmsgp;
2975 abi_long ret = 0;
2976 int i;
2977
2978 if (vlen > UIO_MAXIOV) {
2979 vlen = UIO_MAXIOV;
2980 }
2981
2982 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2983 if (!mmsgp) {
2984 return -TARGET_EFAULT;
2985 }
2986
2987 for (i = 0; i < vlen; i++) {
2988 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2989 if (is_error(ret)) {
2990 break;
2991 }
2992 mmsgp[i].msg_len = tswap32(ret);
2993 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2994 if (flags & MSG_WAITFORONE) {
2995 flags |= MSG_DONTWAIT;
2996 }
2997 }
2998
2999 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3000
3001 /* Return number of datagrams sent if we sent any at all;
3002 * otherwise return the error.
3003 */
3004 if (i) {
3005 return i;
3006 }
3007 return ret;
3008}
Alexander Graff19e00d2014-03-02 19:36:42 +00003009
Peter Maydella94b4982013-02-08 04:35:04 +00003010/* If we don't have a system accept4() then just call accept.
3011 * The callsites to do_accept4() will ensure that they don't
3012 * pass a non-zero flags argument in this config.
3013 */
3014#ifndef CONFIG_ACCEPT4
3015static inline int accept4(int sockfd, struct sockaddr *addr,
3016 socklen_t *addrlen, int flags)
3017{
3018 assert(flags == 0);
3019 return accept(sockfd, addr, addrlen);
3020}
3021#endif
3022
3023/* do_accept4() Must return target values and target errnos. */
3024static abi_long do_accept4(int fd, abi_ulong target_addr,
3025 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003026{
bellard2f619692007-11-16 10:46:05 +00003027 socklen_t addrlen;
3028 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003029 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003030 int host_flags;
3031
3032 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003033
Peter Maydella94b4982013-02-08 04:35:04 +00003034 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003035 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003036 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003037
3038 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003039 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003040 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003041
Blue Swirl38724252010-09-18 05:53:14 +00003042 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003043 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003044 }
aurel328f7aeaf2009-01-30 19:47:57 +00003045
Arnaud Patard917507b2009-06-19 10:44:45 +03003046 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3047 return -TARGET_EINVAL;
3048
bellard2f619692007-11-16 10:46:05 +00003049 addr = alloca(addrlen);
3050
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003051 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003052 if (!is_error(ret)) {
3053 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003054 if (put_user_u32(addrlen, target_addrlen_addr))
3055 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003056 }
3057 return ret;
3058}
3059
ths0da46a62007-10-20 20:23:07 +00003060/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003061static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003062 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003063{
bellard2f619692007-11-16 10:46:05 +00003064 socklen_t addrlen;
3065 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003066 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003067
bellard2f619692007-11-16 10:46:05 +00003068 if (get_user_u32(addrlen, target_addrlen_addr))
3069 return -TARGET_EFAULT;
3070
Blue Swirl38724252010-09-18 05:53:14 +00003071 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003072 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003073 }
aurel328f7aeaf2009-01-30 19:47:57 +00003074
Arnaud Patard917507b2009-06-19 10:44:45 +03003075 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3076 return -TARGET_EFAULT;
3077
bellard2f619692007-11-16 10:46:05 +00003078 addr = alloca(addrlen);
3079
pbrook1be9e1d2006-11-19 15:26:04 +00003080 ret = get_errno(getpeername(fd, addr, &addrlen));
3081 if (!is_error(ret)) {
3082 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003083 if (put_user_u32(addrlen, target_addrlen_addr))
3084 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003085 }
3086 return ret;
3087}
3088
ths0da46a62007-10-20 20:23:07 +00003089/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003090static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003091 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003092{
bellard2f619692007-11-16 10:46:05 +00003093 socklen_t addrlen;
3094 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003095 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003096
bellard2f619692007-11-16 10:46:05 +00003097 if (get_user_u32(addrlen, target_addrlen_addr))
3098 return -TARGET_EFAULT;
3099
Blue Swirl38724252010-09-18 05:53:14 +00003100 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003101 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003102 }
aurel328f7aeaf2009-01-30 19:47:57 +00003103
Arnaud Patard917507b2009-06-19 10:44:45 +03003104 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3105 return -TARGET_EFAULT;
3106
bellard2f619692007-11-16 10:46:05 +00003107 addr = alloca(addrlen);
3108
pbrook1be9e1d2006-11-19 15:26:04 +00003109 ret = get_errno(getsockname(fd, addr, &addrlen));
3110 if (!is_error(ret)) {
3111 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003112 if (put_user_u32(addrlen, target_addrlen_addr))
3113 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003114 }
3115 return ret;
3116}
3117
ths0da46a62007-10-20 20:23:07 +00003118/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003119static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003120 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003121{
3122 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003123 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003124
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003125 target_to_host_sock_type(&type);
3126
pbrook1be9e1d2006-11-19 15:26:04 +00003127 ret = get_errno(socketpair(domain, type, protocol, tab));
3128 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003129 if (put_user_s32(tab[0], target_tab_addr)
3130 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3131 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003132 }
3133 return ret;
3134}
3135
ths0da46a62007-10-20 20:23:07 +00003136/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003137static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3138 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003139{
3140 void *addr;
3141 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003142 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003143
Blue Swirl38724252010-09-18 05:53:14 +00003144 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003145 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003146 }
aurel328f7aeaf2009-01-30 19:47:57 +00003147
bellard579a97f2007-11-11 14:26:47 +00003148 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3149 if (!host_msg)
3150 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003151 if (fd_trans_target_to_host_data(fd)) {
3152 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3153 if (ret < 0) {
3154 unlock_user(host_msg, msg, 0);
3155 return ret;
3156 }
3157 }
pbrook1be9e1d2006-11-19 15:26:04 +00003158 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003159 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003160 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003161 if (ret) {
3162 unlock_user(host_msg, msg, 0);
3163 return ret;
3164 }
pbrook1be9e1d2006-11-19 15:26:04 +00003165 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
3166 } else {
3167 ret = get_errno(send(fd, host_msg, len, flags));
3168 }
3169 unlock_user(host_msg, msg, 0);
3170 return ret;
3171}
3172
ths0da46a62007-10-20 20:23:07 +00003173/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003174static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3175 abi_ulong target_addr,
3176 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003177{
3178 socklen_t addrlen;
3179 void *addr;
3180 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003181 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003182
bellard579a97f2007-11-11 14:26:47 +00003183 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3184 if (!host_msg)
3185 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003186 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003187 if (get_user_u32(addrlen, target_addrlen)) {
3188 ret = -TARGET_EFAULT;
3189 goto fail;
3190 }
Blue Swirl38724252010-09-18 05:53:14 +00003191 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003192 ret = -TARGET_EINVAL;
3193 goto fail;
3194 }
pbrook1be9e1d2006-11-19 15:26:04 +00003195 addr = alloca(addrlen);
3196 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
3197 } else {
3198 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00003199 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003200 }
3201 if (!is_error(ret)) {
3202 if (target_addr) {
3203 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003204 if (put_user_u32(addrlen, target_addrlen)) {
3205 ret = -TARGET_EFAULT;
3206 goto fail;
3207 }
pbrook1be9e1d2006-11-19 15:26:04 +00003208 }
3209 unlock_user(host_msg, msg, len);
3210 } else {
bellard2f619692007-11-16 10:46:05 +00003211fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003212 unlock_user(host_msg, msg, 0);
3213 }
3214 return ret;
3215}
3216
j_mayer32407102007-09-26 23:01:49 +00003217#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003218/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003219static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003220{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003221 static const unsigned ac[] = { /* number of arguments per call */
3222 [SOCKOP_socket] = 3, /* domain, type, protocol */
3223 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3224 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3225 [SOCKOP_listen] = 2, /* sockfd, backlog */
3226 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3227 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3228 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3229 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3230 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3231 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3232 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3233 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3234 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3235 [SOCKOP_shutdown] = 2, /* sockfd, how */
3236 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3237 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003238 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3239 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003240 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3241 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3242 };
3243 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003244
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003245 /* first, collect the arguments in a[] according to ac[] */
3246 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3247 unsigned i;
3248 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3249 for (i = 0; i < ac[num]; ++i) {
3250 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003251 return -TARGET_EFAULT;
3252 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003253 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003254 }
bellard2f619692007-11-16 10:46:05 +00003255
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003256 /* now when we have the args, actually handle the call */
3257 switch (num) {
3258 case SOCKOP_socket: /* domain, type, protocol */
3259 return do_socket(a[0], a[1], a[2]);
3260 case SOCKOP_bind: /* sockfd, addr, addrlen */
3261 return do_bind(a[0], a[1], a[2]);
3262 case SOCKOP_connect: /* sockfd, addr, addrlen */
3263 return do_connect(a[0], a[1], a[2]);
3264 case SOCKOP_listen: /* sockfd, backlog */
3265 return get_errno(listen(a[0], a[1]));
3266 case SOCKOP_accept: /* sockfd, addr, addrlen */
3267 return do_accept4(a[0], a[1], a[2], 0);
3268 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3269 return do_accept4(a[0], a[1], a[2], a[3]);
3270 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3271 return do_getsockname(a[0], a[1], a[2]);
3272 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3273 return do_getpeername(a[0], a[1], a[2]);
3274 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3275 return do_socketpair(a[0], a[1], a[2], a[3]);
3276 case SOCKOP_send: /* sockfd, msg, len, flags */
3277 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3278 case SOCKOP_recv: /* sockfd, msg, len, flags */
3279 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3280 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3281 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3282 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3283 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3284 case SOCKOP_shutdown: /* sockfd, how */
3285 return get_errno(shutdown(a[0], a[1]));
3286 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3287 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3288 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3289 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003290 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3291 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3292 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3293 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003294 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3295 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3296 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3297 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003298 default:
3299 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003300 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003301 }
bellard31e31b82003-02-18 22:55:36 +00003302}
j_mayer32407102007-09-26 23:01:49 +00003303#endif
bellard31e31b82003-02-18 22:55:36 +00003304
bellard8853f862004-02-22 14:57:26 +00003305#define N_SHM_REGIONS 32
3306
3307static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003308 abi_ulong start;
3309 abi_ulong size;
3310 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003311} shm_regions[N_SHM_REGIONS];
3312
ths3eb6b042007-06-03 14:26:27 +00003313struct target_semid_ds
3314{
3315 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003316 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003317#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003318 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003319#endif
blueswir1992f48a2007-10-14 16:27:31 +00003320 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003321#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003322 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003323#endif
blueswir1992f48a2007-10-14 16:27:31 +00003324 abi_ulong sem_nsems;
3325 abi_ulong __unused3;
3326 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003327};
3328
bellard579a97f2007-11-11 14:26:47 +00003329static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3330 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003331{
3332 struct target_ipc_perm *target_ip;
3333 struct target_semid_ds *target_sd;
3334
bellard579a97f2007-11-11 14:26:47 +00003335 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3336 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003337 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003338 host_ip->__key = tswap32(target_ip->__key);
3339 host_ip->uid = tswap32(target_ip->uid);
3340 host_ip->gid = tswap32(target_ip->gid);
3341 host_ip->cuid = tswap32(target_ip->cuid);
3342 host_ip->cgid = tswap32(target_ip->cgid);
3343#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3344 host_ip->mode = tswap32(target_ip->mode);
3345#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003346 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003347#endif
3348#if defined(TARGET_PPC)
3349 host_ip->__seq = tswap32(target_ip->__seq);
3350#else
3351 host_ip->__seq = tswap16(target_ip->__seq);
3352#endif
ths3eb6b042007-06-03 14:26:27 +00003353 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003354 return 0;
ths3eb6b042007-06-03 14:26:27 +00003355}
3356
bellard579a97f2007-11-11 14:26:47 +00003357static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3358 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003359{
3360 struct target_ipc_perm *target_ip;
3361 struct target_semid_ds *target_sd;
3362
bellard579a97f2007-11-11 14:26:47 +00003363 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3364 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003365 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003366 target_ip->__key = tswap32(host_ip->__key);
3367 target_ip->uid = tswap32(host_ip->uid);
3368 target_ip->gid = tswap32(host_ip->gid);
3369 target_ip->cuid = tswap32(host_ip->cuid);
3370 target_ip->cgid = tswap32(host_ip->cgid);
3371#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3372 target_ip->mode = tswap32(host_ip->mode);
3373#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003374 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003375#endif
3376#if defined(TARGET_PPC)
3377 target_ip->__seq = tswap32(host_ip->__seq);
3378#else
3379 target_ip->__seq = tswap16(host_ip->__seq);
3380#endif
ths3eb6b042007-06-03 14:26:27 +00003381 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003382 return 0;
ths3eb6b042007-06-03 14:26:27 +00003383}
3384
bellard579a97f2007-11-11 14:26:47 +00003385static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3386 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003387{
3388 struct target_semid_ds *target_sd;
3389
bellard579a97f2007-11-11 14:26:47 +00003390 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3391 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003392 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3393 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003394 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3395 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3396 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003397 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003398 return 0;
ths3eb6b042007-06-03 14:26:27 +00003399}
3400
bellard579a97f2007-11-11 14:26:47 +00003401static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3402 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003403{
3404 struct target_semid_ds *target_sd;
3405
bellard579a97f2007-11-11 14:26:47 +00003406 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3407 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003408 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003409 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003410 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3411 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3412 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003413 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003414 return 0;
ths3eb6b042007-06-03 14:26:27 +00003415}
3416
aurel32e5289082009-04-18 16:16:12 +00003417struct target_seminfo {
3418 int semmap;
3419 int semmni;
3420 int semmns;
3421 int semmnu;
3422 int semmsl;
3423 int semopm;
3424 int semume;
3425 int semusz;
3426 int semvmx;
3427 int semaem;
3428};
3429
3430static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3431 struct seminfo *host_seminfo)
3432{
3433 struct target_seminfo *target_seminfo;
3434 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3435 return -TARGET_EFAULT;
3436 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3437 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3438 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3439 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3440 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3441 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3442 __put_user(host_seminfo->semume, &target_seminfo->semume);
3443 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3444 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3445 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3446 unlock_user_struct(target_seminfo, target_addr, 1);
3447 return 0;
3448}
3449
thsfa294812007-02-02 22:05:00 +00003450union semun {
3451 int val;
ths3eb6b042007-06-03 14:26:27 +00003452 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003453 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003454 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003455};
3456
ths3eb6b042007-06-03 14:26:27 +00003457union target_semun {
3458 int val;
aurel32e5289082009-04-18 16:16:12 +00003459 abi_ulong buf;
3460 abi_ulong array;
3461 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003462};
3463
aurel32e5289082009-04-18 16:16:12 +00003464static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3465 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003466{
aurel32e5289082009-04-18 16:16:12 +00003467 int nsems;
3468 unsigned short *array;
3469 union semun semun;
3470 struct semid_ds semid_ds;
3471 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003472
aurel32e5289082009-04-18 16:16:12 +00003473 semun.buf = &semid_ds;
3474
3475 ret = semctl(semid, 0, IPC_STAT, semun);
3476 if (ret == -1)
3477 return get_errno(ret);
3478
3479 nsems = semid_ds.sem_nsems;
3480
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303481 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003482 if (!*host_array) {
3483 return -TARGET_ENOMEM;
3484 }
aurel32e5289082009-04-18 16:16:12 +00003485 array = lock_user(VERIFY_READ, target_addr,
3486 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003487 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303488 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003489 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003490 }
aurel32e5289082009-04-18 16:16:12 +00003491
3492 for(i=0; i<nsems; i++) {
3493 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003494 }
aurel32e5289082009-04-18 16:16:12 +00003495 unlock_user(array, target_addr, 0);
3496
bellard579a97f2007-11-11 14:26:47 +00003497 return 0;
ths3eb6b042007-06-03 14:26:27 +00003498}
3499
aurel32e5289082009-04-18 16:16:12 +00003500static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3501 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003502{
aurel32e5289082009-04-18 16:16:12 +00003503 int nsems;
3504 unsigned short *array;
3505 union semun semun;
3506 struct semid_ds semid_ds;
3507 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003508
aurel32e5289082009-04-18 16:16:12 +00003509 semun.buf = &semid_ds;
3510
3511 ret = semctl(semid, 0, IPC_STAT, semun);
3512 if (ret == -1)
3513 return get_errno(ret);
3514
3515 nsems = semid_ds.sem_nsems;
3516
3517 array = lock_user(VERIFY_WRITE, target_addr,
3518 nsems*sizeof(unsigned short), 0);
3519 if (!array)
3520 return -TARGET_EFAULT;
3521
3522 for(i=0; i<nsems; i++) {
3523 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003524 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303525 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003526 unlock_user(array, target_addr, 1);
3527
bellard579a97f2007-11-11 14:26:47 +00003528 return 0;
ths3eb6b042007-06-03 14:26:27 +00003529}
3530
aurel32e5289082009-04-18 16:16:12 +00003531static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003532 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003533{
Stefan Weild1c002b2015-02-08 15:40:58 +01003534 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003535 union semun arg;
3536 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303537 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003538 struct seminfo seminfo;
3539 abi_long ret = -TARGET_EINVAL;
3540 abi_long err;
3541 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003542
3543 switch( cmd ) {
3544 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003545 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003546 /* In 64 bit cross-endian situations, we will erroneously pick up
3547 * the wrong half of the union for the "val" element. To rectify
3548 * this, the entire 8-byte structure is byteswapped, followed by
3549 * a swap of the 4 byte val field. In other cases, the data is
3550 * already in proper host byte order. */
3551 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3552 target_su.buf = tswapal(target_su.buf);
3553 arg.val = tswap32(target_su.val);
3554 } else {
3555 arg.val = target_su.val;
3556 }
aurel32e5289082009-04-18 16:16:12 +00003557 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003558 break;
3559 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003560 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003561 err = target_to_host_semarray(semid, &array, target_su.array);
3562 if (err)
3563 return err;
3564 arg.array = array;
3565 ret = get_errno(semctl(semid, semnum, cmd, arg));
3566 err = host_to_target_semarray(semid, target_su.array, &array);
3567 if (err)
3568 return err;
ths3eb6b042007-06-03 14:26:27 +00003569 break;
3570 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003571 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003572 case SEM_STAT:
3573 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3574 if (err)
3575 return err;
3576 arg.buf = &dsarg;
3577 ret = get_errno(semctl(semid, semnum, cmd, arg));
3578 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3579 if (err)
3580 return err;
ths3eb6b042007-06-03 14:26:27 +00003581 break;
aurel32e5289082009-04-18 16:16:12 +00003582 case IPC_INFO:
3583 case SEM_INFO:
3584 arg.__buf = &seminfo;
3585 ret = get_errno(semctl(semid, semnum, cmd, arg));
3586 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3587 if (err)
3588 return err;
3589 break;
3590 case IPC_RMID:
3591 case GETPID:
3592 case GETNCNT:
3593 case GETZCNT:
3594 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3595 break;
ths3eb6b042007-06-03 14:26:27 +00003596 }
3597
3598 return ret;
3599}
3600
aurel32e5289082009-04-18 16:16:12 +00003601struct target_sembuf {
3602 unsigned short sem_num;
3603 short sem_op;
3604 short sem_flg;
3605};
3606
3607static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3608 abi_ulong target_addr,
3609 unsigned nsops)
3610{
3611 struct target_sembuf *target_sembuf;
3612 int i;
3613
3614 target_sembuf = lock_user(VERIFY_READ, target_addr,
3615 nsops*sizeof(struct target_sembuf), 1);
3616 if (!target_sembuf)
3617 return -TARGET_EFAULT;
3618
3619 for(i=0; i<nsops; i++) {
3620 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3621 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3622 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3623 }
3624
3625 unlock_user(target_sembuf, target_addr, 0);
3626
3627 return 0;
3628}
3629
3630static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3631{
3632 struct sembuf sops[nsops];
3633
3634 if (target_to_host_sembuf(sops, ptr, nsops))
3635 return -TARGET_EFAULT;
3636
Petar Jovanovicc7128c92013-03-21 07:57:36 +00003637 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00003638}
3639
ths1bc012f2007-06-03 14:27:49 +00003640struct target_msqid_ds
3641{
aurel321c54ff92008-10-13 21:08:44 +00003642 struct target_ipc_perm msg_perm;
3643 abi_ulong msg_stime;
3644#if TARGET_ABI_BITS == 32
3645 abi_ulong __unused1;
3646#endif
3647 abi_ulong msg_rtime;
3648#if TARGET_ABI_BITS == 32
3649 abi_ulong __unused2;
3650#endif
3651 abi_ulong msg_ctime;
3652#if TARGET_ABI_BITS == 32
3653 abi_ulong __unused3;
3654#endif
3655 abi_ulong __msg_cbytes;
3656 abi_ulong msg_qnum;
3657 abi_ulong msg_qbytes;
3658 abi_ulong msg_lspid;
3659 abi_ulong msg_lrpid;
3660 abi_ulong __unused4;
3661 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003662};
3663
bellard579a97f2007-11-11 14:26:47 +00003664static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3665 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003666{
3667 struct target_msqid_ds *target_md;
3668
bellard579a97f2007-11-11 14:26:47 +00003669 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3670 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003671 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3672 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003673 host_md->msg_stime = tswapal(target_md->msg_stime);
3674 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3675 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3676 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3677 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3678 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3679 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3680 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003681 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003682 return 0;
ths1bc012f2007-06-03 14:27:49 +00003683}
3684
bellard579a97f2007-11-11 14:26:47 +00003685static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3686 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003687{
3688 struct target_msqid_ds *target_md;
3689
bellard579a97f2007-11-11 14:26:47 +00003690 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3691 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003692 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3693 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003694 target_md->msg_stime = tswapal(host_md->msg_stime);
3695 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3696 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3697 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3698 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3699 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3700 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3701 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003702 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003703 return 0;
ths1bc012f2007-06-03 14:27:49 +00003704}
3705
aurel321c54ff92008-10-13 21:08:44 +00003706struct target_msginfo {
3707 int msgpool;
3708 int msgmap;
3709 int msgmax;
3710 int msgmnb;
3711 int msgmni;
3712 int msgssz;
3713 int msgtql;
3714 unsigned short int msgseg;
3715};
3716
3717static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3718 struct msginfo *host_msginfo)
3719{
3720 struct target_msginfo *target_msginfo;
3721 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3722 return -TARGET_EFAULT;
3723 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3724 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3725 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3726 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3727 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3728 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3729 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3730 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3731 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003732 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003733}
3734
3735static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003736{
3737 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003738 struct msginfo msginfo;
3739 abi_long ret = -TARGET_EINVAL;
3740
3741 cmd &= 0xff;
3742
3743 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003744 case IPC_STAT:
3745 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003746 case MSG_STAT:
3747 if (target_to_host_msqid_ds(&dsarg,ptr))
3748 return -TARGET_EFAULT;
3749 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3750 if (host_to_target_msqid_ds(ptr,&dsarg))
3751 return -TARGET_EFAULT;
3752 break;
3753 case IPC_RMID:
3754 ret = get_errno(msgctl(msgid, cmd, NULL));
3755 break;
3756 case IPC_INFO:
3757 case MSG_INFO:
3758 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3759 if (host_to_target_msginfo(ptr, &msginfo))
3760 return -TARGET_EFAULT;
3761 break;
ths1bc012f2007-06-03 14:27:49 +00003762 }
aurel321c54ff92008-10-13 21:08:44 +00003763
ths1bc012f2007-06-03 14:27:49 +00003764 return ret;
3765}
3766
3767struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003768 abi_long mtype;
3769 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003770};
3771
blueswir1992f48a2007-10-14 16:27:31 +00003772static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003773 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003774{
3775 struct target_msgbuf *target_mb;
3776 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003777 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003778
Tom Mustaedcc5f92014-08-12 13:53:37 -05003779 if (msgsz < 0) {
3780 return -TARGET_EINVAL;
3781 }
3782
bellard579a97f2007-11-11 14:26:47 +00003783 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3784 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303785 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003786 if (!host_mb) {
3787 unlock_user_struct(target_mb, msgp, 0);
3788 return -TARGET_ENOMEM;
3789 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003790 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003791 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00003792 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303793 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003794 unlock_user_struct(target_mb, msgp, 0);
3795
3796 return ret;
3797}
3798
blueswir1992f48a2007-10-14 16:27:31 +00003799static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003800 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003801 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003802{
3803 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003804 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003805 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003806 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003807
Peter Maydell99874f62016-05-20 19:00:56 +01003808 if (msgsz < 0) {
3809 return -TARGET_EINVAL;
3810 }
3811
bellard579a97f2007-11-11 14:26:47 +00003812 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3813 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003814
Peter Maydell415d8472016-05-20 19:00:57 +01003815 host_mb = g_try_malloc(msgsz + sizeof(long));
3816 if (!host_mb) {
3817 ret = -TARGET_ENOMEM;
3818 goto end;
3819 }
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003820 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003821
bellard579a97f2007-11-11 14:26:47 +00003822 if (ret > 0) {
3823 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3824 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3825 if (!target_mtext) {
3826 ret = -TARGET_EFAULT;
3827 goto end;
3828 }
aurel321c54ff92008-10-13 21:08:44 +00003829 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003830 unlock_user(target_mtext, target_mtext_addr, ret);
3831 }
aurel321c54ff92008-10-13 21:08:44 +00003832
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003833 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003834
bellard579a97f2007-11-11 14:26:47 +00003835end:
3836 if (target_mb)
3837 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003838 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003839 return ret;
3840}
3841
Riku Voipio88a8c982009-04-03 10:42:00 +03003842static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3843 abi_ulong target_addr)
3844{
3845 struct target_shmid_ds *target_sd;
3846
3847 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3848 return -TARGET_EFAULT;
3849 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3850 return -TARGET_EFAULT;
3851 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3852 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3853 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3854 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3855 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3856 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3857 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3858 unlock_user_struct(target_sd, target_addr, 0);
3859 return 0;
3860}
3861
3862static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3863 struct shmid_ds *host_sd)
3864{
3865 struct target_shmid_ds *target_sd;
3866
3867 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3868 return -TARGET_EFAULT;
3869 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3870 return -TARGET_EFAULT;
3871 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3872 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3873 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3874 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3875 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3876 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3877 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3878 unlock_user_struct(target_sd, target_addr, 1);
3879 return 0;
3880}
3881
3882struct target_shminfo {
3883 abi_ulong shmmax;
3884 abi_ulong shmmin;
3885 abi_ulong shmmni;
3886 abi_ulong shmseg;
3887 abi_ulong shmall;
3888};
3889
3890static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3891 struct shminfo *host_shminfo)
3892{
3893 struct target_shminfo *target_shminfo;
3894 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3895 return -TARGET_EFAULT;
3896 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3897 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3898 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3899 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3900 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3901 unlock_user_struct(target_shminfo, target_addr, 1);
3902 return 0;
3903}
3904
3905struct target_shm_info {
3906 int used_ids;
3907 abi_ulong shm_tot;
3908 abi_ulong shm_rss;
3909 abi_ulong shm_swp;
3910 abi_ulong swap_attempts;
3911 abi_ulong swap_successes;
3912};
3913
3914static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3915 struct shm_info *host_shm_info)
3916{
3917 struct target_shm_info *target_shm_info;
3918 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3919 return -TARGET_EFAULT;
3920 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3921 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3922 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3923 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3924 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3925 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3926 unlock_user_struct(target_shm_info, target_addr, 1);
3927 return 0;
3928}
3929
3930static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3931{
3932 struct shmid_ds dsarg;
3933 struct shminfo shminfo;
3934 struct shm_info shm_info;
3935 abi_long ret = -TARGET_EINVAL;
3936
3937 cmd &= 0xff;
3938
3939 switch(cmd) {
3940 case IPC_STAT:
3941 case IPC_SET:
3942 case SHM_STAT:
3943 if (target_to_host_shmid_ds(&dsarg, buf))
3944 return -TARGET_EFAULT;
3945 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3946 if (host_to_target_shmid_ds(buf, &dsarg))
3947 return -TARGET_EFAULT;
3948 break;
3949 case IPC_INFO:
3950 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3951 if (host_to_target_shminfo(buf, &shminfo))
3952 return -TARGET_EFAULT;
3953 break;
3954 case SHM_INFO:
3955 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3956 if (host_to_target_shm_info(buf, &shm_info))
3957 return -TARGET_EFAULT;
3958 break;
3959 case IPC_RMID:
3960 case SHM_LOCK:
3961 case SHM_UNLOCK:
3962 ret = get_errno(shmctl(shmid, cmd, NULL));
3963 break;
3964 }
3965
3966 return ret;
3967}
3968
3969static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3970{
3971 abi_long raddr;
3972 void *host_raddr;
3973 struct shmid_ds shm_info;
3974 int i,ret;
3975
3976 /* find out the length of the shared memory segment */
3977 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3978 if (is_error(ret)) {
3979 /* can't get length, bail out */
3980 return ret;
3981 }
3982
3983 mmap_lock();
3984
3985 if (shmaddr)
3986 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3987 else {
3988 abi_ulong mmap_start;
3989
3990 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3991
3992 if (mmap_start == -1) {
3993 errno = ENOMEM;
3994 host_raddr = (void *)-1;
3995 } else
3996 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3997 }
3998
3999 if (host_raddr == (void *)-1) {
4000 mmap_unlock();
4001 return get_errno((long)host_raddr);
4002 }
4003 raddr=h2g((unsigned long)host_raddr);
4004
4005 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4006 PAGE_VALID | PAGE_READ |
4007 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4008
4009 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004010 if (!shm_regions[i].in_use) {
4011 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004012 shm_regions[i].start = raddr;
4013 shm_regions[i].size = shm_info.shm_segsz;
4014 break;
4015 }
4016 }
4017
4018 mmap_unlock();
4019 return raddr;
4020
4021}
4022
4023static inline abi_long do_shmdt(abi_ulong shmaddr)
4024{
4025 int i;
4026
4027 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004028 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4029 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004030 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004031 break;
4032 }
4033 }
4034
4035 return get_errno(shmdt(g2h(shmaddr)));
4036}
4037
aurel321c54ff92008-10-13 21:08:44 +00004038#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004039/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004040/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004041static abi_long do_ipc(unsigned int call, abi_long first,
4042 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004043 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004044{
4045 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004046 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004047
4048 version = call >> 16;
4049 call &= 0xffff;
4050
4051 switch (call) {
thsfa294812007-02-02 22:05:00 +00004052 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004053 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004054 break;
4055
4056 case IPCOP_semget:
4057 ret = get_errno(semget(first, second, third));
4058 break;
4059
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004060 case IPCOP_semctl: {
4061 /* The semun argument to semctl is passed by value, so dereference the
4062 * ptr argument. */
4063 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004064 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004065 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004066 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004067 }
thsd96372e2007-02-02 22:05:44 +00004068
aurel321c54ff92008-10-13 21:08:44 +00004069 case IPCOP_msgget:
4070 ret = get_errno(msgget(first, second));
4071 break;
thsd96372e2007-02-02 22:05:44 +00004072
aurel321c54ff92008-10-13 21:08:44 +00004073 case IPCOP_msgsnd:
4074 ret = do_msgsnd(first, ptr, second, third);
4075 break;
thsd96372e2007-02-02 22:05:44 +00004076
aurel321c54ff92008-10-13 21:08:44 +00004077 case IPCOP_msgctl:
4078 ret = do_msgctl(first, second, ptr);
4079 break;
thsd96372e2007-02-02 22:05:44 +00004080
aurel321c54ff92008-10-13 21:08:44 +00004081 case IPCOP_msgrcv:
4082 switch (version) {
4083 case 0:
4084 {
4085 struct target_ipc_kludge {
4086 abi_long msgp;
4087 abi_long msgtyp;
4088 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004089
aurel321c54ff92008-10-13 21:08:44 +00004090 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4091 ret = -TARGET_EFAULT;
4092 break;
ths1bc012f2007-06-03 14:27:49 +00004093 }
aurel321c54ff92008-10-13 21:08:44 +00004094
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004095 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004096
4097 unlock_user_struct(tmp, ptr, 0);
4098 break;
4099 }
4100 default:
4101 ret = do_msgrcv(first, ptr, second, fifth, third);
4102 }
4103 break;
thsd96372e2007-02-02 22:05:44 +00004104
bellard8853f862004-02-22 14:57:26 +00004105 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004106 switch (version) {
4107 default:
bellard5a4a8982007-11-11 17:39:18 +00004108 {
4109 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004110 raddr = do_shmat(first, ptr, second);
4111 if (is_error(raddr))
4112 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004113 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004114 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004115 break;
4116 }
4117 case 1:
4118 ret = -TARGET_EINVAL;
4119 break;
bellard5a4a8982007-11-11 17:39:18 +00004120 }
bellard8853f862004-02-22 14:57:26 +00004121 break;
4122 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004123 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004124 break;
4125
4126 case IPCOP_shmget:
4127 /* IPC_* flag values are the same on all linux platforms */
4128 ret = get_errno(shmget(first, second, third));
4129 break;
4130
4131 /* IPC_* and SHM_* command values are the same on all linux platforms */
4132 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004133 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004134 break;
4135 default:
j_mayer32407102007-09-26 23:01:49 +00004136 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004137 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004138 break;
4139 }
4140 return ret;
4141}
j_mayer32407102007-09-26 23:01:49 +00004142#endif
bellard8853f862004-02-22 14:57:26 +00004143
bellard31e31b82003-02-18 22:55:36 +00004144/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004145
Blue Swirl001faf32009-05-13 17:53:17 +00004146#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004147#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4148enum {
4149#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004150STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004151};
4152#undef STRUCT
4153#undef STRUCT_SPECIAL
4154
Blue Swirl001faf32009-05-13 17:53:17 +00004155#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004156#define STRUCT_SPECIAL(name)
4157#include "syscall_types.h"
4158#undef STRUCT
4159#undef STRUCT_SPECIAL
4160
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004161typedef struct IOCTLEntry IOCTLEntry;
4162
4163typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004164 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004165
4166struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004167 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004168 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004169 const char *name;
4170 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004171 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004172 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004173};
bellard31e31b82003-02-18 22:55:36 +00004174
4175#define IOC_R 0x0001
4176#define IOC_W 0x0002
4177#define IOC_RW (IOC_R | IOC_W)
4178
4179#define MAX_STRUCT_SIZE 4096
4180
Peter Maydelldace20d2011-01-10 13:11:24 +00004181#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004182/* So fiemap access checks don't overflow on 32 bit systems.
4183 * This is very slightly smaller than the limit imposed by
4184 * the underlying kernel.
4185 */
4186#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4187 / sizeof(struct fiemap_extent))
4188
4189static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004190 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004191{
4192 /* The parameter for this ioctl is a struct fiemap followed
4193 * by an array of struct fiemap_extent whose size is set
4194 * in fiemap->fm_extent_count. The array is filled in by the
4195 * ioctl.
4196 */
4197 int target_size_in, target_size_out;
4198 struct fiemap *fm;
4199 const argtype *arg_type = ie->arg_type;
4200 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4201 void *argptr, *p;
4202 abi_long ret;
4203 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4204 uint32_t outbufsz;
4205 int free_fm = 0;
4206
4207 assert(arg_type[0] == TYPE_PTR);
4208 assert(ie->access == IOC_RW);
4209 arg_type++;
4210 target_size_in = thunk_type_size(arg_type, 0);
4211 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4212 if (!argptr) {
4213 return -TARGET_EFAULT;
4214 }
4215 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4216 unlock_user(argptr, arg, 0);
4217 fm = (struct fiemap *)buf_temp;
4218 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4219 return -TARGET_EINVAL;
4220 }
4221
4222 outbufsz = sizeof (*fm) +
4223 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4224
4225 if (outbufsz > MAX_STRUCT_SIZE) {
4226 /* We can't fit all the extents into the fixed size buffer.
4227 * Allocate one that is large enough and use it instead.
4228 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304229 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004230 if (!fm) {
4231 return -TARGET_ENOMEM;
4232 }
4233 memcpy(fm, buf_temp, sizeof(struct fiemap));
4234 free_fm = 1;
4235 }
4236 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
4237 if (!is_error(ret)) {
4238 target_size_out = target_size_in;
4239 /* An extent_count of 0 means we were only counting the extents
4240 * so there are no structs to copy
4241 */
4242 if (fm->fm_extent_count != 0) {
4243 target_size_out += fm->fm_mapped_extents * extent_size;
4244 }
4245 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4246 if (!argptr) {
4247 ret = -TARGET_EFAULT;
4248 } else {
4249 /* Convert the struct fiemap */
4250 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4251 if (fm->fm_extent_count != 0) {
4252 p = argptr + target_size_in;
4253 /* ...and then all the struct fiemap_extents */
4254 for (i = 0; i < fm->fm_mapped_extents; i++) {
4255 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4256 THUNK_TARGET);
4257 p += extent_size;
4258 }
4259 }
4260 unlock_user(argptr, arg, target_size_out);
4261 }
4262 }
4263 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304264 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004265 }
4266 return ret;
4267}
Peter Maydelldace20d2011-01-10 13:11:24 +00004268#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004269
Laurent Vivier059c2f22011-03-30 00:12:12 +02004270static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004271 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004272{
4273 const argtype *arg_type = ie->arg_type;
4274 int target_size;
4275 void *argptr;
4276 int ret;
4277 struct ifconf *host_ifconf;
4278 uint32_t outbufsz;
4279 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4280 int target_ifreq_size;
4281 int nb_ifreq;
4282 int free_buf = 0;
4283 int i;
4284 int target_ifc_len;
4285 abi_long target_ifc_buf;
4286 int host_ifc_len;
4287 char *host_ifc_buf;
4288
4289 assert(arg_type[0] == TYPE_PTR);
4290 assert(ie->access == IOC_RW);
4291
4292 arg_type++;
4293 target_size = thunk_type_size(arg_type, 0);
4294
4295 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4296 if (!argptr)
4297 return -TARGET_EFAULT;
4298 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4299 unlock_user(argptr, arg, 0);
4300
4301 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4302 target_ifc_len = host_ifconf->ifc_len;
4303 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4304
4305 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4306 nb_ifreq = target_ifc_len / target_ifreq_size;
4307 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4308
4309 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4310 if (outbufsz > MAX_STRUCT_SIZE) {
4311 /* We can't fit all the extents into the fixed size buffer.
4312 * Allocate one that is large enough and use it instead.
4313 */
4314 host_ifconf = malloc(outbufsz);
4315 if (!host_ifconf) {
4316 return -TARGET_ENOMEM;
4317 }
4318 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4319 free_buf = 1;
4320 }
4321 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4322
4323 host_ifconf->ifc_len = host_ifc_len;
4324 host_ifconf->ifc_buf = host_ifc_buf;
4325
4326 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
4327 if (!is_error(ret)) {
4328 /* convert host ifc_len to target ifc_len */
4329
4330 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4331 target_ifc_len = nb_ifreq * target_ifreq_size;
4332 host_ifconf->ifc_len = target_ifc_len;
4333
4334 /* restore target ifc_buf */
4335
4336 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4337
4338 /* copy struct ifconf to target user */
4339
4340 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4341 if (!argptr)
4342 return -TARGET_EFAULT;
4343 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4344 unlock_user(argptr, arg, target_size);
4345
4346 /* copy ifreq[] to target user */
4347
4348 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4349 for (i = 0; i < nb_ifreq ; i++) {
4350 thunk_convert(argptr + i * target_ifreq_size,
4351 host_ifc_buf + i * sizeof(struct ifreq),
4352 ifreq_arg_type, THUNK_TARGET);
4353 }
4354 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4355 }
4356
4357 if (free_buf) {
4358 free(host_ifconf);
4359 }
4360
4361 return ret;
4362}
4363
Alexander Graf56e904e2012-01-31 18:42:06 +01004364static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004365 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004366{
4367 void *argptr;
4368 struct dm_ioctl *host_dm;
4369 abi_long guest_data;
4370 uint32_t guest_data_size;
4371 int target_size;
4372 const argtype *arg_type = ie->arg_type;
4373 abi_long ret;
4374 void *big_buf = NULL;
4375 char *host_data;
4376
4377 arg_type++;
4378 target_size = thunk_type_size(arg_type, 0);
4379 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4380 if (!argptr) {
4381 ret = -TARGET_EFAULT;
4382 goto out;
4383 }
4384 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4385 unlock_user(argptr, arg, 0);
4386
4387 /* buf_temp is too small, so fetch things into a bigger buffer */
4388 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4389 memcpy(big_buf, buf_temp, target_size);
4390 buf_temp = big_buf;
4391 host_dm = big_buf;
4392
4393 guest_data = arg + host_dm->data_start;
4394 if ((guest_data - arg) < 0) {
4395 ret = -EINVAL;
4396 goto out;
4397 }
4398 guest_data_size = host_dm->data_size - host_dm->data_start;
4399 host_data = (char*)host_dm + host_dm->data_start;
4400
4401 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4402 switch (ie->host_cmd) {
4403 case DM_REMOVE_ALL:
4404 case DM_LIST_DEVICES:
4405 case DM_DEV_CREATE:
4406 case DM_DEV_REMOVE:
4407 case DM_DEV_SUSPEND:
4408 case DM_DEV_STATUS:
4409 case DM_DEV_WAIT:
4410 case DM_TABLE_STATUS:
4411 case DM_TABLE_CLEAR:
4412 case DM_TABLE_DEPS:
4413 case DM_LIST_VERSIONS:
4414 /* no input data */
4415 break;
4416 case DM_DEV_RENAME:
4417 case DM_DEV_SET_GEOMETRY:
4418 /* data contains only strings */
4419 memcpy(host_data, argptr, guest_data_size);
4420 break;
4421 case DM_TARGET_MSG:
4422 memcpy(host_data, argptr, guest_data_size);
4423 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4424 break;
4425 case DM_TABLE_LOAD:
4426 {
4427 void *gspec = argptr;
4428 void *cur_data = host_data;
4429 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4430 int spec_size = thunk_type_size(arg_type, 0);
4431 int i;
4432
4433 for (i = 0; i < host_dm->target_count; i++) {
4434 struct dm_target_spec *spec = cur_data;
4435 uint32_t next;
4436 int slen;
4437
4438 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4439 slen = strlen((char*)gspec + spec_size) + 1;
4440 next = spec->next;
4441 spec->next = sizeof(*spec) + slen;
4442 strcpy((char*)&spec[1], gspec + spec_size);
4443 gspec += next;
4444 cur_data += spec->next;
4445 }
4446 break;
4447 }
4448 default:
4449 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004450 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004451 goto out;
4452 }
4453 unlock_user(argptr, guest_data, 0);
4454
4455 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4456 if (!is_error(ret)) {
4457 guest_data = arg + host_dm->data_start;
4458 guest_data_size = host_dm->data_size - host_dm->data_start;
4459 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4460 switch (ie->host_cmd) {
4461 case DM_REMOVE_ALL:
4462 case DM_DEV_CREATE:
4463 case DM_DEV_REMOVE:
4464 case DM_DEV_RENAME:
4465 case DM_DEV_SUSPEND:
4466 case DM_DEV_STATUS:
4467 case DM_TABLE_LOAD:
4468 case DM_TABLE_CLEAR:
4469 case DM_TARGET_MSG:
4470 case DM_DEV_SET_GEOMETRY:
4471 /* no return data */
4472 break;
4473 case DM_LIST_DEVICES:
4474 {
4475 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4476 uint32_t remaining_data = guest_data_size;
4477 void *cur_data = argptr;
4478 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4479 int nl_size = 12; /* can't use thunk_size due to alignment */
4480
4481 while (1) {
4482 uint32_t next = nl->next;
4483 if (next) {
4484 nl->next = nl_size + (strlen(nl->name) + 1);
4485 }
4486 if (remaining_data < nl->next) {
4487 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4488 break;
4489 }
4490 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4491 strcpy(cur_data + nl_size, nl->name);
4492 cur_data += nl->next;
4493 remaining_data -= nl->next;
4494 if (!next) {
4495 break;
4496 }
4497 nl = (void*)nl + next;
4498 }
4499 break;
4500 }
4501 case DM_DEV_WAIT:
4502 case DM_TABLE_STATUS:
4503 {
4504 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4505 void *cur_data = argptr;
4506 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4507 int spec_size = thunk_type_size(arg_type, 0);
4508 int i;
4509
4510 for (i = 0; i < host_dm->target_count; i++) {
4511 uint32_t next = spec->next;
4512 int slen = strlen((char*)&spec[1]) + 1;
4513 spec->next = (cur_data - argptr) + spec_size + slen;
4514 if (guest_data_size < spec->next) {
4515 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4516 break;
4517 }
4518 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4519 strcpy(cur_data + spec_size, (char*)&spec[1]);
4520 cur_data = argptr + spec->next;
4521 spec = (void*)host_dm + host_dm->data_start + next;
4522 }
4523 break;
4524 }
4525 case DM_TABLE_DEPS:
4526 {
4527 void *hdata = (void*)host_dm + host_dm->data_start;
4528 int count = *(uint32_t*)hdata;
4529 uint64_t *hdev = hdata + 8;
4530 uint64_t *gdev = argptr + 8;
4531 int i;
4532
4533 *(uint32_t*)argptr = tswap32(count);
4534 for (i = 0; i < count; i++) {
4535 *gdev = tswap64(*hdev);
4536 gdev++;
4537 hdev++;
4538 }
4539 break;
4540 }
4541 case DM_LIST_VERSIONS:
4542 {
4543 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4544 uint32_t remaining_data = guest_data_size;
4545 void *cur_data = argptr;
4546 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4547 int vers_size = thunk_type_size(arg_type, 0);
4548
4549 while (1) {
4550 uint32_t next = vers->next;
4551 if (next) {
4552 vers->next = vers_size + (strlen(vers->name) + 1);
4553 }
4554 if (remaining_data < vers->next) {
4555 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4556 break;
4557 }
4558 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4559 strcpy(cur_data + vers_size, vers->name);
4560 cur_data += vers->next;
4561 remaining_data -= vers->next;
4562 if (!next) {
4563 break;
4564 }
4565 vers = (void*)vers + next;
4566 }
4567 break;
4568 }
4569 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004570 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004571 ret = -TARGET_EINVAL;
4572 goto out;
4573 }
4574 unlock_user(argptr, guest_data, guest_data_size);
4575
4576 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4577 if (!argptr) {
4578 ret = -TARGET_EFAULT;
4579 goto out;
4580 }
4581 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4582 unlock_user(argptr, arg, target_size);
4583 }
4584out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004585 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004586 return ret;
4587}
4588
Alexander Grafa59b5e32014-08-22 13:15:50 +02004589static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004590 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004591{
4592 void *argptr;
4593 int target_size;
4594 const argtype *arg_type = ie->arg_type;
4595 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4596 abi_long ret;
4597
4598 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4599 struct blkpg_partition host_part;
4600
4601 /* Read and convert blkpg */
4602 arg_type++;
4603 target_size = thunk_type_size(arg_type, 0);
4604 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4605 if (!argptr) {
4606 ret = -TARGET_EFAULT;
4607 goto out;
4608 }
4609 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4610 unlock_user(argptr, arg, 0);
4611
4612 switch (host_blkpg->op) {
4613 case BLKPG_ADD_PARTITION:
4614 case BLKPG_DEL_PARTITION:
4615 /* payload is struct blkpg_partition */
4616 break;
4617 default:
4618 /* Unknown opcode */
4619 ret = -TARGET_EINVAL;
4620 goto out;
4621 }
4622
4623 /* Read and convert blkpg->data */
4624 arg = (abi_long)(uintptr_t)host_blkpg->data;
4625 target_size = thunk_type_size(part_arg_type, 0);
4626 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4627 if (!argptr) {
4628 ret = -TARGET_EFAULT;
4629 goto out;
4630 }
4631 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4632 unlock_user(argptr, arg, 0);
4633
4634 /* Swizzle the data pointer to our local copy and call! */
4635 host_blkpg->data = &host_part;
4636 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
4637
4638out:
4639 return ret;
4640}
4641
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004642static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004643 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004644{
4645 const argtype *arg_type = ie->arg_type;
4646 const StructEntry *se;
4647 const argtype *field_types;
4648 const int *dst_offsets, *src_offsets;
4649 int target_size;
4650 void *argptr;
4651 abi_ulong *target_rt_dev_ptr;
4652 unsigned long *host_rt_dev_ptr;
4653 abi_long ret;
4654 int i;
4655
4656 assert(ie->access == IOC_W);
4657 assert(*arg_type == TYPE_PTR);
4658 arg_type++;
4659 assert(*arg_type == TYPE_STRUCT);
4660 target_size = thunk_type_size(arg_type, 0);
4661 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4662 if (!argptr) {
4663 return -TARGET_EFAULT;
4664 }
4665 arg_type++;
4666 assert(*arg_type == (int)STRUCT_rtentry);
4667 se = struct_entries + *arg_type++;
4668 assert(se->convert[0] == NULL);
4669 /* convert struct here to be able to catch rt_dev string */
4670 field_types = se->field_types;
4671 dst_offsets = se->field_offsets[THUNK_HOST];
4672 src_offsets = se->field_offsets[THUNK_TARGET];
4673 for (i = 0; i < se->nb_fields; i++) {
4674 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4675 assert(*field_types == TYPE_PTRVOID);
4676 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4677 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4678 if (*target_rt_dev_ptr != 0) {
4679 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4680 tswapal(*target_rt_dev_ptr));
4681 if (!*host_rt_dev_ptr) {
4682 unlock_user(argptr, arg, 0);
4683 return -TARGET_EFAULT;
4684 }
4685 } else {
4686 *host_rt_dev_ptr = 0;
4687 }
4688 field_types++;
4689 continue;
4690 }
4691 field_types = thunk_convert(buf_temp + dst_offsets[i],
4692 argptr + src_offsets[i],
4693 field_types, THUNK_HOST);
4694 }
4695 unlock_user(argptr, arg, 0);
4696
4697 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4698 if (*host_rt_dev_ptr != 0) {
4699 unlock_user((void *)*host_rt_dev_ptr,
4700 *target_rt_dev_ptr, 0);
4701 }
4702 return ret;
4703}
4704
Paul Burtonca56f5b2014-06-22 11:25:47 +01004705static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004706 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004707{
4708 int sig = target_to_host_signal(arg);
4709 return get_errno(ioctl(fd, ie->host_cmd, sig));
4710}
4711
blueswir19f106a72008-10-05 10:52:52 +00004712static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004713#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004714 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4715#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4716 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004717#include "ioctls.h"
4718 { 0, 0, },
4719};
4720
pbrook53a59602006-03-25 19:31:22 +00004721/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004722/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004723static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004724{
4725 const IOCTLEntry *ie;
4726 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004727 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004728 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004729 int target_size;
4730 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004731
4732 ie = ioctl_entries;
4733 for(;;) {
4734 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004735 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004736 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004737 }
4738 if (ie->target_cmd == cmd)
4739 break;
4740 ie++;
4741 }
4742 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004743#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004744 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004745#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004746 if (ie->do_ioctl) {
4747 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4748 }
4749
bellard31e31b82003-02-18 22:55:36 +00004750 switch(arg_type[0]) {
4751 case TYPE_NULL:
4752 /* no argument */
4753 ret = get_errno(ioctl(fd, ie->host_cmd));
4754 break;
4755 case TYPE_PTRVOID:
4756 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004757 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4758 break;
4759 case TYPE_PTR:
4760 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004761 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004762 switch(ie->access) {
4763 case IOC_R:
4764 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4765 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004766 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4767 if (!argptr)
4768 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004769 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4770 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004771 }
4772 break;
4773 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004774 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4775 if (!argptr)
4776 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004777 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4778 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004779 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4780 break;
4781 default:
4782 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004783 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4784 if (!argptr)
4785 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004786 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4787 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004788 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4789 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004790 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4791 if (!argptr)
4792 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004793 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4794 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004795 }
4796 break;
4797 }
4798 break;
4799 default:
j_mayer32407102007-09-26 23:01:49 +00004800 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4801 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004802 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004803 break;
4804 }
4805 return ret;
4806}
4807
blueswir1b39bc502008-10-05 10:51:10 +00004808static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004809 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4810 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4811 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4812 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4813 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4814 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4815 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4816 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4817 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4818 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4819 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4820 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4821 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4822 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4823 { 0, 0, 0, 0 }
4824};
4825
blueswir1b39bc502008-10-05 10:51:10 +00004826static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004827 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4828 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4829 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4830 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4831 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4832 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4833 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4834 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4835 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4836 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4837 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4838 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4839 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4840 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4841 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4842 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4843 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4844 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4845 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4846 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4847 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4848 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4849 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4850 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4851 { 0, 0, 0, 0 }
4852};
4853
blueswir1b39bc502008-10-05 10:51:10 +00004854static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004855 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4856 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4857 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4858 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4859 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4860 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4861 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4862 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4863 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4864 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4865 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4866 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4867 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4868 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4869 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4870 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4871 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4872 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4873 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4874 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4875 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4876 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4877 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4878 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4879 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4880 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4881 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4882 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4883 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4884 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4885 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4886 { 0, 0, 0, 0 }
4887};
4888
blueswir1b39bc502008-10-05 10:51:10 +00004889static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004890 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4891 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4892 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4893 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4894 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4895 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4896 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4897 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4898 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4899 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4900 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4901 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4902 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4903 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4904 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4905 { 0, 0, 0, 0 }
4906};
4907
4908static void target_to_host_termios (void *dst, const void *src)
4909{
4910 struct host_termios *host = dst;
4911 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004912
ths5fafdf22007-09-16 21:08:06 +00004913 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004914 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004915 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004916 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004917 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004918 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004919 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004920 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4921 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004922
Arnaud Patard44607122009-04-21 17:39:08 +03004923 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004924 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4925 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004926 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004927 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004928 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004929 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004930 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004931 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004932 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004933 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4934 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004935 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4936 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4937 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4938 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4939 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004940 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004941}
ths3b46e622007-09-17 08:09:54 +00004942
bellard31e31b82003-02-18 22:55:36 +00004943static void host_to_target_termios (void *dst, const void *src)
4944{
4945 struct target_termios *target = dst;
4946 const struct host_termios *host = src;
4947
ths5fafdf22007-09-16 21:08:06 +00004948 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004949 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004950 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004951 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004952 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004953 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004954 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004955 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4956 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004957
Arnaud Patard44607122009-04-21 17:39:08 +03004958 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004959 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4960 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4961 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4962 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4963 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4964 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4965 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4966 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4967 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4968 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4969 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4970 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4971 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4972 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4973 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4974 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4975 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4976}
4977
blueswir18e853dc2008-10-05 10:49:32 +00004978static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004979 .convert = { host_to_target_termios, target_to_host_termios },
4980 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4981 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4982};
4983
bellard5286db72003-06-05 00:57:30 +00004984static bitmask_transtbl mmap_flags_tbl[] = {
4985 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4986 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4987 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4988 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4989 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4990 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4991 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4992 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004993 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4994 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004995 { 0, 0, 0, 0 }
4996};
4997
bellard2ab83ea2003-06-15 19:56:46 +00004998#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004999
5000/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005001static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005002
bellard03acab62007-11-11 14:57:14 +00005003static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005004{
5005 int size;
pbrook53a59602006-03-25 19:31:22 +00005006 void *p;
bellard6dbad632003-03-16 18:05:05 +00005007
5008 if (!ldt_table)
5009 return 0;
5010 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5011 if (size > bytecount)
5012 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005013 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5014 if (!p)
bellard03acab62007-11-11 14:57:14 +00005015 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005016 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005017 memcpy(p, ldt_table, size);
5018 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005019 return size;
5020}
5021
5022/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005023static abi_long write_ldt(CPUX86State *env,
5024 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005025{
5026 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005027 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005028 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005029 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005030 uint32_t *lp, entry_1, entry_2;
5031
5032 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005033 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005034 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005035 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005036 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005037 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005038 ldt_info.limit = tswap32(target_ldt_info->limit);
5039 ldt_info.flags = tswap32(target_ldt_info->flags);
5040 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005041
bellard6dbad632003-03-16 18:05:05 +00005042 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005043 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005044 seg_32bit = ldt_info.flags & 1;
5045 contents = (ldt_info.flags >> 1) & 3;
5046 read_exec_only = (ldt_info.flags >> 3) & 1;
5047 limit_in_pages = (ldt_info.flags >> 4) & 1;
5048 seg_not_present = (ldt_info.flags >> 5) & 1;
5049 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005050#ifdef TARGET_ABI32
5051 lm = 0;
5052#else
5053 lm = (ldt_info.flags >> 7) & 1;
5054#endif
bellard6dbad632003-03-16 18:05:05 +00005055 if (contents == 3) {
5056 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005057 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005058 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005059 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005060 }
5061 /* allocate the LDT */
5062 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005063 env->ldt.base = target_mmap(0,
5064 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5065 PROT_READ|PROT_WRITE,
5066 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5067 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005068 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005069 memset(g2h(env->ldt.base), 0,
5070 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005071 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005072 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005073 }
5074
5075 /* NOTE: same code as Linux kernel */
5076 /* Allow LDTs to be cleared by the user. */
5077 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5078 if (oldmode ||
5079 (contents == 0 &&
5080 read_exec_only == 1 &&
5081 seg_32bit == 0 &&
5082 limit_in_pages == 0 &&
5083 seg_not_present == 1 &&
5084 useable == 0 )) {
5085 entry_1 = 0;
5086 entry_2 = 0;
5087 goto install;
5088 }
5089 }
ths3b46e622007-09-17 08:09:54 +00005090
bellard6dbad632003-03-16 18:05:05 +00005091 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5092 (ldt_info.limit & 0x0ffff);
5093 entry_2 = (ldt_info.base_addr & 0xff000000) |
5094 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5095 (ldt_info.limit & 0xf0000) |
5096 ((read_exec_only ^ 1) << 9) |
5097 (contents << 10) |
5098 ((seg_not_present ^ 1) << 15) |
5099 (seg_32bit << 22) |
5100 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005101 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005102 0x7000;
5103 if (!oldmode)
5104 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005105
bellard6dbad632003-03-16 18:05:05 +00005106 /* Install the new entry ... */
5107install:
5108 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5109 lp[0] = tswap32(entry_1);
5110 lp[1] = tswap32(entry_2);
5111 return 0;
5112}
5113
5114/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005115static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5116 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005117{
bellard03acab62007-11-11 14:57:14 +00005118 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005119
bellard6dbad632003-03-16 18:05:05 +00005120 switch (func) {
5121 case 0:
5122 ret = read_ldt(ptr, bytecount);
5123 break;
5124 case 1:
5125 ret = write_ldt(env, ptr, bytecount, 1);
5126 break;
5127 case 0x11:
5128 ret = write_ldt(env, ptr, bytecount, 0);
5129 break;
bellard03acab62007-11-11 14:57:14 +00005130 default:
5131 ret = -TARGET_ENOSYS;
5132 break;
bellard6dbad632003-03-16 18:05:05 +00005133 }
5134 return ret;
5135}
bellard1b6b0292003-03-22 17:31:38 +00005136
blueswir14583f582008-08-24 10:35:55 +00005137#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005138abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005139{
5140 uint64_t *gdt_table = g2h(env->gdt.base);
5141 struct target_modify_ldt_ldt_s ldt_info;
5142 struct target_modify_ldt_ldt_s *target_ldt_info;
5143 int seg_32bit, contents, read_exec_only, limit_in_pages;
5144 int seg_not_present, useable, lm;
5145 uint32_t *lp, entry_1, entry_2;
5146 int i;
5147
5148 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5149 if (!target_ldt_info)
5150 return -TARGET_EFAULT;
5151 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005152 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005153 ldt_info.limit = tswap32(target_ldt_info->limit);
5154 ldt_info.flags = tswap32(target_ldt_info->flags);
5155 if (ldt_info.entry_number == -1) {
5156 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5157 if (gdt_table[i] == 0) {
5158 ldt_info.entry_number = i;
5159 target_ldt_info->entry_number = tswap32(i);
5160 break;
5161 }
5162 }
5163 }
5164 unlock_user_struct(target_ldt_info, ptr, 1);
5165
5166 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5167 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5168 return -TARGET_EINVAL;
5169 seg_32bit = ldt_info.flags & 1;
5170 contents = (ldt_info.flags >> 1) & 3;
5171 read_exec_only = (ldt_info.flags >> 3) & 1;
5172 limit_in_pages = (ldt_info.flags >> 4) & 1;
5173 seg_not_present = (ldt_info.flags >> 5) & 1;
5174 useable = (ldt_info.flags >> 6) & 1;
5175#ifdef TARGET_ABI32
5176 lm = 0;
5177#else
5178 lm = (ldt_info.flags >> 7) & 1;
5179#endif
5180
5181 if (contents == 3) {
5182 if (seg_not_present == 0)
5183 return -TARGET_EINVAL;
5184 }
5185
5186 /* NOTE: same code as Linux kernel */
5187 /* Allow LDTs to be cleared by the user. */
5188 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5189 if ((contents == 0 &&
5190 read_exec_only == 1 &&
5191 seg_32bit == 0 &&
5192 limit_in_pages == 0 &&
5193 seg_not_present == 1 &&
5194 useable == 0 )) {
5195 entry_1 = 0;
5196 entry_2 = 0;
5197 goto install;
5198 }
5199 }
5200
5201 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5202 (ldt_info.limit & 0x0ffff);
5203 entry_2 = (ldt_info.base_addr & 0xff000000) |
5204 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5205 (ldt_info.limit & 0xf0000) |
5206 ((read_exec_only ^ 1) << 9) |
5207 (contents << 10) |
5208 ((seg_not_present ^ 1) << 15) |
5209 (seg_32bit << 22) |
5210 (limit_in_pages << 23) |
5211 (useable << 20) |
5212 (lm << 21) |
5213 0x7000;
5214
5215 /* Install the new entry ... */
5216install:
5217 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5218 lp[0] = tswap32(entry_1);
5219 lp[1] = tswap32(entry_2);
5220 return 0;
5221}
5222
blueswir18fcd3692008-08-17 20:26:25 +00005223static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005224{
5225 struct target_modify_ldt_ldt_s *target_ldt_info;
5226 uint64_t *gdt_table = g2h(env->gdt.base);
5227 uint32_t base_addr, limit, flags;
5228 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5229 int seg_not_present, useable, lm;
5230 uint32_t *lp, entry_1, entry_2;
5231
5232 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5233 if (!target_ldt_info)
5234 return -TARGET_EFAULT;
5235 idx = tswap32(target_ldt_info->entry_number);
5236 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5237 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5238 unlock_user_struct(target_ldt_info, ptr, 1);
5239 return -TARGET_EINVAL;
5240 }
5241 lp = (uint32_t *)(gdt_table + idx);
5242 entry_1 = tswap32(lp[0]);
5243 entry_2 = tswap32(lp[1]);
5244
5245 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5246 contents = (entry_2 >> 10) & 3;
5247 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5248 seg_32bit = (entry_2 >> 22) & 1;
5249 limit_in_pages = (entry_2 >> 23) & 1;
5250 useable = (entry_2 >> 20) & 1;
5251#ifdef TARGET_ABI32
5252 lm = 0;
5253#else
5254 lm = (entry_2 >> 21) & 1;
5255#endif
5256 flags = (seg_32bit << 0) | (contents << 1) |
5257 (read_exec_only << 3) | (limit_in_pages << 4) |
5258 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5259 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5260 base_addr = (entry_1 >> 16) |
5261 (entry_2 & 0xff000000) |
5262 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005263 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005264 target_ldt_info->limit = tswap32(limit);
5265 target_ldt_info->flags = tswap32(flags);
5266 unlock_user_struct(target_ldt_info, ptr, 1);
5267 return 0;
5268}
blueswir14583f582008-08-24 10:35:55 +00005269#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005270
bellardd2fd1af2007-11-14 18:08:56 +00005271#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005272abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005273{
Juan Quintela1add8692011-06-16 17:37:09 +01005274 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005275 abi_ulong val;
5276 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005277
bellardd2fd1af2007-11-14 18:08:56 +00005278 switch(code) {
5279 case TARGET_ARCH_SET_GS:
5280 case TARGET_ARCH_SET_FS:
5281 if (code == TARGET_ARCH_SET_GS)
5282 idx = R_GS;
5283 else
5284 idx = R_FS;
5285 cpu_x86_load_seg(env, idx, 0);
5286 env->segs[idx].base = addr;
5287 break;
5288 case TARGET_ARCH_GET_GS:
5289 case TARGET_ARCH_GET_FS:
5290 if (code == TARGET_ARCH_GET_GS)
5291 idx = R_GS;
5292 else
5293 idx = R_FS;
5294 val = env->segs[idx].base;
5295 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005296 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005297 break;
5298 default:
5299 ret = -TARGET_EINVAL;
5300 break;
5301 }
Juan Quintela1add8692011-06-16 17:37:09 +01005302 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005303}
5304#endif
5305
bellard2ab83ea2003-06-15 19:56:46 +00005306#endif /* defined(TARGET_I386) */
5307
Riku Voipio05098a92011-03-04 15:27:29 +02005308#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005309
pbrookd865bab2008-06-07 22:12:17 +00005310
5311static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5312typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005313 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005314 pthread_mutex_t mutex;
5315 pthread_cond_t cond;
5316 pthread_t thread;
5317 uint32_t tid;
5318 abi_ulong child_tidptr;
5319 abi_ulong parent_tidptr;
5320 sigset_t sigmask;
5321} new_thread_info;
5322
5323static void *clone_func(void *arg)
5324{
5325 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005326 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005327 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005328 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005329
Emilio G. Cota70903762015-08-23 20:23:41 -04005330 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005331 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005332 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005333 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005334 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005335 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005336 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005337 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005338 if (info->child_tidptr)
5339 put_user_u32(info->tid, info->child_tidptr);
5340 if (info->parent_tidptr)
5341 put_user_u32(info->tid, info->parent_tidptr);
5342 /* Enable signals. */
5343 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5344 /* Signal to the parent that we're ready. */
5345 pthread_mutex_lock(&info->mutex);
5346 pthread_cond_broadcast(&info->cond);
5347 pthread_mutex_unlock(&info->mutex);
5348 /* Wait until the parent has finshed initializing the tls state. */
5349 pthread_mutex_lock(&clone_lock);
5350 pthread_mutex_unlock(&clone_lock);
5351 cpu_loop(env);
5352 /* never exits */
5353 return NULL;
5354}
bellard1b6b0292003-03-22 17:31:38 +00005355
ths0da46a62007-10-20 20:23:07 +00005356/* do_fork() Must return host values and target errnos (unlike most
5357 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005358static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005359 abi_ulong parent_tidptr, target_ulong newtls,
5360 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005361{
Andreas Färber0429a972013-08-26 18:14:44 +02005362 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005363 int ret;
bellard5cd43932003-03-29 16:54:36 +00005364 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005365 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005366 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005367 unsigned int nptl_flags;
5368 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005369
balrog436d1242008-09-21 02:39:45 +00005370 /* Emulate vfork() with fork() */
5371 if (flags & CLONE_VFORK)
5372 flags &= ~(CLONE_VFORK | CLONE_VM);
5373
bellard1b6b0292003-03-22 17:31:38 +00005374 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005375 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005376 new_thread_info info;
5377 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005378
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005379 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005380 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005381 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005382 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005383 /* Init regs that differ from the parent. */
5384 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005385 new_cpu = ENV_GET_CPU(new_env);
5386 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005387 ts->bprm = parent_ts->bprm;
5388 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00005389 nptl_flags = flags;
5390 flags &= ~CLONE_NPTL_FLAGS2;
5391
pbrookc2764712009-03-07 15:24:59 +00005392 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5393 ts->child_tidptr = child_tidptr;
5394 }
5395
pbrookd865bab2008-06-07 22:12:17 +00005396 if (nptl_flags & CLONE_SETTLS)
5397 cpu_set_tls (new_env, newtls);
5398
5399 /* Grab a mutex so that thread setup appears atomic. */
5400 pthread_mutex_lock(&clone_lock);
5401
5402 memset(&info, 0, sizeof(info));
5403 pthread_mutex_init(&info.mutex, NULL);
5404 pthread_mutex_lock(&info.mutex);
5405 pthread_cond_init(&info.cond, NULL);
5406 info.env = new_env;
5407 if (nptl_flags & CLONE_CHILD_SETTID)
5408 info.child_tidptr = child_tidptr;
5409 if (nptl_flags & CLONE_PARENT_SETTID)
5410 info.parent_tidptr = parent_tidptr;
5411
5412 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005413 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5414 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005415 /* It is not safe to deliver signals until the child has finished
5416 initializing, so temporarily block all signals. */
5417 sigfillset(&sigmask);
5418 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5419
5420 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005421 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005422
5423 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5424 pthread_attr_destroy(&attr);
5425 if (ret == 0) {
5426 /* Wait for the child to initialize. */
5427 pthread_cond_wait(&info.cond, &info.mutex);
5428 ret = info.tid;
5429 if (flags & CLONE_PARENT_SETTID)
5430 put_user_u32(ret, parent_tidptr);
5431 } else {
5432 ret = -1;
5433 }
5434 pthread_mutex_unlock(&info.mutex);
5435 pthread_cond_destroy(&info.cond);
5436 pthread_mutex_destroy(&info.mutex);
5437 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005438 } else {
5439 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005440 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5441 return -TARGET_EINVAL;
5442 }
pbrookd865bab2008-06-07 22:12:17 +00005443 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005444 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005445 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005446 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005447 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005448 cpu_clone_regs(env, newsp);
5449 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005450 /* There is a race condition here. The parent process could
5451 theoretically read the TID in the child process before the child
5452 tid is set. This would require using either ptrace
5453 (not implemented) or having *_tidptr to point at a shared memory
5454 mapping. We can't repeat the spinlock hack used above because
5455 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005456 if (flags & CLONE_CHILD_SETTID)
5457 put_user_u32(gettid(), child_tidptr);
5458 if (flags & CLONE_PARENT_SETTID)
5459 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005460 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005461 if (flags & CLONE_SETTLS)
5462 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005463 if (flags & CLONE_CHILD_CLEARTID)
5464 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005465 } else {
5466 fork_end(0);
5467 }
bellard1b6b0292003-03-22 17:31:38 +00005468 }
5469 return ret;
5470}
5471
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005472/* warning : doesn't handle linux specific flags... */
5473static int target_to_host_fcntl_cmd(int cmd)
5474{
5475 switch(cmd) {
5476 case TARGET_F_DUPFD:
5477 case TARGET_F_GETFD:
5478 case TARGET_F_SETFD:
5479 case TARGET_F_GETFL:
5480 case TARGET_F_SETFL:
5481 return cmd;
5482 case TARGET_F_GETLK:
5483 return F_GETLK;
5484 case TARGET_F_SETLK:
5485 return F_SETLK;
5486 case TARGET_F_SETLKW:
5487 return F_SETLKW;
5488 case TARGET_F_GETOWN:
5489 return F_GETOWN;
5490 case TARGET_F_SETOWN:
5491 return F_SETOWN;
5492 case TARGET_F_GETSIG:
5493 return F_GETSIG;
5494 case TARGET_F_SETSIG:
5495 return F_SETSIG;
5496#if TARGET_ABI_BITS == 32
5497 case TARGET_F_GETLK64:
5498 return F_GETLK64;
5499 case TARGET_F_SETLK64:
5500 return F_SETLK64;
5501 case TARGET_F_SETLKW64:
5502 return F_SETLKW64;
5503#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005504 case TARGET_F_SETLEASE:
5505 return F_SETLEASE;
5506 case TARGET_F_GETLEASE:
5507 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005508#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005509 case TARGET_F_DUPFD_CLOEXEC:
5510 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005511#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005512 case TARGET_F_NOTIFY:
5513 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005514#ifdef F_GETOWN_EX
5515 case TARGET_F_GETOWN_EX:
5516 return F_GETOWN_EX;
5517#endif
5518#ifdef F_SETOWN_EX
5519 case TARGET_F_SETOWN_EX:
5520 return F_SETOWN_EX;
5521#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005522 default:
5523 return -TARGET_EINVAL;
5524 }
5525 return -TARGET_EINVAL;
5526}
5527
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005528#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5529static const bitmask_transtbl flock_tbl[] = {
5530 TRANSTBL_CONVERT(F_RDLCK),
5531 TRANSTBL_CONVERT(F_WRLCK),
5532 TRANSTBL_CONVERT(F_UNLCK),
5533 TRANSTBL_CONVERT(F_EXLCK),
5534 TRANSTBL_CONVERT(F_SHLCK),
5535 { 0, 0, 0, 0 }
5536};
5537
blueswir1992f48a2007-10-14 16:27:31 +00005538static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005539{
5540 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00005541 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00005542 struct flock64 fl64;
5543 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005544#ifdef F_GETOWN_EX
5545 struct f_owner_ex fox;
5546 struct target_f_owner_ex *target_fox;
5547#endif
blueswir1992f48a2007-10-14 16:27:31 +00005548 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005549 int host_cmd = target_to_host_fcntl_cmd(cmd);
5550
5551 if (host_cmd == -TARGET_EINVAL)
5552 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005553
bellard7775e9e2003-05-14 22:46:48 +00005554 switch(cmd) {
5555 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00005556 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
5557 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005558 fl.l_type =
5559 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00005560 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005561 fl.l_start = tswapal(target_fl->l_start);
5562 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005563 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00005564 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005565 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00005566 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00005567 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
5568 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005569 target_fl->l_type =
5570 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00005571 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005572 target_fl->l_start = tswapal(fl.l_start);
5573 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005574 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00005575 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00005576 }
5577 break;
ths3b46e622007-09-17 08:09:54 +00005578
bellard7775e9e2003-05-14 22:46:48 +00005579 case TARGET_F_SETLK:
5580 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00005581 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
5582 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005583 fl.l_type =
5584 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00005585 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005586 fl.l_start = tswapal(target_fl->l_start);
5587 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005588 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00005589 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005590 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00005591 break;
ths3b46e622007-09-17 08:09:54 +00005592
bellard7775e9e2003-05-14 22:46:48 +00005593 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00005594 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
5595 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005596 fl64.l_type =
5597 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00005598 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005599 fl64.l_start = tswap64(target_fl64->l_start);
5600 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005601 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00005602 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005603 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005604 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00005605 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
5606 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005607 target_fl64->l_type =
5608 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00005609 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005610 target_fl64->l_start = tswap64(fl64.l_start);
5611 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005612 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00005613 unlock_user_struct(target_fl64, arg, 1);
5614 }
bellard9ee1fa22007-11-11 15:11:19 +00005615 break;
bellard7775e9e2003-05-14 22:46:48 +00005616 case TARGET_F_SETLK64:
5617 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00005618 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
5619 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005620 fl64.l_type =
5621 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00005622 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005623 fl64.l_start = tswap64(target_fl64->l_start);
5624 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005625 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00005626 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005627 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005628 break;
5629
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005630 case TARGET_F_GETFL:
5631 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005632 if (ret >= 0) {
5633 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5634 }
bellardffa65c32004-01-04 23:57:22 +00005635 break;
5636
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005637 case TARGET_F_SETFL:
5638 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
5639 break;
5640
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005641#ifdef F_GETOWN_EX
5642 case TARGET_F_GETOWN_EX:
5643 ret = get_errno(fcntl(fd, host_cmd, &fox));
5644 if (ret >= 0) {
5645 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5646 return -TARGET_EFAULT;
5647 target_fox->type = tswap32(fox.type);
5648 target_fox->pid = tswap32(fox.pid);
5649 unlock_user_struct(target_fox, arg, 1);
5650 }
5651 break;
5652#endif
5653
5654#ifdef F_SETOWN_EX
5655 case TARGET_F_SETOWN_EX:
5656 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5657 return -TARGET_EFAULT;
5658 fox.type = tswap32(target_fox->type);
5659 fox.pid = tswap32(target_fox->pid);
5660 unlock_user_struct(target_fox, arg, 0);
5661 ret = get_errno(fcntl(fd, host_cmd, &fox));
5662 break;
5663#endif
5664
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005665 case TARGET_F_SETOWN:
5666 case TARGET_F_GETOWN:
5667 case TARGET_F_SETSIG:
5668 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005669 case TARGET_F_SETLEASE:
5670 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005671 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005672 break;
5673
bellard7775e9e2003-05-14 22:46:48 +00005674 default:
bellard9ee1fa22007-11-11 15:11:19 +00005675 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005676 break;
5677 }
5678 return ret;
5679}
5680
bellard67867302003-11-23 17:05:30 +00005681#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005682
bellard67867302003-11-23 17:05:30 +00005683static inline int high2lowuid(int uid)
5684{
5685 if (uid > 65535)
5686 return 65534;
5687 else
5688 return uid;
5689}
5690
5691static inline int high2lowgid(int gid)
5692{
5693 if (gid > 65535)
5694 return 65534;
5695 else
5696 return gid;
5697}
5698
5699static inline int low2highuid(int uid)
5700{
5701 if ((int16_t)uid == -1)
5702 return -1;
5703 else
5704 return uid;
5705}
5706
5707static inline int low2highgid(int gid)
5708{
5709 if ((int16_t)gid == -1)
5710 return -1;
5711 else
5712 return gid;
5713}
Riku Voipio0c866a72011-04-18 15:23:06 +03005714static inline int tswapid(int id)
5715{
5716 return tswap16(id);
5717}
Peter Maydell76ca3102014-03-02 19:36:41 +00005718
5719#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5720
Riku Voipio0c866a72011-04-18 15:23:06 +03005721#else /* !USE_UID16 */
5722static inline int high2lowuid(int uid)
5723{
5724 return uid;
5725}
5726static inline int high2lowgid(int gid)
5727{
5728 return gid;
5729}
5730static inline int low2highuid(int uid)
5731{
5732 return uid;
5733}
5734static inline int low2highgid(int gid)
5735{
5736 return gid;
5737}
5738static inline int tswapid(int id)
5739{
5740 return tswap32(id);
5741}
Peter Maydell76ca3102014-03-02 19:36:41 +00005742
5743#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5744
bellard67867302003-11-23 17:05:30 +00005745#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005746
Peter Maydellfd6f7792016-03-01 16:33:02 +00005747/* We must do direct syscalls for setting UID/GID, because we want to
5748 * implement the Linux system call semantics of "change only for this thread",
5749 * not the libc/POSIX semantics of "change for all threads in process".
5750 * (See http://ewontfix.com/17/ for more details.)
5751 * We use the 32-bit version of the syscalls if present; if it is not
5752 * then either the host architecture supports 32-bit UIDs natively with
5753 * the standard syscall, or the 16-bit UID is the best we can do.
5754 */
5755#ifdef __NR_setuid32
5756#define __NR_sys_setuid __NR_setuid32
5757#else
5758#define __NR_sys_setuid __NR_setuid
5759#endif
5760#ifdef __NR_setgid32
5761#define __NR_sys_setgid __NR_setgid32
5762#else
5763#define __NR_sys_setgid __NR_setgid
5764#endif
5765#ifdef __NR_setresuid32
5766#define __NR_sys_setresuid __NR_setresuid32
5767#else
5768#define __NR_sys_setresuid __NR_setresuid
5769#endif
5770#ifdef __NR_setresgid32
5771#define __NR_sys_setresgid __NR_setresgid32
5772#else
5773#define __NR_sys_setresgid __NR_setresgid
5774#endif
5775
5776_syscall1(int, sys_setuid, uid_t, uid)
5777_syscall1(int, sys_setgid, gid_t, gid)
5778_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
5779_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
5780
bellard31e31b82003-02-18 22:55:36 +00005781void syscall_init(void)
5782{
bellard2ab83ea2003-06-15 19:56:46 +00005783 IOCTLEntry *ie;
5784 const argtype *arg_type;
5785 int size;
thsb92c47c2007-11-01 00:07:38 +00005786 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005787
Alexander Graf8be656b2015-05-06 23:47:32 +02005788 thunk_init(STRUCT_MAX);
5789
Blue Swirl001faf32009-05-13 17:53:17 +00005790#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005791#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005792#include "syscall_types.h"
5793#undef STRUCT
5794#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005795
Peter Maydelldd6e9572012-07-23 08:07:22 +00005796 /* Build target_to_host_errno_table[] table from
5797 * host_to_target_errno_table[]. */
5798 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5799 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5800 }
5801
bellard2ab83ea2003-06-15 19:56:46 +00005802 /* we patch the ioctl size if necessary. We rely on the fact that
5803 no ioctl has all the bits at '1' in the size field */
5804 ie = ioctl_entries;
5805 while (ie->target_cmd != 0) {
5806 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5807 TARGET_IOC_SIZEMASK) {
5808 arg_type = ie->arg_type;
5809 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005810 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005811 ie->target_cmd);
5812 exit(1);
5813 }
5814 arg_type++;
5815 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005816 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005817 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5818 (size << TARGET_IOC_SIZESHIFT);
5819 }
thsb92c47c2007-11-01 00:07:38 +00005820
bellard2ab83ea2003-06-15 19:56:46 +00005821 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005822#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5823 (defined(__x86_64__) && defined(TARGET_X86_64))
5824 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5825 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5826 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005827 }
5828#endif
5829 ie++;
5830 }
bellard31e31b82003-02-18 22:55:36 +00005831}
bellardc573ff62004-01-04 15:51:36 +00005832
blueswir1992f48a2007-10-14 16:27:31 +00005833#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005834static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5835{
thsaf325d32008-06-10 15:29:15 +00005836#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005837 return ((uint64_t)word0 << 32) | word1;
5838#else
5839 return ((uint64_t)word1 << 32) | word0;
5840#endif
5841}
blueswir1992f48a2007-10-14 16:27:31 +00005842#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005843static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5844{
5845 return word0;
5846}
blueswir1992f48a2007-10-14 16:27:31 +00005847#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005848
5849#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005850static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5851 abi_long arg2,
5852 abi_long arg3,
5853 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005854{
Riku Voipio48e515d2011-07-12 15:40:51 +03005855 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005856 arg2 = arg3;
5857 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005858 }
pbrookce4defa2006-02-09 16:49:55 +00005859 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5860}
5861#endif
5862
5863#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005864static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5865 abi_long arg2,
5866 abi_long arg3,
5867 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005868{
Riku Voipio48e515d2011-07-12 15:40:51 +03005869 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005870 arg2 = arg3;
5871 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005872 }
pbrookce4defa2006-02-09 16:49:55 +00005873 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5874}
5875#endif
5876
bellard579a97f2007-11-11 14:26:47 +00005877static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5878 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005879{
5880 struct target_timespec *target_ts;
5881
bellard579a97f2007-11-11 14:26:47 +00005882 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5883 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01005884 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
5885 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005886 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005887 return 0;
pbrook53a59602006-03-25 19:31:22 +00005888}
5889
bellard579a97f2007-11-11 14:26:47 +00005890static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5891 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005892{
5893 struct target_timespec *target_ts;
5894
bellard579a97f2007-11-11 14:26:47 +00005895 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5896 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01005897 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
5898 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005899 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005900 return 0;
pbrook53a59602006-03-25 19:31:22 +00005901}
5902
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005903static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5904 abi_ulong target_addr)
5905{
5906 struct target_itimerspec *target_itspec;
5907
5908 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5909 return -TARGET_EFAULT;
5910 }
5911
5912 host_itspec->it_interval.tv_sec =
5913 tswapal(target_itspec->it_interval.tv_sec);
5914 host_itspec->it_interval.tv_nsec =
5915 tswapal(target_itspec->it_interval.tv_nsec);
5916 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5917 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5918
5919 unlock_user_struct(target_itspec, target_addr, 1);
5920 return 0;
5921}
5922
5923static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5924 struct itimerspec *host_its)
5925{
5926 struct target_itimerspec *target_itspec;
5927
5928 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5929 return -TARGET_EFAULT;
5930 }
5931
5932 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5933 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5934
5935 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5936 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5937
5938 unlock_user_struct(target_itspec, target_addr, 0);
5939 return 0;
5940}
5941
Peter Maydellc0659762014-08-09 15:42:32 +01005942static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5943 abi_ulong target_addr)
5944{
5945 struct target_sigevent *target_sevp;
5946
5947 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5948 return -TARGET_EFAULT;
5949 }
5950
5951 /* This union is awkward on 64 bit systems because it has a 32 bit
5952 * integer and a pointer in it; we follow the conversion approach
5953 * used for handling sigval types in signal.c so the guest should get
5954 * the correct value back even if we did a 64 bit byteswap and it's
5955 * using the 32 bit integer.
5956 */
5957 host_sevp->sigev_value.sival_ptr =
5958 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5959 host_sevp->sigev_signo =
5960 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5961 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5962 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5963
5964 unlock_user_struct(target_sevp, target_addr, 1);
5965 return 0;
5966}
5967
Tom Musta6f6a4032014-08-12 13:53:42 -05005968#if defined(TARGET_NR_mlockall)
5969static inline int target_to_host_mlockall_arg(int arg)
5970{
5971 int result = 0;
5972
5973 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5974 result |= MCL_CURRENT;
5975 }
5976 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5977 result |= MCL_FUTURE;
5978 }
5979 return result;
5980}
5981#endif
5982
balrog6a24a772008-09-20 02:23:36 +00005983static inline abi_long host_to_target_stat64(void *cpu_env,
5984 abi_ulong target_addr,
5985 struct stat *host_st)
5986{
Alexander Graf09701192013-09-03 20:12:15 +01005987#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005988 if (((CPUARMState *)cpu_env)->eabi) {
5989 struct target_eabi_stat64 *target_st;
5990
5991 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5992 return -TARGET_EFAULT;
5993 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5994 __put_user(host_st->st_dev, &target_st->st_dev);
5995 __put_user(host_st->st_ino, &target_st->st_ino);
5996#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5997 __put_user(host_st->st_ino, &target_st->__st_ino);
5998#endif
5999 __put_user(host_st->st_mode, &target_st->st_mode);
6000 __put_user(host_st->st_nlink, &target_st->st_nlink);
6001 __put_user(host_st->st_uid, &target_st->st_uid);
6002 __put_user(host_st->st_gid, &target_st->st_gid);
6003 __put_user(host_st->st_rdev, &target_st->st_rdev);
6004 __put_user(host_st->st_size, &target_st->st_size);
6005 __put_user(host_st->st_blksize, &target_st->st_blksize);
6006 __put_user(host_st->st_blocks, &target_st->st_blocks);
6007 __put_user(host_st->st_atime, &target_st->target_st_atime);
6008 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6009 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6010 unlock_user_struct(target_st, target_addr, 1);
6011 } else
6012#endif
6013 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006014#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006015 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006016#else
6017 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006018#endif
balrog6a24a772008-09-20 02:23:36 +00006019
6020 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6021 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006022 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006023 __put_user(host_st->st_dev, &target_st->st_dev);
6024 __put_user(host_st->st_ino, &target_st->st_ino);
6025#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6026 __put_user(host_st->st_ino, &target_st->__st_ino);
6027#endif
6028 __put_user(host_st->st_mode, &target_st->st_mode);
6029 __put_user(host_st->st_nlink, &target_st->st_nlink);
6030 __put_user(host_st->st_uid, &target_st->st_uid);
6031 __put_user(host_st->st_gid, &target_st->st_gid);
6032 __put_user(host_st->st_rdev, &target_st->st_rdev);
6033 /* XXX: better use of kernel struct */
6034 __put_user(host_st->st_size, &target_st->st_size);
6035 __put_user(host_st->st_blksize, &target_st->st_blksize);
6036 __put_user(host_st->st_blocks, &target_st->st_blocks);
6037 __put_user(host_st->st_atime, &target_st->target_st_atime);
6038 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6039 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6040 unlock_user_struct(target_st, target_addr, 1);
6041 }
6042
6043 return 0;
6044}
balrog6a24a772008-09-20 02:23:36 +00006045
pbrookbd0c5662008-05-29 14:34:11 +00006046/* ??? Using host futex calls even when target atomic operations
6047 are not really atomic probably breaks things. However implementing
6048 futexes locally would make futexes shared between multiple processes
6049 tricky. However they're probably useless because guest atomic
6050 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006051static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6052 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006053{
6054 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006055 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006056
6057 /* ??? We assume FUTEX_* constants are the same on both host
6058 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006059#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006060 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006061#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006062 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006063#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006064 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006065 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006066 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006067 if (timeout) {
6068 pts = &ts;
6069 target_to_host_timespec(pts, timeout);
6070 } else {
6071 pts = NULL;
6072 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006073 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006074 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006075 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006076 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006077 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006078 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006079 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006080 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006081 case FUTEX_WAKE_OP:
6082 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6083 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6084 But the prototype takes a `struct timespec *'; insert casts
6085 to satisfy the compiler. We do not need to tswap TIMEOUT
6086 since it's not compared to guest memory. */
6087 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006088 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6089 g2h(uaddr2),
6090 (base_op == FUTEX_CMP_REQUEUE
6091 ? tswap32(val3)
6092 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006093 default:
6094 return -TARGET_ENOSYS;
6095 }
6096}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006097#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6098static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6099 abi_long handle, abi_long mount_id,
6100 abi_long flags)
6101{
6102 struct file_handle *target_fh;
6103 struct file_handle *fh;
6104 int mid = 0;
6105 abi_long ret;
6106 char *name;
6107 unsigned int size, total_size;
6108
6109 if (get_user_s32(size, handle)) {
6110 return -TARGET_EFAULT;
6111 }
6112
6113 name = lock_user_string(pathname);
6114 if (!name) {
6115 return -TARGET_EFAULT;
6116 }
6117
6118 total_size = sizeof(struct file_handle) + size;
6119 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6120 if (!target_fh) {
6121 unlock_user(name, pathname, 0);
6122 return -TARGET_EFAULT;
6123 }
6124
6125 fh = g_malloc0(total_size);
6126 fh->handle_bytes = size;
6127
6128 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6129 unlock_user(name, pathname, 0);
6130
6131 /* man name_to_handle_at(2):
6132 * Other than the use of the handle_bytes field, the caller should treat
6133 * the file_handle structure as an opaque data type
6134 */
6135
6136 memcpy(target_fh, fh, total_size);
6137 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6138 target_fh->handle_type = tswap32(fh->handle_type);
6139 g_free(fh);
6140 unlock_user(target_fh, handle, total_size);
6141
6142 if (put_user_s32(mid, mount_id)) {
6143 return -TARGET_EFAULT;
6144 }
6145
6146 return ret;
6147
6148}
6149#endif
6150
6151#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6152static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6153 abi_long flags)
6154{
6155 struct file_handle *target_fh;
6156 struct file_handle *fh;
6157 unsigned int size, total_size;
6158 abi_long ret;
6159
6160 if (get_user_s32(size, handle)) {
6161 return -TARGET_EFAULT;
6162 }
6163
6164 total_size = sizeof(struct file_handle) + size;
6165 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6166 if (!target_fh) {
6167 return -TARGET_EFAULT;
6168 }
6169
Thomas Huthe9d49d52015-10-09 17:56:38 +02006170 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006171 fh->handle_bytes = size;
6172 fh->handle_type = tswap32(target_fh->handle_type);
6173
6174 ret = get_errno(open_by_handle_at(mount_fd, fh,
6175 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6176
6177 g_free(fh);
6178
6179 unlock_user(target_fh, handle, total_size);
6180
6181 return ret;
6182}
6183#endif
pbrookbd0c5662008-05-29 14:34:11 +00006184
Laurent Viviere36800c2015-10-02 14:48:09 +02006185#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6186
6187/* signalfd siginfo conversion */
6188
6189static void
6190host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6191 const struct signalfd_siginfo *info)
6192{
6193 int sig = host_to_target_signal(info->ssi_signo);
6194
6195 /* linux/signalfd.h defines a ssi_addr_lsb
6196 * not defined in sys/signalfd.h but used by some kernels
6197 */
6198
6199#ifdef BUS_MCEERR_AO
6200 if (tinfo->ssi_signo == SIGBUS &&
6201 (tinfo->ssi_code == BUS_MCEERR_AR ||
6202 tinfo->ssi_code == BUS_MCEERR_AO)) {
6203 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6204 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6205 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6206 }
6207#endif
6208
6209 tinfo->ssi_signo = tswap32(sig);
6210 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6211 tinfo->ssi_code = tswap32(info->ssi_code);
6212 tinfo->ssi_pid = tswap32(info->ssi_pid);
6213 tinfo->ssi_uid = tswap32(info->ssi_uid);
6214 tinfo->ssi_fd = tswap32(info->ssi_fd);
6215 tinfo->ssi_tid = tswap32(info->ssi_tid);
6216 tinfo->ssi_band = tswap32(info->ssi_band);
6217 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6218 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6219 tinfo->ssi_status = tswap32(info->ssi_status);
6220 tinfo->ssi_int = tswap32(info->ssi_int);
6221 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6222 tinfo->ssi_utime = tswap64(info->ssi_utime);
6223 tinfo->ssi_stime = tswap64(info->ssi_stime);
6224 tinfo->ssi_addr = tswap64(info->ssi_addr);
6225}
6226
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006227static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006228{
6229 int i;
6230
6231 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6232 host_to_target_signalfd_siginfo(buf + i, buf + i);
6233 }
6234
6235 return len;
6236}
6237
6238static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006239 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006240};
6241
6242static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6243{
6244 int host_flags;
6245 target_sigset_t *target_mask;
6246 sigset_t host_mask;
6247 abi_long ret;
6248
6249 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6250 return -TARGET_EINVAL;
6251 }
6252 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6253 return -TARGET_EFAULT;
6254 }
6255
6256 target_to_host_sigset(&host_mask, target_mask);
6257
6258 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6259
6260 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6261 if (ret >= 0) {
6262 fd_trans_register(ret, &target_signalfd_trans);
6263 }
6264
6265 unlock_user_struct(target_mask, mask, 0);
6266
6267 return ret;
6268}
6269#endif
6270
pbrook1d9d8b52009-04-16 15:17:02 +00006271/* Map host to target signal numbers for the wait family of syscalls.
6272 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006273int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006274{
6275 if (WIFSIGNALED(status)) {
6276 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6277 }
6278 if (WIFSTOPPED(status)) {
6279 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6280 | (status & 0xff);
6281 }
6282 return status;
6283}
6284
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006285static int open_self_cmdline(void *cpu_env, int fd)
6286{
6287 int fd_orig = -1;
6288 bool word_skipped = false;
6289
6290 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6291 if (fd_orig < 0) {
6292 return fd_orig;
6293 }
6294
6295 while (true) {
6296 ssize_t nb_read;
6297 char buf[128];
6298 char *cp_buf = buf;
6299
6300 nb_read = read(fd_orig, buf, sizeof(buf));
6301 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006302 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006303 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006304 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006305 return -1;
6306 } else if (nb_read == 0) {
6307 break;
6308 }
6309
6310 if (!word_skipped) {
6311 /* Skip the first string, which is the path to qemu-*-static
6312 instead of the actual command. */
6313 cp_buf = memchr(buf, 0, sizeof(buf));
6314 if (cp_buf) {
6315 /* Null byte found, skip one string */
6316 cp_buf++;
6317 nb_read -= cp_buf - buf;
6318 word_skipped = true;
6319 }
6320 }
6321
6322 if (word_skipped) {
6323 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006324 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006325 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006326 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006327 return -1;
6328 }
6329 }
6330 }
6331
6332 return close(fd_orig);
6333}
6334
Alexander Graf36c08d42011-11-02 20:23:24 +01006335static int open_self_maps(void *cpu_env, int fd)
6336{
Andreas Färber0429a972013-08-26 18:14:44 +02006337 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6338 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006339 FILE *fp;
6340 char *line = NULL;
6341 size_t len = 0;
6342 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006343
Alexander Graf1a49ef22012-05-01 16:30:28 +01006344 fp = fopen("/proc/self/maps", "r");
6345 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006346 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006347 }
6348
6349 while ((read = getline(&line, &len, fp)) != -1) {
6350 int fields, dev_maj, dev_min, inode;
6351 uint64_t min, max, offset;
6352 char flag_r, flag_w, flag_x, flag_p;
6353 char path[512] = "";
6354 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6355 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6356 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6357
6358 if ((fields < 10) || (fields > 11)) {
6359 continue;
6360 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006361 if (h2g_valid(min)) {
6362 int flags = page_get_flags(h2g(min));
6363 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6364 if (page_check_range(h2g(min), max - min, flags) == -1) {
6365 continue;
6366 }
6367 if (h2g(min) == ts->info->stack_limit) {
6368 pstrcpy(path, sizeof(path), " [stack]");
6369 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006370 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006371 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006372 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006373 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006374 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006375 }
6376 }
6377
6378 free(line);
6379 fclose(fp);
6380
Alexander Graf36c08d42011-11-02 20:23:24 +01006381 return 0;
6382}
6383
Alexander Graf480b8e72011-11-02 20:23:25 +01006384static int open_self_stat(void *cpu_env, int fd)
6385{
Andreas Färber0429a972013-08-26 18:14:44 +02006386 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6387 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006388 abi_ulong start_stack = ts->info->start_stack;
6389 int i;
6390
6391 for (i = 0; i < 44; i++) {
6392 char buf[128];
6393 int len;
6394 uint64_t val = 0;
6395
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006396 if (i == 0) {
6397 /* pid */
6398 val = getpid();
6399 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6400 } else if (i == 1) {
6401 /* app name */
6402 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6403 } else if (i == 27) {
6404 /* stack bottom */
6405 val = start_stack;
6406 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6407 } else {
6408 /* for the rest, there is MasterCard */
6409 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006410 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006411
Alexander Graf480b8e72011-11-02 20:23:25 +01006412 len = strlen(buf);
6413 if (write(fd, buf, len) != len) {
6414 return -1;
6415 }
6416 }
6417
6418 return 0;
6419}
6420
Alexander Graf257450e2011-11-02 20:23:26 +01006421static int open_self_auxv(void *cpu_env, int fd)
6422{
Andreas Färber0429a972013-08-26 18:14:44 +02006423 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6424 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006425 abi_ulong auxv = ts->info->saved_auxv;
6426 abi_ulong len = ts->info->auxv_len;
6427 char *ptr;
6428
6429 /*
6430 * Auxiliary vector is stored in target process stack.
6431 * read in whole auxv vector and copy it to file
6432 */
6433 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6434 if (ptr != NULL) {
6435 while (len > 0) {
6436 ssize_t r;
6437 r = write(fd, ptr, len);
6438 if (r <= 0) {
6439 break;
6440 }
6441 len -= r;
6442 ptr += r;
6443 }
6444 lseek(fd, 0, SEEK_SET);
6445 unlock_user(ptr, auxv, len);
6446 }
6447
6448 return 0;
6449}
6450
Andreas Schwab463d8e72013-07-02 14:04:12 +01006451static int is_proc_myself(const char *filename, const char *entry)
6452{
6453 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6454 filename += strlen("/proc/");
6455 if (!strncmp(filename, "self/", strlen("self/"))) {
6456 filename += strlen("self/");
6457 } else if (*filename >= '1' && *filename <= '9') {
6458 char myself[80];
6459 snprintf(myself, sizeof(myself), "%d/", getpid());
6460 if (!strncmp(filename, myself, strlen(myself))) {
6461 filename += strlen(myself);
6462 } else {
6463 return 0;
6464 }
6465 } else {
6466 return 0;
6467 }
6468 if (!strcmp(filename, entry)) {
6469 return 1;
6470 }
6471 }
6472 return 0;
6473}
6474
Laurent Vivierde6b9932013-08-30 01:46:40 +02006475#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6476static int is_proc(const char *filename, const char *entry)
6477{
6478 return strcmp(filename, entry) == 0;
6479}
6480
6481static int open_net_route(void *cpu_env, int fd)
6482{
6483 FILE *fp;
6484 char *line = NULL;
6485 size_t len = 0;
6486 ssize_t read;
6487
6488 fp = fopen("/proc/net/route", "r");
6489 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006490 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006491 }
6492
6493 /* read header */
6494
6495 read = getline(&line, &len, fp);
6496 dprintf(fd, "%s", line);
6497
6498 /* read routes */
6499
6500 while ((read = getline(&line, &len, fp)) != -1) {
6501 char iface[16];
6502 uint32_t dest, gw, mask;
6503 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6504 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6505 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6506 &mask, &mtu, &window, &irtt);
6507 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6508 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6509 metric, tswap32(mask), mtu, window, irtt);
6510 }
6511
6512 free(line);
6513 fclose(fp);
6514
6515 return 0;
6516}
6517#endif
6518
Riku Voipio0b2effd2014-08-06 10:36:37 +03006519static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006520{
6521 struct fake_open {
6522 const char *filename;
6523 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006524 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006525 };
6526 const struct fake_open *fake_open;
6527 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006528 { "maps", open_self_maps, is_proc_myself },
6529 { "stat", open_self_stat, is_proc_myself },
6530 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006531 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006532#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6533 { "/proc/net/route", open_net_route, is_proc },
6534#endif
6535 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006536 };
6537
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006538 if (is_proc_myself(pathname, "exe")) {
6539 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006540 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006541 }
6542
Alexander Graf3be14d02011-11-02 20:23:23 +01006543 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006544 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006545 break;
6546 }
6547 }
6548
6549 if (fake_open->filename) {
6550 const char *tmpdir;
6551 char filename[PATH_MAX];
6552 int fd, r;
6553
6554 /* create temporary file to map stat to */
6555 tmpdir = getenv("TMPDIR");
6556 if (!tmpdir)
6557 tmpdir = "/tmp";
6558 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6559 fd = mkstemp(filename);
6560 if (fd < 0) {
6561 return fd;
6562 }
6563 unlink(filename);
6564
6565 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006566 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006567 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006568 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006569 return r;
6570 }
6571 lseek(fd, 0, SEEK_SET);
6572
6573 return fd;
6574 }
6575
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006576 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006577}
6578
Alexander Grafaecc8862014-11-10 21:33:03 +01006579#define TIMER_MAGIC 0x0caf0000
6580#define TIMER_MAGIC_MASK 0xffff0000
6581
6582/* Convert QEMU provided timer ID back to internal 16bit index format */
6583static target_timer_t get_timer_id(abi_long arg)
6584{
6585 target_timer_t timerid = arg;
6586
6587 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6588 return -TARGET_EINVAL;
6589 }
6590
6591 timerid &= 0xffff;
6592
6593 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6594 return -TARGET_EINVAL;
6595 }
6596
6597 return timerid;
6598}
6599
ths0da46a62007-10-20 20:23:07 +00006600/* do_syscall() should always have a single exit point at the end so
6601 that actions, such as logging of syscall results, can be performed.
6602 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006603abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6604 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006605 abi_long arg5, abi_long arg6, abi_long arg7,
6606 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006607{
Andreas Färber182735e2013-05-29 22:29:20 +02006608 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006609 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006610 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006611 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006612 void *p;
ths3b46e622007-09-17 08:09:54 +00006613
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006614#if defined(DEBUG_ERESTARTSYS)
6615 /* Debug-only code for exercising the syscall-restart code paths
6616 * in the per-architecture cpu main loops: restart every syscall
6617 * the guest makes once before letting it through.
6618 */
6619 {
6620 static int flag;
6621
6622 flag = !flag;
6623 if (flag) {
6624 return -TARGET_ERESTARTSYS;
6625 }
6626 }
6627#endif
6628
bellard72f03902003-02-18 23:33:18 +00006629#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006630 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006631#endif
thsb92c47c2007-11-01 00:07:38 +00006632 if(do_strace)
6633 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6634
bellard31e31b82003-02-18 22:55:36 +00006635 switch(num) {
6636 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006637 /* In old applications this may be used to implement _exit(2).
6638 However in threaded applictions it is used for thread termination,
6639 and _exit_group is used for application termination.
6640 Do thread termination if we have more then one thread. */
6641 /* FIXME: This probably breaks if a signal arrives. We should probably
6642 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006643 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006644 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006645
Andreas Färber9b056fc2013-06-24 23:53:10 +02006646 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006647 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006648 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006649 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006650 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006651 if (ts->child_tidptr) {
6652 put_user_u32(0, ts->child_tidptr);
6653 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6654 NULL, NULL, 0);
6655 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006656 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006657 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006658 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006659 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006660 pthread_exit(NULL);
6661 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006662#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006663 _mcleanup();
6664#endif
bellarde9009672005-04-26 20:42:36 +00006665 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006666 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006667 ret = 0; /* avoid warning */
6668 break;
6669 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006670 if (arg3 == 0)
6671 ret = 0;
6672 else {
6673 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6674 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006675 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006676 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006677 fd_trans_host_to_target_data(arg1)) {
6678 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006679 }
aurel3238d840e2009-01-30 19:48:17 +00006680 unlock_user(p, arg2, ret);
6681 }
bellard31e31b82003-02-18 22:55:36 +00006682 break;
6683 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006684 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6685 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006686 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006687 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006688 break;
Chen Gang704eff62015-08-21 05:37:33 +08006689#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006690 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006691 if (!(p = lock_user_string(arg1)))
6692 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006693 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6694 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6695 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006696 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006697 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006698 break;
Chen Gang704eff62015-08-21 05:37:33 +08006699#endif
ths82424832007-09-24 09:21:55 +00006700 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006701 if (!(p = lock_user_string(arg2)))
6702 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006703 ret = get_errno(do_openat(cpu_env, arg1, p,
6704 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6705 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006706 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006707 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006708 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006709#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6710 case TARGET_NR_name_to_handle_at:
6711 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6712 break;
6713#endif
6714#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6715 case TARGET_NR_open_by_handle_at:
6716 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006717 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006718 break;
6719#endif
bellard31e31b82003-02-18 22:55:36 +00006720 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006721 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006722 ret = get_errno(close(arg1));
6723 break;
6724 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006725 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006726 break;
Chen Gang704eff62015-08-21 05:37:33 +08006727#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006728 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006729 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006730 break;
Chen Gang704eff62015-08-21 05:37:33 +08006731#endif
thse5febef2007-04-01 18:31:35 +00006732#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006733 case TARGET_NR_waitpid:
6734 {
pbrook53a59602006-03-25 19:31:22 +00006735 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006736 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006737 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006738 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006739 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006740 }
6741 break;
thse5febef2007-04-01 18:31:35 +00006742#endif
pbrookf0cbb612008-05-30 18:20:05 +00006743#ifdef TARGET_NR_waitid
6744 case TARGET_NR_waitid:
6745 {
6746 siginfo_t info;
6747 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006748 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006749 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006750 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006751 goto efault;
6752 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006753 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006754 }
6755 }
6756 break;
6757#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006758#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006759 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006760 if (!(p = lock_user_string(arg1)))
6761 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006762 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006763 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006764 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006765 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006766#endif
Chen Gang704eff62015-08-21 05:37:33 +08006767#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006768 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006769 {
6770 void * p2;
6771 p = lock_user_string(arg1);
6772 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006773 if (!p || !p2)
6774 ret = -TARGET_EFAULT;
6775 else
6776 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006777 unlock_user(p2, arg2, 0);
6778 unlock_user(p, arg1, 0);
6779 }
bellard31e31b82003-02-18 22:55:36 +00006780 break;
Chen Gang704eff62015-08-21 05:37:33 +08006781#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006782#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006783 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006784 {
6785 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006786 if (!arg2 || !arg4)
6787 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006788 p = lock_user_string(arg2);
6789 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006790 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006791 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006792 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006793 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006794 unlock_user(p, arg2, 0);
6795 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006796 }
6797 break;
6798#endif
Chen Gang704eff62015-08-21 05:37:33 +08006799#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006800 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006801 if (!(p = lock_user_string(arg1)))
6802 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006803 ret = get_errno(unlink(p));
6804 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006805 break;
Chen Gang704eff62015-08-21 05:37:33 +08006806#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006807#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006808 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006809 if (!(p = lock_user_string(arg2)))
6810 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006811 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006812 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006813 break;
balrogb7d35e62007-12-12 00:40:24 +00006814#endif
bellard31e31b82003-02-18 22:55:36 +00006815 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006816 {
6817 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006818 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006819 abi_ulong gp;
6820 abi_ulong guest_argp;
6821 abi_ulong guest_envp;
6822 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006823 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006824 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006825
bellardf7341ff2003-03-30 21:00:25 +00006826 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006827 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006828 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006829 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006830 goto efault;
ths03aa1972007-12-02 06:28:08 +00006831 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006832 break;
bellard7854b052003-03-29 17:22:23 +00006833 argc++;
bellard2f619692007-11-16 10:46:05 +00006834 }
bellardf7341ff2003-03-30 21:00:25 +00006835 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006836 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006837 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006838 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006839 goto efault;
ths03aa1972007-12-02 06:28:08 +00006840 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006841 break;
bellard7854b052003-03-29 17:22:23 +00006842 envc++;
bellard2f619692007-11-16 10:46:05 +00006843 }
bellard7854b052003-03-29 17:22:23 +00006844
bellardf7341ff2003-03-30 21:00:25 +00006845 argp = alloca((argc + 1) * sizeof(void *));
6846 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006847
pbrookda94d262008-05-30 18:24:00 +00006848 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006849 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006850 if (get_user_ual(addr, gp))
6851 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006852 if (!addr)
6853 break;
bellard2f619692007-11-16 10:46:05 +00006854 if (!(*q = lock_user_string(addr)))
6855 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006856 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006857 }
bellardf7341ff2003-03-30 21:00:25 +00006858 *q = NULL;
6859
pbrookda94d262008-05-30 18:24:00 +00006860 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006861 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006862 if (get_user_ual(addr, gp))
6863 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006864 if (!addr)
6865 break;
bellard2f619692007-11-16 10:46:05 +00006866 if (!(*q = lock_user_string(addr)))
6867 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006868 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006869 }
bellardf7341ff2003-03-30 21:00:25 +00006870 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006871
bellard2f619692007-11-16 10:46:05 +00006872 if (!(p = lock_user_string(arg1)))
6873 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01006874 /* Although execve() is not an interruptible syscall it is
6875 * a special case where we must use the safe_syscall wrapper:
6876 * if we allow a signal to happen before we make the host
6877 * syscall then we will 'lose' it, because at the point of
6878 * execve the process leaves QEMU's control. So we use the
6879 * safe syscall wrapper to ensure that we either take the
6880 * signal as a guest signal, or else it does not happen
6881 * before the execve completes and makes it the other
6882 * program's problem.
6883 */
6884 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00006885 unlock_user(p, arg1, 0);
6886
bellard2f619692007-11-16 10:46:05 +00006887 goto execve_end;
6888
6889 execve_efault:
6890 ret = -TARGET_EFAULT;
6891
6892 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006893 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006894 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006895 if (get_user_ual(addr, gp)
6896 || !addr)
6897 break;
pbrook53a59602006-03-25 19:31:22 +00006898 unlock_user(*q, addr, 0);
6899 }
6900 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006901 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006902 if (get_user_ual(addr, gp)
6903 || !addr)
6904 break;
pbrook53a59602006-03-25 19:31:22 +00006905 unlock_user(*q, addr, 0);
6906 }
bellard7854b052003-03-29 17:22:23 +00006907 }
bellard31e31b82003-02-18 22:55:36 +00006908 break;
6909 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006910 if (!(p = lock_user_string(arg1)))
6911 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006912 ret = get_errno(chdir(p));
6913 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006914 break;
bellarda315a142005-01-30 22:59:18 +00006915#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006916 case TARGET_NR_time:
6917 {
pbrook53a59602006-03-25 19:31:22 +00006918 time_t host_time;
6919 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006920 if (!is_error(ret)
6921 && arg1
6922 && put_user_sal(host_time, arg1))
6923 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006924 }
6925 break;
bellarda315a142005-01-30 22:59:18 +00006926#endif
Chen Gang704eff62015-08-21 05:37:33 +08006927#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006928 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006929 if (!(p = lock_user_string(arg1)))
6930 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006931 ret = get_errno(mknod(p, arg2, arg3));
6932 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006933 break;
Chen Gang704eff62015-08-21 05:37:33 +08006934#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006935#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006936 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006937 if (!(p = lock_user_string(arg2)))
6938 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006939 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00006940 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00006941 break;
6942#endif
Chen Gang704eff62015-08-21 05:37:33 +08006943#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00006944 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00006945 if (!(p = lock_user_string(arg1)))
6946 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006947 ret = get_errno(chmod(p, arg2));
6948 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006949 break;
Chen Gang704eff62015-08-21 05:37:33 +08006950#endif
bellardebc05482003-09-30 21:08:41 +00006951#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00006952 case TARGET_NR_break:
6953 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006954#endif
6955#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00006956 case TARGET_NR_oldstat:
6957 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006958#endif
bellard31e31b82003-02-18 22:55:36 +00006959 case TARGET_NR_lseek:
6960 ret = get_errno(lseek(arg1, arg2, arg3));
6961 break;
Richard Henderson92317332010-05-03 10:07:53 -07006962#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
6963 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00006964 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07006965 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00006966 ret = get_errno(getpid());
6967 break;
Richard Henderson92317332010-05-03 10:07:53 -07006968#endif
6969#ifdef TARGET_NR_getpid
6970 case TARGET_NR_getpid:
6971 ret = get_errno(getpid());
6972 break;
6973#endif
bellard31e31b82003-02-18 22:55:36 +00006974 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01006975 {
6976 /* need to look at the data field */
6977 void *p2, *p3;
6978
6979 if (arg1) {
6980 p = lock_user_string(arg1);
6981 if (!p) {
6982 goto efault;
6983 }
6984 } else {
6985 p = NULL;
6986 }
6987
6988 p2 = lock_user_string(arg2);
6989 if (!p2) {
6990 if (arg1) {
6991 unlock_user(p, arg1, 0);
6992 }
6993 goto efault;
6994 }
6995
6996 if (arg3) {
6997 p3 = lock_user_string(arg3);
6998 if (!p3) {
6999 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007000 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007001 }
7002 unlock_user(p2, arg2, 0);
7003 goto efault;
7004 }
7005 } else {
7006 p3 = NULL;
7007 }
7008
7009 /* FIXME - arg5 should be locked, but it isn't clear how to
7010 * do that since it's not guaranteed to be a NULL-terminated
7011 * string.
7012 */
7013 if (!arg5) {
7014 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7015 } else {
7016 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7017 }
7018 ret = get_errno(ret);
7019
7020 if (arg1) {
7021 unlock_user(p, arg1, 0);
7022 }
7023 unlock_user(p2, arg2, 0);
7024 if (arg3) {
7025 unlock_user(p3, arg3, 0);
7026 }
7027 }
7028 break;
thse5febef2007-04-01 18:31:35 +00007029#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007030 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007031 if (!(p = lock_user_string(arg1)))
7032 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007033 ret = get_errno(umount(p));
7034 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007035 break;
thse5febef2007-04-01 18:31:35 +00007036#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007037#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007038 case TARGET_NR_stime:
7039 {
pbrook53a59602006-03-25 19:31:22 +00007040 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007041 if (get_user_sal(host_time, arg1))
7042 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007043 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007044 }
7045 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007046#endif
bellard31e31b82003-02-18 22:55:36 +00007047 case TARGET_NR_ptrace:
7048 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007049#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007050 case TARGET_NR_alarm:
7051 ret = alarm(arg1);
7052 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007053#endif
bellardebc05482003-09-30 21:08:41 +00007054#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007055 case TARGET_NR_oldfstat:
7056 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007057#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007058#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007059 case TARGET_NR_pause:
7060 ret = get_errno(pause());
7061 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007062#endif
thse5febef2007-04-01 18:31:35 +00007063#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007064 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007065 {
pbrook53a59602006-03-25 19:31:22 +00007066 struct utimbuf tbuf, *host_tbuf;
7067 struct target_utimbuf *target_tbuf;
7068 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007069 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7070 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007071 tbuf.actime = tswapal(target_tbuf->actime);
7072 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007073 unlock_user_struct(target_tbuf, arg2, 0);
7074 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007075 } else {
pbrook53a59602006-03-25 19:31:22 +00007076 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007077 }
bellard579a97f2007-11-11 14:26:47 +00007078 if (!(p = lock_user_string(arg1)))
7079 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007080 ret = get_errno(utime(p, host_tbuf));
7081 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007082 }
7083 break;
thse5febef2007-04-01 18:31:35 +00007084#endif
Chen Gang704eff62015-08-21 05:37:33 +08007085#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007086 case TARGET_NR_utimes:
7087 {
bellard978a66f2004-12-06 22:58:05 +00007088 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007089 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007090 if (copy_from_user_timeval(&tv[0], arg2)
7091 || copy_from_user_timeval(&tv[1],
7092 arg2 + sizeof(struct target_timeval)))
7093 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007094 tvp = tv;
7095 } else {
7096 tvp = NULL;
7097 }
bellard579a97f2007-11-11 14:26:47 +00007098 if (!(p = lock_user_string(arg1)))
7099 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007100 ret = get_errno(utimes(p, tvp));
7101 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007102 }
7103 break;
Chen Gang704eff62015-08-21 05:37:33 +08007104#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007105#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007106 case TARGET_NR_futimesat:
7107 {
7108 struct timeval *tvp, tv[2];
7109 if (arg3) {
7110 if (copy_from_user_timeval(&tv[0], arg3)
7111 || copy_from_user_timeval(&tv[1],
7112 arg3 + sizeof(struct target_timeval)))
7113 goto efault;
7114 tvp = tv;
7115 } else {
7116 tvp = NULL;
7117 }
7118 if (!(p = lock_user_string(arg2)))
7119 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007120 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007121 unlock_user(p, arg2, 0);
7122 }
7123 break;
7124#endif
bellardebc05482003-09-30 21:08:41 +00007125#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007126 case TARGET_NR_stty:
7127 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007128#endif
7129#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007130 case TARGET_NR_gtty:
7131 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007132#endif
Chen Gang704eff62015-08-21 05:37:33 +08007133#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007134 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007135 if (!(p = lock_user_string(arg1)))
7136 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007137 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007138 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007139 break;
Chen Gang704eff62015-08-21 05:37:33 +08007140#endif
ths92a34c12007-09-24 09:27:49 +00007141#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7142 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007143 if (!(p = lock_user_string(arg2)))
7144 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007145 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007146 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007147 break;
7148#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007149#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007150 case TARGET_NR_nice:
7151 ret = get_errno(nice(arg1));
7152 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007153#endif
bellardebc05482003-09-30 21:08:41 +00007154#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007155 case TARGET_NR_ftime:
7156 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007157#endif
bellard31e31b82003-02-18 22:55:36 +00007158 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007159 sync();
7160 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007161 break;
7162 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00007163 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007164 break;
Chen Gang704eff62015-08-21 05:37:33 +08007165#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007166 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007167 {
7168 void *p2;
7169 p = lock_user_string(arg1);
7170 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007171 if (!p || !p2)
7172 ret = -TARGET_EFAULT;
7173 else
7174 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007175 unlock_user(p2, arg2, 0);
7176 unlock_user(p, arg1, 0);
7177 }
bellard31e31b82003-02-18 22:55:36 +00007178 break;
Chen Gang704eff62015-08-21 05:37:33 +08007179#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007180#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007181 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007182 {
bellard579a97f2007-11-11 14:26:47 +00007183 void *p2;
ths722183f2007-09-24 09:24:37 +00007184 p = lock_user_string(arg2);
7185 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007186 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007187 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007188 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007189 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007190 unlock_user(p2, arg4, 0);
7191 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007192 }
7193 break;
7194#endif
Chen Gang704eff62015-08-21 05:37:33 +08007195#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007196 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007197 if (!(p = lock_user_string(arg1)))
7198 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007199 ret = get_errno(mkdir(p, arg2));
7200 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007201 break;
Chen Gang704eff62015-08-21 05:37:33 +08007202#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007203#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007204 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007205 if (!(p = lock_user_string(arg2)))
7206 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007207 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007208 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007209 break;
7210#endif
Chen Gang704eff62015-08-21 05:37:33 +08007211#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007212 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007213 if (!(p = lock_user_string(arg1)))
7214 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007215 ret = get_errno(rmdir(p));
7216 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007217 break;
Chen Gang704eff62015-08-21 05:37:33 +08007218#endif
bellard31e31b82003-02-18 22:55:36 +00007219 case TARGET_NR_dup:
7220 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007221 if (ret >= 0) {
7222 fd_trans_dup(arg1, ret);
7223 }
bellard31e31b82003-02-18 22:55:36 +00007224 break;
Chen Gang704eff62015-08-21 05:37:33 +08007225#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007226 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007227 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007228 break;
Chen Gang704eff62015-08-21 05:37:33 +08007229#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007230#ifdef TARGET_NR_pipe2
7231 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007232 ret = do_pipe(cpu_env, arg1,
7233 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007234 break;
7235#endif
bellard31e31b82003-02-18 22:55:36 +00007236 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007237 {
pbrook53a59602006-03-25 19:31:22 +00007238 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007239 struct tms tms;
7240 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007241 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007242 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7243 if (!tmsp)
7244 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007245 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7246 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7247 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7248 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007249 }
bellardc596ed12003-07-13 17:32:31 +00007250 if (!is_error(ret))
7251 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007252 }
7253 break;
bellardebc05482003-09-30 21:08:41 +00007254#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007255 case TARGET_NR_prof:
7256 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007257#endif
thse5febef2007-04-01 18:31:35 +00007258#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007259 case TARGET_NR_signal:
7260 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007261#endif
bellard31e31b82003-02-18 22:55:36 +00007262 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007263 if (arg1 == 0) {
7264 ret = get_errno(acct(NULL));
7265 } else {
7266 if (!(p = lock_user_string(arg1)))
7267 goto efault;
7268 ret = get_errno(acct(path(p)));
7269 unlock_user(p, arg1, 0);
7270 }
pbrook24836682006-04-16 14:14:53 +00007271 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007272#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007273 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007274 if (!(p = lock_user_string(arg1)))
7275 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007276 ret = get_errno(umount2(p, arg2));
7277 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007278 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007279#endif
bellardebc05482003-09-30 21:08:41 +00007280#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007281 case TARGET_NR_lock:
7282 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007283#endif
bellard31e31b82003-02-18 22:55:36 +00007284 case TARGET_NR_ioctl:
7285 ret = do_ioctl(arg1, arg2, arg3);
7286 break;
7287 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007288 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007289 break;
bellardebc05482003-09-30 21:08:41 +00007290#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007291 case TARGET_NR_mpx:
7292 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007293#endif
bellard31e31b82003-02-18 22:55:36 +00007294 case TARGET_NR_setpgid:
7295 ret = get_errno(setpgid(arg1, arg2));
7296 break;
bellardebc05482003-09-30 21:08:41 +00007297#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007298 case TARGET_NR_ulimit:
7299 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007300#endif
7301#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_oldolduname:
7303 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007304#endif
bellard31e31b82003-02-18 22:55:36 +00007305 case TARGET_NR_umask:
7306 ret = get_errno(umask(arg1));
7307 break;
7308 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007309 if (!(p = lock_user_string(arg1)))
7310 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007311 ret = get_errno(chroot(p));
7312 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007313 break;
Chen Gang704eff62015-08-21 05:37:33 +08007314#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007315 case TARGET_NR_ustat:
7316 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007317#endif
7318#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007319 case TARGET_NR_dup2:
7320 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007321 if (ret >= 0) {
7322 fd_trans_dup(arg1, arg2);
7323 }
bellard31e31b82003-02-18 22:55:36 +00007324 break;
Chen Gang704eff62015-08-21 05:37:33 +08007325#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007326#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7327 case TARGET_NR_dup3:
7328 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007329 if (ret >= 0) {
7330 fd_trans_dup(arg1, arg2);
7331 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007332 break;
7333#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007334#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007335 case TARGET_NR_getppid:
7336 ret = get_errno(getppid());
7337 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007338#endif
Chen Gang704eff62015-08-21 05:37:33 +08007339#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007340 case TARGET_NR_getpgrp:
7341 ret = get_errno(getpgrp());
7342 break;
Chen Gang704eff62015-08-21 05:37:33 +08007343#endif
bellard31e31b82003-02-18 22:55:36 +00007344 case TARGET_NR_setsid:
7345 ret = get_errno(setsid());
7346 break;
thse5febef2007-04-01 18:31:35 +00007347#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007348 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007349 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007350#if defined(TARGET_ALPHA)
7351 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007352 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007353 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007354 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7355 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007356 act._sa_handler = old_act->_sa_handler;
7357 target_siginitset(&act.sa_mask, old_act->sa_mask);
7358 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007359 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007360 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007361 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007362 }
7363 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007364 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007365 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7366 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007367 old_act->_sa_handler = oact._sa_handler;
7368 old_act->sa_mask = oact.sa_mask.sig[0];
7369 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007370 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007371 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007372#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007373 struct target_sigaction act, oact, *pact, *old_act;
7374
7375 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007376 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7377 goto efault;
bellard106ec872006-06-27 21:08:10 +00007378 act._sa_handler = old_act->_sa_handler;
7379 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7380 act.sa_flags = old_act->sa_flags;
7381 unlock_user_struct(old_act, arg2, 0);
7382 pact = &act;
7383 } else {
7384 pact = NULL;
7385 }
7386
7387 ret = get_errno(do_sigaction(arg1, pact, &oact));
7388
7389 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007390 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7391 goto efault;
bellard106ec872006-06-27 21:08:10 +00007392 old_act->_sa_handler = oact._sa_handler;
7393 old_act->sa_flags = oact.sa_flags;
7394 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7395 old_act->sa_mask.sig[1] = 0;
7396 old_act->sa_mask.sig[2] = 0;
7397 old_act->sa_mask.sig[3] = 0;
7398 unlock_user_struct(old_act, arg3, 1);
7399 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007400#else
7401 struct target_old_sigaction *old_act;
7402 struct target_sigaction act, oact, *pact;
7403 if (arg2) {
7404 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7405 goto efault;
7406 act._sa_handler = old_act->_sa_handler;
7407 target_siginitset(&act.sa_mask, old_act->sa_mask);
7408 act.sa_flags = old_act->sa_flags;
7409 act.sa_restorer = old_act->sa_restorer;
7410 unlock_user_struct(old_act, arg2, 0);
7411 pact = &act;
7412 } else {
7413 pact = NULL;
7414 }
7415 ret = get_errno(do_sigaction(arg1, pact, &oact));
7416 if (!is_error(ret) && arg3) {
7417 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7418 goto efault;
7419 old_act->_sa_handler = oact._sa_handler;
7420 old_act->sa_mask = oact.sa_mask.sig[0];
7421 old_act->sa_flags = oact.sa_flags;
7422 old_act->sa_restorer = oact.sa_restorer;
7423 unlock_user_struct(old_act, arg3, 1);
7424 }
ths388bb212007-05-13 13:58:00 +00007425#endif
bellard31e31b82003-02-18 22:55:36 +00007426 }
7427 break;
thse5febef2007-04-01 18:31:35 +00007428#endif
bellard66fb9762003-03-23 01:06:05 +00007429 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007430 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007431#if defined(TARGET_ALPHA)
7432 struct target_sigaction act, oact, *pact = 0;
7433 struct target_rt_sigaction *rt_act;
7434 /* ??? arg4 == sizeof(sigset_t). */
7435 if (arg2) {
7436 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7437 goto efault;
7438 act._sa_handler = rt_act->_sa_handler;
7439 act.sa_mask = rt_act->sa_mask;
7440 act.sa_flags = rt_act->sa_flags;
7441 act.sa_restorer = arg5;
7442 unlock_user_struct(rt_act, arg2, 0);
7443 pact = &act;
7444 }
7445 ret = get_errno(do_sigaction(arg1, pact, &oact));
7446 if (!is_error(ret) && arg3) {
7447 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7448 goto efault;
7449 rt_act->_sa_handler = oact._sa_handler;
7450 rt_act->sa_mask = oact.sa_mask;
7451 rt_act->sa_flags = oact.sa_flags;
7452 unlock_user_struct(rt_act, arg3, 1);
7453 }
7454#else
pbrook53a59602006-03-25 19:31:22 +00007455 struct target_sigaction *act;
7456 struct target_sigaction *oact;
7457
bellard579a97f2007-11-11 14:26:47 +00007458 if (arg2) {
7459 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7460 goto efault;
7461 } else
pbrook53a59602006-03-25 19:31:22 +00007462 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007463 if (arg3) {
7464 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7465 ret = -TARGET_EFAULT;
7466 goto rt_sigaction_fail;
7467 }
7468 } else
pbrook53a59602006-03-25 19:31:22 +00007469 oact = NULL;
7470 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007471 rt_sigaction_fail:
7472 if (act)
pbrook53a59602006-03-25 19:31:22 +00007473 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007474 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007475 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007476#endif
pbrook53a59602006-03-25 19:31:22 +00007477 }
bellard66fb9762003-03-23 01:06:05 +00007478 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007479#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007480 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007481 {
7482 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007483 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00007484 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00007485 host_to_target_old_sigset(&target_set, &cur_set);
7486 ret = target_set;
7487 }
7488 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007489#endif
7490#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007491 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007492 {
7493 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007494 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00007495 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00007496 target_to_host_old_sigset(&set, &target_set);
7497 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00007498 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00007499 host_to_target_old_sigset(&target_set, &oset);
7500 ret = target_set;
7501 }
7502 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007503#endif
thse5febef2007-04-01 18:31:35 +00007504#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007505 case TARGET_NR_sigprocmask:
7506 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007507#if defined(TARGET_ALPHA)
7508 sigset_t set, oldset;
7509 abi_ulong mask;
7510 int how;
7511
7512 switch (arg1) {
7513 case TARGET_SIG_BLOCK:
7514 how = SIG_BLOCK;
7515 break;
7516 case TARGET_SIG_UNBLOCK:
7517 how = SIG_UNBLOCK;
7518 break;
7519 case TARGET_SIG_SETMASK:
7520 how = SIG_SETMASK;
7521 break;
7522 default:
7523 ret = -TARGET_EINVAL;
7524 goto fail;
7525 }
7526 mask = arg2;
7527 target_to_host_old_sigset(&set, &mask);
7528
Alex Barcelo1c275922014-03-14 14:36:55 +00007529 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07007530 if (!is_error(ret)) {
7531 host_to_target_old_sigset(&mask, &oldset);
7532 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007533 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007534 }
7535#else
bellard66fb9762003-03-23 01:06:05 +00007536 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007537 int how;
ths3b46e622007-09-17 08:09:54 +00007538
pbrook53a59602006-03-25 19:31:22 +00007539 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007540 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007541 case TARGET_SIG_BLOCK:
7542 how = SIG_BLOCK;
7543 break;
7544 case TARGET_SIG_UNBLOCK:
7545 how = SIG_UNBLOCK;
7546 break;
7547 case TARGET_SIG_SETMASK:
7548 how = SIG_SETMASK;
7549 break;
7550 default:
ths0da46a62007-10-20 20:23:07 +00007551 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007552 goto fail;
7553 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007554 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007555 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007556 target_to_host_old_sigset(&set, p);
7557 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007558 set_ptr = &set;
7559 } else {
7560 how = 0;
7561 set_ptr = NULL;
7562 }
Alex Barcelo1c275922014-03-14 14:36:55 +00007563 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00007564 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007565 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007566 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007567 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007568 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007569 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007570#endif
bellard66fb9762003-03-23 01:06:05 +00007571 }
7572 break;
thse5febef2007-04-01 18:31:35 +00007573#endif
bellard66fb9762003-03-23 01:06:05 +00007574 case TARGET_NR_rt_sigprocmask:
7575 {
7576 int how = arg1;
7577 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007578
pbrook53a59602006-03-25 19:31:22 +00007579 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007580 switch(how) {
7581 case TARGET_SIG_BLOCK:
7582 how = SIG_BLOCK;
7583 break;
7584 case TARGET_SIG_UNBLOCK:
7585 how = SIG_UNBLOCK;
7586 break;
7587 case TARGET_SIG_SETMASK:
7588 how = SIG_SETMASK;
7589 break;
7590 default:
ths0da46a62007-10-20 20:23:07 +00007591 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007592 goto fail;
7593 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007594 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007595 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007596 target_to_host_sigset(&set, p);
7597 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007598 set_ptr = &set;
7599 } else {
7600 how = 0;
7601 set_ptr = NULL;
7602 }
Alex Barcelo1c275922014-03-14 14:36:55 +00007603 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00007604 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007605 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007606 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007607 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007608 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007609 }
7610 }
7611 break;
thse5febef2007-04-01 18:31:35 +00007612#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007613 case TARGET_NR_sigpending:
7614 {
7615 sigset_t set;
7616 ret = get_errno(sigpending(&set));
7617 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007618 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007619 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007620 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007621 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007622 }
7623 }
7624 break;
thse5febef2007-04-01 18:31:35 +00007625#endif
bellard66fb9762003-03-23 01:06:05 +00007626 case TARGET_NR_rt_sigpending:
7627 {
7628 sigset_t set;
7629 ret = get_errno(sigpending(&set));
7630 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007631 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007632 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007633 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007634 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007635 }
7636 }
7637 break;
thse5febef2007-04-01 18:31:35 +00007638#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007639 case TARGET_NR_sigsuspend:
7640 {
7641 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007642#if defined(TARGET_ALPHA)
7643 abi_ulong mask = arg1;
7644 target_to_host_old_sigset(&set, &mask);
7645#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007646 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007647 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007648 target_to_host_old_sigset(&set, p);
7649 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007650#endif
bellard66fb9762003-03-23 01:06:05 +00007651 ret = get_errno(sigsuspend(&set));
7652 }
7653 break;
thse5febef2007-04-01 18:31:35 +00007654#endif
bellard66fb9762003-03-23 01:06:05 +00007655 case TARGET_NR_rt_sigsuspend:
7656 {
7657 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05007658 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007659 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007660 target_to_host_sigset(&set, p);
7661 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007662 ret = get_errno(sigsuspend(&set));
7663 }
7664 break;
7665 case TARGET_NR_rt_sigtimedwait:
7666 {
bellard66fb9762003-03-23 01:06:05 +00007667 sigset_t set;
7668 struct timespec uts, *puts;
7669 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007670
Anthony Liguoric227f092009-10-01 16:12:16 -05007671 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007672 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007673 target_to_host_sigset(&set, p);
7674 unlock_user(p, arg1, 0);
7675 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007676 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007677 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007678 } else {
7679 puts = NULL;
7680 }
7681 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007682 if (!is_error(ret)) {
7683 if (arg2) {
7684 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7685 0);
7686 if (!p) {
7687 goto efault;
7688 }
7689 host_to_target_siginfo(p, &uinfo);
7690 unlock_user(p, arg2, sizeof(target_siginfo_t));
7691 }
7692 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007693 }
7694 }
7695 break;
7696 case TARGET_NR_rt_sigqueueinfo:
7697 {
7698 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05007699 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007700 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007701 target_to_host_siginfo(&uinfo, p);
7702 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007703 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7704 }
7705 break;
thse5febef2007-04-01 18:31:35 +00007706#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007707 case TARGET_NR_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007708 ret = do_sigreturn(cpu_env);
7709 break;
thse5febef2007-04-01 18:31:35 +00007710#endif
bellard66fb9762003-03-23 01:06:05 +00007711 case TARGET_NR_rt_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007712 ret = do_rt_sigreturn(cpu_env);
7713 break;
bellard31e31b82003-02-18 22:55:36 +00007714 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007715 if (!(p = lock_user_string(arg1)))
7716 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007717 ret = get_errno(sethostname(p, arg2));
7718 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007719 break;
7720 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007721 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007722 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007723 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007724 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007725 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7726 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007727 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7728 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007729 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007730 ret = get_errno(setrlimit(resource, &rlim));
7731 }
7732 break;
bellard31e31b82003-02-18 22:55:36 +00007733 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007734 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007735 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007736 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007737 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007738
bellard9de5e442003-03-23 16:49:39 +00007739 ret = get_errno(getrlimit(resource, &rlim));
7740 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007741 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7742 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007743 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7744 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007745 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007746 }
7747 }
7748 break;
bellard31e31b82003-02-18 22:55:36 +00007749 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007750 {
7751 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007752 ret = get_errno(getrusage(arg1, &rusage));
7753 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007754 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007755 }
7756 }
7757 break;
bellard31e31b82003-02-18 22:55:36 +00007758 case TARGET_NR_gettimeofday:
7759 {
bellard31e31b82003-02-18 22:55:36 +00007760 struct timeval tv;
7761 ret = get_errno(gettimeofday(&tv, NULL));
7762 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007763 if (copy_to_user_timeval(arg1, &tv))
7764 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007765 }
7766 }
7767 break;
7768 case TARGET_NR_settimeofday:
7769 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007770 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007771 struct timezone tz, *ptz = NULL;
7772
Paul Burtonb67d8032014-06-22 11:25:41 +01007773 if (arg1) {
7774 if (copy_from_user_timeval(&tv, arg1)) {
7775 goto efault;
7776 }
7777 ptv = &tv;
7778 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007779
7780 if (arg2) {
7781 if (copy_from_user_timezone(&tz, arg2)) {
7782 goto efault;
7783 }
7784 ptz = &tz;
7785 }
7786
Paul Burtonb67d8032014-06-22 11:25:41 +01007787 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007788 }
7789 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007790#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007791 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007792#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7793 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7794#else
bellardf2674e32003-07-09 12:26:09 +00007795 {
pbrook53a59602006-03-25 19:31:22 +00007796 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007797 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007798 long nsel;
7799
bellard579a97f2007-11-11 14:26:47 +00007800 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7801 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007802 nsel = tswapal(sel->n);
7803 inp = tswapal(sel->inp);
7804 outp = tswapal(sel->outp);
7805 exp = tswapal(sel->exp);
7806 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007807 unlock_user_struct(sel, arg1, 0);
7808 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007809 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007810#endif
bellardf2674e32003-07-09 12:26:09 +00007811 break;
bellard048f6b42005-11-26 18:47:20 +00007812#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007813#ifdef TARGET_NR_pselect6
7814 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007815 {
7816 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7817 fd_set rfds, wfds, efds;
7818 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7819 struct timespec ts, *ts_ptr;
7820
7821 /*
7822 * The 6th arg is actually two args smashed together,
7823 * so we cannot use the C library.
7824 */
7825 sigset_t set;
7826 struct {
7827 sigset_t *set;
7828 size_t size;
7829 } sig, *sig_ptr;
7830
7831 abi_ulong arg_sigset, arg_sigsize, *arg7;
7832 target_sigset_t *target_sigset;
7833
7834 n = arg1;
7835 rfd_addr = arg2;
7836 wfd_addr = arg3;
7837 efd_addr = arg4;
7838 ts_addr = arg5;
7839
7840 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7841 if (ret) {
7842 goto fail;
7843 }
7844 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7845 if (ret) {
7846 goto fail;
7847 }
7848 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7849 if (ret) {
7850 goto fail;
7851 }
7852
7853 /*
7854 * This takes a timespec, and not a timeval, so we cannot
7855 * use the do_select() helper ...
7856 */
7857 if (ts_addr) {
7858 if (target_to_host_timespec(&ts, ts_addr)) {
7859 goto efault;
7860 }
7861 ts_ptr = &ts;
7862 } else {
7863 ts_ptr = NULL;
7864 }
7865
7866 /* Extract the two packed args for the sigset */
7867 if (arg6) {
7868 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01007869 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04007870
7871 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7872 if (!arg7) {
7873 goto efault;
7874 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007875 arg_sigset = tswapal(arg7[0]);
7876 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007877 unlock_user(arg7, arg6, 0);
7878
7879 if (arg_sigset) {
7880 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007881 if (arg_sigsize != sizeof(*target_sigset)) {
7882 /* Like the kernel, we enforce correct size sigsets */
7883 ret = -TARGET_EINVAL;
7884 goto fail;
7885 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007886 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7887 sizeof(*target_sigset), 1);
7888 if (!target_sigset) {
7889 goto efault;
7890 }
7891 target_to_host_sigset(&set, target_sigset);
7892 unlock_user(target_sigset, arg_sigset, 0);
7893 } else {
7894 sig.set = NULL;
7895 }
7896 } else {
7897 sig_ptr = NULL;
7898 }
7899
Peter Maydell6df9d382016-05-12 18:47:51 +01007900 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7901 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04007902
7903 if (!is_error(ret)) {
7904 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7905 goto efault;
7906 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7907 goto efault;
7908 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7909 goto efault;
7910
7911 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
7912 goto efault;
7913 }
7914 }
7915 break;
Riku Voipio9e423822010-05-07 12:28:05 +00007916#endif
Chen Gang704eff62015-08-21 05:37:33 +08007917#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00007918 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00007919 {
7920 void *p2;
7921 p = lock_user_string(arg1);
7922 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007923 if (!p || !p2)
7924 ret = -TARGET_EFAULT;
7925 else
7926 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007927 unlock_user(p2, arg2, 0);
7928 unlock_user(p, arg1, 0);
7929 }
bellard31e31b82003-02-18 22:55:36 +00007930 break;
Chen Gang704eff62015-08-21 05:37:33 +08007931#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007932#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00007933 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00007934 {
bellard579a97f2007-11-11 14:26:47 +00007935 void *p2;
thsf0b62432007-09-24 09:25:40 +00007936 p = lock_user_string(arg1);
7937 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00007938 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007939 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00007940 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007941 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00007942 unlock_user(p2, arg3, 0);
7943 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00007944 }
7945 break;
7946#endif
bellardebc05482003-09-30 21:08:41 +00007947#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00007948 case TARGET_NR_oldlstat:
7949 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007950#endif
Chen Gang704eff62015-08-21 05:37:33 +08007951#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00007952 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00007953 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01007954 void *p2;
pbrook53a59602006-03-25 19:31:22 +00007955 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00007956 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007957 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00007958 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09007959 } else if (!arg3) {
7960 /* Short circuit this for the magic exe check. */
7961 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01007962 } else if (is_proc_myself((const char *)p, "exe")) {
7963 char real[PATH_MAX], *temp;
7964 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09007965 /* Return value is # of bytes that we wrote to the buffer. */
7966 if (temp == NULL) {
7967 ret = get_errno(-1);
7968 } else {
7969 /* Don't worry about sign mismatch as earlier mapping
7970 * logic would have thrown a bad address error. */
7971 ret = MIN(strlen(real), arg3);
7972 /* We cannot NUL terminate the string. */
7973 memcpy(p2, real, ret);
7974 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01007975 } else {
7976 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00007977 }
pbrook53a59602006-03-25 19:31:22 +00007978 unlock_user(p2, arg2, ret);
7979 unlock_user(p, arg1, 0);
7980 }
bellard31e31b82003-02-18 22:55:36 +00007981 break;
Chen Gang704eff62015-08-21 05:37:33 +08007982#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007983#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00007984 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00007985 {
bellard579a97f2007-11-11 14:26:47 +00007986 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00007987 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007988 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007989 if (!p || !p2) {
7990 ret = -TARGET_EFAULT;
7991 } else if (is_proc_myself((const char *)p, "exe")) {
7992 char real[PATH_MAX], *temp;
7993 temp = realpath(exec_path, real);
7994 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
7995 snprintf((char *)p2, arg4, "%s", real);
7996 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01007997 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01007998 }
bellard579a97f2007-11-11 14:26:47 +00007999 unlock_user(p2, arg3, ret);
8000 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008001 }
8002 break;
8003#endif
thse5febef2007-04-01 18:31:35 +00008004#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008005 case TARGET_NR_uselib:
8006 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008007#endif
8008#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008009 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008010 if (!(p = lock_user_string(arg1)))
8011 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008012 ret = get_errno(swapon(p, arg2));
8013 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008014 break;
thse5febef2007-04-01 18:31:35 +00008015#endif
bellard31e31b82003-02-18 22:55:36 +00008016 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008017 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8018 /* arg4 must be ignored in all other cases */
8019 p = lock_user_string(arg4);
8020 if (!p) {
8021 goto efault;
8022 }
8023 ret = get_errno(reboot(arg1, arg2, arg3, p));
8024 unlock_user(p, arg4, 0);
8025 } else {
8026 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8027 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008028 break;
thse5febef2007-04-01 18:31:35 +00008029#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008030 case TARGET_NR_readdir:
8031 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008032#endif
8033#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008034 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008035#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8036 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008037 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8038 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008039 {
blueswir1992f48a2007-10-14 16:27:31 +00008040 abi_ulong *v;
8041 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008042 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8043 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008044 v1 = tswapal(v[0]);
8045 v2 = tswapal(v[1]);
8046 v3 = tswapal(v[2]);
8047 v4 = tswapal(v[3]);
8048 v5 = tswapal(v[4]);
8049 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008050 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008051 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008052 target_to_host_bitmask(v4, mmap_flags_tbl),
8053 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008054 }
bellard31e31b82003-02-18 22:55:36 +00008055#else
ths5fafdf22007-09-16 21:08:06 +00008056 ret = get_errno(target_mmap(arg1, arg2, arg3,
8057 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008058 arg5,
8059 arg6));
bellard31e31b82003-02-18 22:55:36 +00008060#endif
bellard6fb883e2003-07-09 17:12:39 +00008061 break;
thse5febef2007-04-01 18:31:35 +00008062#endif
bellarda315a142005-01-30 22:59:18 +00008063#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008064 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008065#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008066#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008067#endif
ths5fafdf22007-09-16 21:08:06 +00008068 ret = get_errno(target_mmap(arg1, arg2, arg3,
8069 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008070 arg5,
bellardc573ff62004-01-04 15:51:36 +00008071 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008072 break;
bellarda315a142005-01-30 22:59:18 +00008073#endif
bellard31e31b82003-02-18 22:55:36 +00008074 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008075 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008076 break;
bellard9de5e442003-03-23 16:49:39 +00008077 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008078 {
Andreas Färber0429a972013-08-26 18:14:44 +02008079 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008080 /* Special hack to detect libc making the stack executable. */
8081 if ((arg3 & PROT_GROWSDOWN)
8082 && arg1 >= ts->info->stack_limit
8083 && arg1 <= ts->info->start_stack) {
8084 arg3 &= ~PROT_GROWSDOWN;
8085 arg2 = arg2 + arg1 - ts->info->stack_limit;
8086 arg1 = ts->info->stack_limit;
8087 }
8088 }
bellard54936002003-05-13 00:25:15 +00008089 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008090 break;
thse5febef2007-04-01 18:31:35 +00008091#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008092 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008093 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008094 break;
thse5febef2007-04-01 18:31:35 +00008095#endif
pbrook53a59602006-03-25 19:31:22 +00008096 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008097#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008098 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008099 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008100 break;
thse5febef2007-04-01 18:31:35 +00008101#endif
8102#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008103 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008104 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008105 break;
thse5febef2007-04-01 18:31:35 +00008106#endif
8107#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008108 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008109 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008110 break;
thse5febef2007-04-01 18:31:35 +00008111#endif
8112#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008113 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008114 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008115 break;
thse5febef2007-04-01 18:31:35 +00008116#endif
8117#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008118 case TARGET_NR_munlockall:
8119 ret = get_errno(munlockall());
8120 break;
thse5febef2007-04-01 18:31:35 +00008121#endif
bellard31e31b82003-02-18 22:55:36 +00008122 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008123 if (!(p = lock_user_string(arg1)))
8124 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008125 ret = get_errno(truncate(p, arg2));
8126 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008127 break;
8128 case TARGET_NR_ftruncate:
8129 ret = get_errno(ftruncate(arg1, arg2));
8130 break;
8131 case TARGET_NR_fchmod:
8132 ret = get_errno(fchmod(arg1, arg2));
8133 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008134#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008135 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008136 if (!(p = lock_user_string(arg2)))
8137 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008138 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008139 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008140 break;
8141#endif
bellard31e31b82003-02-18 22:55:36 +00008142 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008143 /* Note that negative values are valid for getpriority, so we must
8144 differentiate based on errno settings. */
8145 errno = 0;
8146 ret = getpriority(arg1, arg2);
8147 if (ret == -1 && errno != 0) {
8148 ret = -host_to_target_errno(errno);
8149 break;
8150 }
8151#ifdef TARGET_ALPHA
8152 /* Return value is the unbiased priority. Signal no error. */
8153 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8154#else
8155 /* Return value is a biased priority to avoid negative numbers. */
8156 ret = 20 - ret;
8157#endif
bellard31e31b82003-02-18 22:55:36 +00008158 break;
8159 case TARGET_NR_setpriority:
8160 ret = get_errno(setpriority(arg1, arg2, arg3));
8161 break;
bellardebc05482003-09-30 21:08:41 +00008162#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008163 case TARGET_NR_profil:
8164 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008165#endif
bellard31e31b82003-02-18 22:55:36 +00008166 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008167 if (!(p = lock_user_string(arg1)))
8168 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008169 ret = get_errno(statfs(path(p), &stfs));
8170 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008171 convert_statfs:
8172 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008173 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008174
bellard579a97f2007-11-11 14:26:47 +00008175 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8176 goto efault;
8177 __put_user(stfs.f_type, &target_stfs->f_type);
8178 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8179 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8180 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8181 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8182 __put_user(stfs.f_files, &target_stfs->f_files);
8183 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8184 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8185 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8186 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008187 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8188 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008189 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008190 }
8191 break;
8192 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008193 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008194 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008195#ifdef TARGET_NR_statfs64
8196 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008197 if (!(p = lock_user_string(arg1)))
8198 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008199 ret = get_errno(statfs(path(p), &stfs));
8200 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008201 convert_statfs64:
8202 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008203 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008204
bellard579a97f2007-11-11 14:26:47 +00008205 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8206 goto efault;
8207 __put_user(stfs.f_type, &target_stfs->f_type);
8208 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8209 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8210 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8211 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8212 __put_user(stfs.f_files, &target_stfs->f_files);
8213 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8214 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8215 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8216 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008217 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8218 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008219 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008220 }
8221 break;
8222 case TARGET_NR_fstatfs64:
8223 ret = get_errno(fstatfs(arg1, &stfs));
8224 goto convert_statfs64;
8225#endif
bellardebc05482003-09-30 21:08:41 +00008226#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008227 case TARGET_NR_ioperm:
8228 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008229#endif
thse5febef2007-04-01 18:31:35 +00008230#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008231 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008232 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008233 break;
thse5febef2007-04-01 18:31:35 +00008234#endif
bellard3532fa72006-06-24 15:06:03 +00008235#ifdef TARGET_NR_accept
8236 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008237 ret = do_accept4(arg1, arg2, arg3, 0);
8238 break;
8239#endif
8240#ifdef TARGET_NR_accept4
8241 case TARGET_NR_accept4:
8242#ifdef CONFIG_ACCEPT4
8243 ret = do_accept4(arg1, arg2, arg3, arg4);
8244#else
8245 goto unimplemented;
8246#endif
bellard3532fa72006-06-24 15:06:03 +00008247 break;
8248#endif
8249#ifdef TARGET_NR_bind
8250 case TARGET_NR_bind:
8251 ret = do_bind(arg1, arg2, arg3);
8252 break;
8253#endif
8254#ifdef TARGET_NR_connect
8255 case TARGET_NR_connect:
8256 ret = do_connect(arg1, arg2, arg3);
8257 break;
8258#endif
8259#ifdef TARGET_NR_getpeername
8260 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008261 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008262 break;
8263#endif
8264#ifdef TARGET_NR_getsockname
8265 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008266 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008267 break;
8268#endif
8269#ifdef TARGET_NR_getsockopt
8270 case TARGET_NR_getsockopt:
8271 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8272 break;
8273#endif
8274#ifdef TARGET_NR_listen
8275 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008276 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008277 break;
8278#endif
8279#ifdef TARGET_NR_recv
8280 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008281 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008282 break;
8283#endif
8284#ifdef TARGET_NR_recvfrom
8285 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008286 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008287 break;
8288#endif
8289#ifdef TARGET_NR_recvmsg
8290 case TARGET_NR_recvmsg:
8291 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8292 break;
8293#endif
8294#ifdef TARGET_NR_send
8295 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008296 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008297 break;
8298#endif
8299#ifdef TARGET_NR_sendmsg
8300 case TARGET_NR_sendmsg:
8301 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8302 break;
8303#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008304#ifdef TARGET_NR_sendmmsg
8305 case TARGET_NR_sendmmsg:
8306 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8307 break;
8308 case TARGET_NR_recvmmsg:
8309 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8310 break;
8311#endif
bellard3532fa72006-06-24 15:06:03 +00008312#ifdef TARGET_NR_sendto
8313 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008314 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008315 break;
8316#endif
8317#ifdef TARGET_NR_shutdown
8318 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008319 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008320 break;
8321#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008322#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8323 case TARGET_NR_getrandom:
8324 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8325 if (!p) {
8326 goto efault;
8327 }
8328 ret = get_errno(getrandom(p, arg2, arg3));
8329 unlock_user(p, arg1, ret);
8330 break;
8331#endif
bellard3532fa72006-06-24 15:06:03 +00008332#ifdef TARGET_NR_socket
8333 case TARGET_NR_socket:
8334 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008335 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008336 break;
8337#endif
8338#ifdef TARGET_NR_socketpair
8339 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008340 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008341 break;
8342#endif
8343#ifdef TARGET_NR_setsockopt
8344 case TARGET_NR_setsockopt:
8345 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8346 break;
8347#endif
ths7494b0f2007-02-11 18:26:53 +00008348
bellard31e31b82003-02-18 22:55:36 +00008349 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008350 if (!(p = lock_user_string(arg2)))
8351 goto efault;
thse5574482007-02-11 20:03:13 +00008352 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8353 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008354 break;
8355
bellard31e31b82003-02-18 22:55:36 +00008356 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008357 {
bellard66fb9762003-03-23 01:06:05 +00008358 struct itimerval value, ovalue, *pvalue;
8359
pbrook53a59602006-03-25 19:31:22 +00008360 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008361 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008362 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8363 || copy_from_user_timeval(&pvalue->it_value,
8364 arg2 + sizeof(struct target_timeval)))
8365 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008366 } else {
8367 pvalue = NULL;
8368 }
8369 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008370 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008371 if (copy_to_user_timeval(arg3,
8372 &ovalue.it_interval)
8373 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8374 &ovalue.it_value))
8375 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008376 }
8377 }
8378 break;
bellard31e31b82003-02-18 22:55:36 +00008379 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008380 {
bellard66fb9762003-03-23 01:06:05 +00008381 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008382
bellard66fb9762003-03-23 01:06:05 +00008383 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008384 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008385 if (copy_to_user_timeval(arg2,
8386 &value.it_interval)
8387 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8388 &value.it_value))
8389 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008390 }
8391 }
8392 break;
Chen Gang704eff62015-08-21 05:37:33 +08008393#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008394 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008395 if (!(p = lock_user_string(arg1)))
8396 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008397 ret = get_errno(stat(path(p), &st));
8398 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008399 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008400#endif
8401#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008402 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008403 if (!(p = lock_user_string(arg1)))
8404 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008405 ret = get_errno(lstat(path(p), &st));
8406 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008407 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008408#endif
bellard31e31b82003-02-18 22:55:36 +00008409 case TARGET_NR_fstat:
8410 {
8411 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008412#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008413 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008414#endif
bellard31e31b82003-02-18 22:55:36 +00008415 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008416 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008417
bellard579a97f2007-11-11 14:26:47 +00008418 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8419 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008420 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008421 __put_user(st.st_dev, &target_st->st_dev);
8422 __put_user(st.st_ino, &target_st->st_ino);
8423 __put_user(st.st_mode, &target_st->st_mode);
8424 __put_user(st.st_uid, &target_st->st_uid);
8425 __put_user(st.st_gid, &target_st->st_gid);
8426 __put_user(st.st_nlink, &target_st->st_nlink);
8427 __put_user(st.st_rdev, &target_st->st_rdev);
8428 __put_user(st.st_size, &target_st->st_size);
8429 __put_user(st.st_blksize, &target_st->st_blksize);
8430 __put_user(st.st_blocks, &target_st->st_blocks);
8431 __put_user(st.st_atime, &target_st->target_st_atime);
8432 __put_user(st.st_mtime, &target_st->target_st_mtime);
8433 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008434 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008435 }
8436 }
8437 break;
bellardebc05482003-09-30 21:08:41 +00008438#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008439 case TARGET_NR_olduname:
8440 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008441#endif
8442#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008443 case TARGET_NR_iopl:
8444 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008445#endif
bellard31e31b82003-02-18 22:55:36 +00008446 case TARGET_NR_vhangup:
8447 ret = get_errno(vhangup());
8448 break;
bellardebc05482003-09-30 21:08:41 +00008449#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008450 case TARGET_NR_idle:
8451 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008452#endif
bellard42ad6ae2005-01-03 22:48:11 +00008453#ifdef TARGET_NR_syscall
8454 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008455 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8456 arg6, arg7, arg8, 0);
8457 break;
bellard42ad6ae2005-01-03 22:48:11 +00008458#endif
bellard31e31b82003-02-18 22:55:36 +00008459 case TARGET_NR_wait4:
8460 {
8461 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008462 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008463 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008464 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008465 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008466 if (target_rusage)
8467 rusage_ptr = &rusage;
8468 else
8469 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008470 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008471 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008472 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008473 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008474 if (put_user_s32(status, status_ptr))
8475 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008476 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008477 if (target_rusage) {
8478 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8479 if (rusage_err) {
8480 ret = rusage_err;
8481 }
8482 }
bellard31e31b82003-02-18 22:55:36 +00008483 }
8484 }
8485 break;
thse5febef2007-04-01 18:31:35 +00008486#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008487 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008488 if (!(p = lock_user_string(arg1)))
8489 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008490 ret = get_errno(swapoff(p));
8491 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008492 break;
thse5febef2007-04-01 18:31:35 +00008493#endif
bellard31e31b82003-02-18 22:55:36 +00008494 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008495 {
pbrook53a59602006-03-25 19:31:22 +00008496 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008497 struct sysinfo value;
8498 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008499 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008500 {
bellard579a97f2007-11-11 14:26:47 +00008501 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8502 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008503 __put_user(value.uptime, &target_value->uptime);
8504 __put_user(value.loads[0], &target_value->loads[0]);
8505 __put_user(value.loads[1], &target_value->loads[1]);
8506 __put_user(value.loads[2], &target_value->loads[2]);
8507 __put_user(value.totalram, &target_value->totalram);
8508 __put_user(value.freeram, &target_value->freeram);
8509 __put_user(value.sharedram, &target_value->sharedram);
8510 __put_user(value.bufferram, &target_value->bufferram);
8511 __put_user(value.totalswap, &target_value->totalswap);
8512 __put_user(value.freeswap, &target_value->freeswap);
8513 __put_user(value.procs, &target_value->procs);
8514 __put_user(value.totalhigh, &target_value->totalhigh);
8515 __put_user(value.freehigh, &target_value->freehigh);
8516 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008517 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008518 }
8519 }
8520 break;
thse5febef2007-04-01 18:31:35 +00008521#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008522 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008523 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8524 break;
thse5febef2007-04-01 18:31:35 +00008525#endif
aurel32e5289082009-04-18 16:16:12 +00008526#ifdef TARGET_NR_semget
8527 case TARGET_NR_semget:
8528 ret = get_errno(semget(arg1, arg2, arg3));
8529 break;
8530#endif
8531#ifdef TARGET_NR_semop
8532 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008533 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008534 break;
8535#endif
8536#ifdef TARGET_NR_semctl
8537 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008538 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008539 break;
8540#endif
aurel32eeb438c2008-10-13 21:08:55 +00008541#ifdef TARGET_NR_msgctl
8542 case TARGET_NR_msgctl:
8543 ret = do_msgctl(arg1, arg2, arg3);
8544 break;
8545#endif
8546#ifdef TARGET_NR_msgget
8547 case TARGET_NR_msgget:
8548 ret = get_errno(msgget(arg1, arg2));
8549 break;
8550#endif
8551#ifdef TARGET_NR_msgrcv
8552 case TARGET_NR_msgrcv:
8553 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8554 break;
8555#endif
8556#ifdef TARGET_NR_msgsnd
8557 case TARGET_NR_msgsnd:
8558 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8559 break;
8560#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008561#ifdef TARGET_NR_shmget
8562 case TARGET_NR_shmget:
8563 ret = get_errno(shmget(arg1, arg2, arg3));
8564 break;
8565#endif
8566#ifdef TARGET_NR_shmctl
8567 case TARGET_NR_shmctl:
8568 ret = do_shmctl(arg1, arg2, arg3);
8569 break;
8570#endif
8571#ifdef TARGET_NR_shmat
8572 case TARGET_NR_shmat:
8573 ret = do_shmat(arg1, arg2, arg3);
8574 break;
8575#endif
8576#ifdef TARGET_NR_shmdt
8577 case TARGET_NR_shmdt:
8578 ret = do_shmdt(arg1);
8579 break;
8580#endif
bellard31e31b82003-02-18 22:55:36 +00008581 case TARGET_NR_fsync:
8582 ret = get_errno(fsync(arg1));
8583 break;
bellard31e31b82003-02-18 22:55:36 +00008584 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008585 /* Linux manages to have three different orderings for its
8586 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8587 * match the kernel's CONFIG_CLONE_* settings.
8588 * Microblaze is further special in that it uses a sixth
8589 * implicit argument to clone for the TLS pointer.
8590 */
8591#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008592 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008593#elif defined(TARGET_CLONE_BACKWARDS)
8594 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8595#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008596 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008597#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008598 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008599#endif
bellard1b6b0292003-03-22 17:31:38 +00008600 break;
bellardec86b0f2003-04-11 00:15:04 +00008601#ifdef __NR_exit_group
8602 /* new thread calls */
8603 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008604#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008605 _mcleanup();
8606#endif
bellarde9009672005-04-26 20:42:36 +00008607 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008608 ret = get_errno(exit_group(arg1));
8609 break;
8610#endif
bellard31e31b82003-02-18 22:55:36 +00008611 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008612 if (!(p = lock_user_string(arg1)))
8613 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008614 ret = get_errno(setdomainname(p, arg2));
8615 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008616 break;
8617 case TARGET_NR_uname:
8618 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008619 {
8620 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008621
bellard579a97f2007-11-11 14:26:47 +00008622 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8623 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008624 ret = get_errno(sys_uname(buf));
8625 if (!is_error(ret)) {
8626 /* Overrite the native machine name with whatever is being
8627 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01008628 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008629 /* Allow the user to override the reported release. */
8630 if (qemu_uname_release && *qemu_uname_release)
8631 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008632 }
pbrook53a59602006-03-25 19:31:22 +00008633 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008634 }
bellard31e31b82003-02-18 22:55:36 +00008635 break;
bellard6dbad632003-03-16 18:05:05 +00008636#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008637 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008638 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008639 break;
j_mayer84409dd2007-04-06 08:56:50 +00008640#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008641 case TARGET_NR_vm86old:
8642 goto unimplemented;
8643 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008644 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008645 break;
8646#endif
j_mayer84409dd2007-04-06 08:56:50 +00008647#endif
bellard31e31b82003-02-18 22:55:36 +00008648 case TARGET_NR_adjtimex:
8649 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008650#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008651 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008652#endif
bellard31e31b82003-02-18 22:55:36 +00008653 case TARGET_NR_init_module:
8654 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008655#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008656 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008657#endif
bellard31e31b82003-02-18 22:55:36 +00008658 goto unimplemented;
8659 case TARGET_NR_quotactl:
8660 goto unimplemented;
8661 case TARGET_NR_getpgid:
8662 ret = get_errno(getpgid(arg1));
8663 break;
8664 case TARGET_NR_fchdir:
8665 ret = get_errno(fchdir(arg1));
8666 break;
j_mayer84409dd2007-04-06 08:56:50 +00008667#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008668 case TARGET_NR_bdflush:
8669 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008670#endif
thse5febef2007-04-01 18:31:35 +00008671#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008672 case TARGET_NR_sysfs:
8673 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008674#endif
bellard31e31b82003-02-18 22:55:36 +00008675 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008676 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008677 break;
thse5febef2007-04-01 18:31:35 +00008678#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008679 case TARGET_NR_afs_syscall:
8680 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008681#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008682#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008683 case TARGET_NR__llseek:
8684 {
8685 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008686#if !defined(__NR_llseek)
8687 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8688 if (res == -1) {
8689 ret = get_errno(res);
8690 } else {
8691 ret = 0;
8692 }
8693#else
bellard31e31b82003-02-18 22:55:36 +00008694 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008695#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008696 if ((ret == 0) && put_user_s64(res, arg4)) {
8697 goto efault;
8698 }
bellard31e31b82003-02-18 22:55:36 +00008699 }
8700 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008701#endif
Chen Gang704eff62015-08-21 05:37:33 +08008702#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008703 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008704#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008705#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008706 {
pbrook53a59602006-03-25 19:31:22 +00008707 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008708 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008709 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008710
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308711 dirp = g_try_malloc(count);
8712 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008713 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008714 goto fail;
8715 }
ths3b46e622007-09-17 08:09:54 +00008716
bellard4add45b2003-06-05 01:52:59 +00008717 ret = get_errno(sys_getdents(arg1, dirp, count));
8718 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008719 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008720 struct target_dirent *tde;
8721 int len = ret;
8722 int reclen, treclen;
8723 int count1, tnamelen;
8724
8725 count1 = 0;
8726 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008727 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8728 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008729 tde = target_dirp;
8730 while (len > 0) {
8731 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008732 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8733 assert(tnamelen >= 0);
8734 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8735 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008736 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008737 tde->d_ino = tswapal(de->d_ino);
8738 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008739 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008740 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008741 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008742 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008743 count1 += treclen;
8744 }
8745 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008746 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008747 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308748 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008749 }
8750#else
bellard31e31b82003-02-18 22:55:36 +00008751 {
aurel326556a832008-10-13 21:08:17 +00008752 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008753 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008754
bellard579a97f2007-11-11 14:26:47 +00008755 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8756 goto efault;
bellard72f03902003-02-18 23:33:18 +00008757 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008758 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008759 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008760 int len = ret;
8761 int reclen;
8762 de = dirp;
8763 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008764 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008765 if (reclen > len)
8766 break;
bellard8083a3e2003-03-24 23:12:16 +00008767 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008768 tswapls(&de->d_ino);
8769 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008770 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008771 len -= reclen;
8772 }
8773 }
pbrook53a59602006-03-25 19:31:22 +00008774 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008775 }
bellard4add45b2003-06-05 01:52:59 +00008776#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008777#else
8778 /* Implement getdents in terms of getdents64 */
8779 {
8780 struct linux_dirent64 *dirp;
8781 abi_long count = arg3;
8782
8783 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8784 if (!dirp) {
8785 goto efault;
8786 }
8787 ret = get_errno(sys_getdents64(arg1, dirp, count));
8788 if (!is_error(ret)) {
8789 /* Convert the dirent64 structs to target dirent. We do this
8790 * in-place, since we can guarantee that a target_dirent is no
8791 * larger than a dirent64; however this means we have to be
8792 * careful to read everything before writing in the new format.
8793 */
8794 struct linux_dirent64 *de;
8795 struct target_dirent *tde;
8796 int len = ret;
8797 int tlen = 0;
8798
8799 de = dirp;
8800 tde = (struct target_dirent *)dirp;
8801 while (len > 0) {
8802 int namelen, treclen;
8803 int reclen = de->d_reclen;
8804 uint64_t ino = de->d_ino;
8805 int64_t off = de->d_off;
8806 uint8_t type = de->d_type;
8807
8808 namelen = strlen(de->d_name);
8809 treclen = offsetof(struct target_dirent, d_name)
8810 + namelen + 2;
8811 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8812
8813 memmove(tde->d_name, de->d_name, namelen + 1);
8814 tde->d_ino = tswapal(ino);
8815 tde->d_off = tswapal(off);
8816 tde->d_reclen = tswap16(treclen);
8817 /* The target_dirent type is in what was formerly a padding
8818 * byte at the end of the structure:
8819 */
8820 *(((char *)tde) + treclen - 1) = type;
8821
8822 de = (struct linux_dirent64 *)((char *)de + reclen);
8823 tde = (struct target_dirent *)((char *)tde + treclen);
8824 len -= reclen;
8825 tlen += treclen;
8826 }
8827 ret = tlen;
8828 }
8829 unlock_user(dirp, arg2, ret);
8830 }
8831#endif
bellard31e31b82003-02-18 22:55:36 +00008832 break;
Chen Gang704eff62015-08-21 05:37:33 +08008833#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008834#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008835 case TARGET_NR_getdents64:
8836 {
aurel326556a832008-10-13 21:08:17 +00008837 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008838 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008839 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8840 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008841 ret = get_errno(sys_getdents64(arg1, dirp, count));
8842 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008843 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008844 int len = ret;
8845 int reclen;
8846 de = dirp;
8847 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008848 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008849 if (reclen > len)
8850 break;
bellard8083a3e2003-03-24 23:12:16 +00008851 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008852 tswap64s((uint64_t *)&de->d_ino);
8853 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008854 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008855 len -= reclen;
8856 }
8857 }
pbrook53a59602006-03-25 19:31:22 +00008858 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008859 }
8860 break;
bellarda541f292004-04-12 20:39:29 +00008861#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008862#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008863 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008864 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008865 break;
thse5febef2007-04-01 18:31:35 +00008866#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008867#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8868# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008869 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008870# endif
8871# ifdef TARGET_NR_ppoll
8872 case TARGET_NR_ppoll:
8873# endif
bellard9de5e442003-03-23 16:49:39 +00008874 {
pbrook53a59602006-03-25 19:31:22 +00008875 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008876 unsigned int nfds = arg2;
8877 int timeout = arg3;
8878 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008879 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008880
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008881 pfd = NULL;
8882 target_pfd = NULL;
8883 if (nfds) {
8884 target_pfd = lock_user(VERIFY_WRITE, arg1,
8885 sizeof(struct target_pollfd) * nfds, 1);
8886 if (!target_pfd) {
8887 goto efault;
8888 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008889
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008890 pfd = alloca(sizeof(struct pollfd) * nfds);
8891 for (i = 0; i < nfds; i++) {
8892 pfd[i].fd = tswap32(target_pfd[i].fd);
8893 pfd[i].events = tswap16(target_pfd[i].events);
8894 }
bellard9de5e442003-03-23 16:49:39 +00008895 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008896
8897# ifdef TARGET_NR_ppoll
8898 if (num == TARGET_NR_ppoll) {
8899 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8900 target_sigset_t *target_set;
8901 sigset_t _set, *set = &_set;
8902
8903 if (arg3) {
8904 if (target_to_host_timespec(timeout_ts, arg3)) {
8905 unlock_user(target_pfd, arg1, 0);
8906 goto efault;
8907 }
8908 } else {
8909 timeout_ts = NULL;
8910 }
8911
8912 if (arg4) {
8913 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
8914 if (!target_set) {
8915 unlock_user(target_pfd, arg1, 0);
8916 goto efault;
8917 }
8918 target_to_host_sigset(set, target_set);
8919 } else {
8920 set = NULL;
8921 }
8922
Peter Maydellb28a1f32016-05-27 15:51:47 +01008923 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts,
8924 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05008925
8926 if (!is_error(ret) && arg3) {
8927 host_to_target_timespec(arg3, timeout_ts);
8928 }
8929 if (arg4) {
8930 unlock_user(target_set, arg4, 0);
8931 }
8932 } else
8933# endif
8934 ret = get_errno(poll(pfd, nfds, timeout));
8935
bellard9de5e442003-03-23 16:49:39 +00008936 if (!is_error(ret)) {
8937 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00008938 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00008939 }
8940 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00008941 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00008942 }
8943 break;
thse5febef2007-04-01 18:31:35 +00008944#endif
bellard31e31b82003-02-18 22:55:36 +00008945 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00008946 /* NOTE: the flock constant seems to be the same for every
8947 Linux platform */
8948 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008949 break;
8950 case TARGET_NR_readv:
8951 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008952 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
8953 if (vec != NULL) {
8954 ret = get_errno(readv(arg1, vec, arg3));
8955 unlock_iovec(vec, arg2, arg3, 1);
8956 } else {
8957 ret = -host_to_target_errno(errno);
8958 }
bellard31e31b82003-02-18 22:55:36 +00008959 }
8960 break;
8961 case TARGET_NR_writev:
8962 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008963 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8964 if (vec != NULL) {
8965 ret = get_errno(writev(arg1, vec, arg3));
8966 unlock_iovec(vec, arg2, arg3, 0);
8967 } else {
8968 ret = -host_to_target_errno(errno);
8969 }
bellard31e31b82003-02-18 22:55:36 +00008970 }
8971 break;
8972 case TARGET_NR_getsid:
8973 ret = get_errno(getsid(arg1));
8974 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008975#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00008976 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00008977 ret = get_errno(fdatasync(arg1));
8978 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008979#endif
Chen Gang704eff62015-08-21 05:37:33 +08008980#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00008981 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00008982 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00008983 return value. */
ths0da46a62007-10-20 20:23:07 +00008984 ret = -TARGET_ENOTDIR;
8985 break;
Chen Gang704eff62015-08-21 05:37:33 +08008986#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05008987 case TARGET_NR_sched_getaffinity:
8988 {
8989 unsigned int mask_size;
8990 unsigned long *mask;
8991
8992 /*
8993 * sched_getaffinity needs multiples of ulong, so need to take
8994 * care of mismatches between target ulong and host ulong sizes.
8995 */
8996 if (arg2 & (sizeof(abi_ulong) - 1)) {
8997 ret = -TARGET_EINVAL;
8998 break;
8999 }
9000 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9001
9002 mask = alloca(mask_size);
9003 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9004
9005 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009006 if (ret > arg2) {
9007 /* More data returned than the caller's buffer will fit.
9008 * This only happens if sizeof(abi_long) < sizeof(long)
9009 * and the caller passed us a buffer holding an odd number
9010 * of abi_longs. If the host kernel is actually using the
9011 * extra 4 bytes then fail EINVAL; otherwise we can just
9012 * ignore them and only copy the interesting part.
9013 */
9014 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9015 if (numcpus > arg2 * 8) {
9016 ret = -TARGET_EINVAL;
9017 break;
9018 }
9019 ret = arg2;
9020 }
9021
Mike McCormackcd18f052011-04-18 14:43:36 +09009022 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009023 goto efault;
9024 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009025 }
9026 }
9027 break;
9028 case TARGET_NR_sched_setaffinity:
9029 {
9030 unsigned int mask_size;
9031 unsigned long *mask;
9032
9033 /*
9034 * sched_setaffinity needs multiples of ulong, so need to take
9035 * care of mismatches between target ulong and host ulong sizes.
9036 */
9037 if (arg2 & (sizeof(abi_ulong) - 1)) {
9038 ret = -TARGET_EINVAL;
9039 break;
9040 }
9041 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9042
9043 mask = alloca(mask_size);
9044 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9045 goto efault;
9046 }
9047 memcpy(mask, p, arg2);
9048 unlock_user_struct(p, arg2, 0);
9049
9050 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9051 }
9052 break;
bellard31e31b82003-02-18 22:55:36 +00009053 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009054 {
pbrook53a59602006-03-25 19:31:22 +00009055 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009056 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009057
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009058 if (arg2 == 0) {
9059 return -TARGET_EINVAL;
9060 }
bellard579a97f2007-11-11 14:26:47 +00009061 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9062 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009063 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009064 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009065 ret = get_errno(sched_setparam(arg1, &schp));
9066 }
9067 break;
bellard31e31b82003-02-18 22:55:36 +00009068 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009069 {
pbrook53a59602006-03-25 19:31:22 +00009070 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009071 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009072
9073 if (arg2 == 0) {
9074 return -TARGET_EINVAL;
9075 }
bellard5cd43932003-03-29 16:54:36 +00009076 ret = get_errno(sched_getparam(arg1, &schp));
9077 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009078 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9079 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009080 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009081 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009082 }
9083 }
9084 break;
bellard31e31b82003-02-18 22:55:36 +00009085 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009086 {
pbrook53a59602006-03-25 19:31:22 +00009087 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009088 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009089 if (arg3 == 0) {
9090 return -TARGET_EINVAL;
9091 }
bellard579a97f2007-11-11 14:26:47 +00009092 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9093 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009094 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009095 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009096 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9097 }
9098 break;
bellard31e31b82003-02-18 22:55:36 +00009099 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009100 ret = get_errno(sched_getscheduler(arg1));
9101 break;
bellard31e31b82003-02-18 22:55:36 +00009102 case TARGET_NR_sched_yield:
9103 ret = get_errno(sched_yield());
9104 break;
9105 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009106 ret = get_errno(sched_get_priority_max(arg1));
9107 break;
bellard31e31b82003-02-18 22:55:36 +00009108 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009109 ret = get_errno(sched_get_priority_min(arg1));
9110 break;
bellard31e31b82003-02-18 22:55:36 +00009111 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009112 {
bellard5cd43932003-03-29 16:54:36 +00009113 struct timespec ts;
9114 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9115 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009116 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009117 }
9118 }
9119 break;
bellard31e31b82003-02-18 22:55:36 +00009120 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009121 {
bellard1b6b0292003-03-22 17:31:38 +00009122 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009123 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00009124 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009125 if (is_error(ret) && arg2) {
9126 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009127 }
9128 }
9129 break;
thse5febef2007-04-01 18:31:35 +00009130#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009131 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009132 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009133#endif
9134#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009135 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009136 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009137#endif
bellard31e31b82003-02-18 22:55:36 +00009138 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009139 switch (arg1) {
9140 case PR_GET_PDEATHSIG:
9141 {
9142 int deathsig;
9143 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9144 if (!is_error(ret) && arg2
9145 && put_user_ual(deathsig, arg2)) {
9146 goto efault;
thse5574482007-02-11 20:03:13 +00009147 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009148 break;
9149 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009150#ifdef PR_GET_NAME
9151 case PR_GET_NAME:
9152 {
9153 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9154 if (!name) {
9155 goto efault;
9156 }
9157 ret = get_errno(prctl(arg1, (unsigned long)name,
9158 arg3, arg4, arg5));
9159 unlock_user(name, arg2, 16);
9160 break;
9161 }
9162 case PR_SET_NAME:
9163 {
9164 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9165 if (!name) {
9166 goto efault;
9167 }
9168 ret = get_errno(prctl(arg1, (unsigned long)name,
9169 arg3, arg4, arg5));
9170 unlock_user(name, arg2, 0);
9171 break;
9172 }
9173#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009174 default:
9175 /* Most prctl options have no pointer arguments */
9176 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9177 break;
9178 }
ths39b9aae2007-02-11 18:36:44 +00009179 break;
bellardd2fd1af2007-11-14 18:08:56 +00009180#ifdef TARGET_NR_arch_prctl
9181 case TARGET_NR_arch_prctl:
9182#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9183 ret = do_arch_prctl(cpu_env, arg1, arg2);
9184 break;
9185#else
9186 goto unimplemented;
9187#endif
9188#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009189#ifdef TARGET_NR_pread64
9190 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009191 if (regpairs_aligned(cpu_env)) {
9192 arg4 = arg5;
9193 arg5 = arg6;
9194 }
aurel32f2c7ba12008-03-28 22:32:06 +00009195 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9196 goto efault;
9197 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9198 unlock_user(p, arg2, ret);
9199 break;
9200 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009201 if (regpairs_aligned(cpu_env)) {
9202 arg4 = arg5;
9203 arg5 = arg6;
9204 }
aurel32f2c7ba12008-03-28 22:32:06 +00009205 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9206 goto efault;
9207 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9208 unlock_user(p, arg2, 0);
9209 break;
9210#endif
bellard31e31b82003-02-18 22:55:36 +00009211 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009212 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9213 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009214 ret = get_errno(sys_getcwd1(p, arg2));
9215 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009216 break;
9217 case TARGET_NR_capget:
9218 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009219 {
9220 struct target_user_cap_header *target_header;
9221 struct target_user_cap_data *target_data = NULL;
9222 struct __user_cap_header_struct header;
9223 struct __user_cap_data_struct data[2];
9224 struct __user_cap_data_struct *dataptr = NULL;
9225 int i, target_datalen;
9226 int data_items = 1;
9227
9228 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9229 goto efault;
9230 }
9231 header.version = tswap32(target_header->version);
9232 header.pid = tswap32(target_header->pid);
9233
Peter Maydellec864872014-03-19 16:07:30 +00009234 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009235 /* Version 2 and up takes pointer to two user_data structs */
9236 data_items = 2;
9237 }
9238
9239 target_datalen = sizeof(*target_data) * data_items;
9240
9241 if (arg2) {
9242 if (num == TARGET_NR_capget) {
9243 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9244 } else {
9245 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9246 }
9247 if (!target_data) {
9248 unlock_user_struct(target_header, arg1, 0);
9249 goto efault;
9250 }
9251
9252 if (num == TARGET_NR_capset) {
9253 for (i = 0; i < data_items; i++) {
9254 data[i].effective = tswap32(target_data[i].effective);
9255 data[i].permitted = tswap32(target_data[i].permitted);
9256 data[i].inheritable = tswap32(target_data[i].inheritable);
9257 }
9258 }
9259
9260 dataptr = data;
9261 }
9262
9263 if (num == TARGET_NR_capget) {
9264 ret = get_errno(capget(&header, dataptr));
9265 } else {
9266 ret = get_errno(capset(&header, dataptr));
9267 }
9268
9269 /* The kernel always updates version for both capget and capset */
9270 target_header->version = tswap32(header.version);
9271 unlock_user_struct(target_header, arg1, 1);
9272
9273 if (arg2) {
9274 if (num == TARGET_NR_capget) {
9275 for (i = 0; i < data_items; i++) {
9276 target_data[i].effective = tswap32(data[i].effective);
9277 target_data[i].permitted = tswap32(data[i].permitted);
9278 target_data[i].inheritable = tswap32(data[i].inheritable);
9279 }
9280 unlock_user(target_data, arg2, target_datalen);
9281 } else {
9282 unlock_user(target_data, arg2, 0);
9283 }
9284 }
9285 break;
9286 }
bellard31e31b82003-02-18 22:55:36 +00009287 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009288 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009289 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009290
9291#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009292 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009293 {
9294 off_t *offp = NULL;
9295 off_t off;
9296 if (arg3) {
9297 ret = get_user_sal(off, arg3);
9298 if (is_error(ret)) {
9299 break;
9300 }
9301 offp = &off;
9302 }
9303 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9304 if (!is_error(ret) && arg3) {
9305 abi_long ret2 = put_user_sal(off, arg3);
9306 if (is_error(ret2)) {
9307 ret = ret2;
9308 }
9309 }
9310 break;
9311 }
9312#ifdef TARGET_NR_sendfile64
9313 case TARGET_NR_sendfile64:
9314 {
9315 off_t *offp = NULL;
9316 off_t off;
9317 if (arg3) {
9318 ret = get_user_s64(off, arg3);
9319 if (is_error(ret)) {
9320 break;
9321 }
9322 offp = &off;
9323 }
9324 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9325 if (!is_error(ret) && arg3) {
9326 abi_long ret2 = put_user_s64(off, arg3);
9327 if (is_error(ret2)) {
9328 ret = ret2;
9329 }
9330 }
9331 break;
9332 }
9333#endif
9334#else
9335 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009336#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009337 case TARGET_NR_sendfile64:
9338#endif
bellard5cd43932003-03-29 16:54:36 +00009339 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009340#endif
9341
bellardebc05482003-09-30 21:08:41 +00009342#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009343 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009344 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009345#endif
9346#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009347 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009348 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009349#endif
bellard048f6b42005-11-26 18:47:20 +00009350#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009351 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009352 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9353 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009354 break;
bellard048f6b42005-11-26 18:47:20 +00009355#endif
bellardebc05482003-09-30 21:08:41 +00009356#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009357 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009358 {
9359 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009360 int resource = target_to_host_resource(arg1);
9361 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009362 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009363 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009364 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9365 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009366 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9367 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009368 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009369 }
9370 break;
9371 }
bellardebc05482003-09-30 21:08:41 +00009372#endif
bellarda315a142005-01-30 22:59:18 +00009373#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009374 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009375 if (!(p = lock_user_string(arg1)))
9376 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009377 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9378 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009379 break;
bellarda315a142005-01-30 22:59:18 +00009380#endif
9381#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009382 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009383 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009384 break;
bellarda315a142005-01-30 22:59:18 +00009385#endif
9386#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009387 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009388 if (!(p = lock_user_string(arg1)))
9389 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009390 ret = get_errno(stat(path(p), &st));
9391 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009392 if (!is_error(ret))
9393 ret = host_to_target_stat64(cpu_env, arg2, &st);
9394 break;
bellarda315a142005-01-30 22:59:18 +00009395#endif
9396#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009397 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009398 if (!(p = lock_user_string(arg1)))
9399 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009400 ret = get_errno(lstat(path(p), &st));
9401 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009402 if (!is_error(ret))
9403 ret = host_to_target_stat64(cpu_env, arg2, &st);
9404 break;
bellarda315a142005-01-30 22:59:18 +00009405#endif
9406#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009407 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009408 ret = get_errno(fstat(arg1, &st));
9409 if (!is_error(ret))
9410 ret = host_to_target_stat64(cpu_env, arg2, &st);
9411 break;
bellardec86b0f2003-04-11 00:15:04 +00009412#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009413#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009414#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009415 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009416#endif
9417#ifdef TARGET_NR_newfstatat
9418 case TARGET_NR_newfstatat:
9419#endif
balrog6a24a772008-09-20 02:23:36 +00009420 if (!(p = lock_user_string(arg2)))
9421 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009422 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009423 if (!is_error(ret))
9424 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009425 break;
bellarda315a142005-01-30 22:59:18 +00009426#endif
Chen Gang704eff62015-08-21 05:37:33 +08009427#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009428 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009429 if (!(p = lock_user_string(arg1)))
9430 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009431 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9432 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009433 break;
Chen Gang704eff62015-08-21 05:37:33 +08009434#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009435#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009436 case TARGET_NR_getuid:
9437 ret = get_errno(high2lowuid(getuid()));
9438 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009439#endif
9440#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009441 case TARGET_NR_getgid:
9442 ret = get_errno(high2lowgid(getgid()));
9443 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009444#endif
9445#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009446 case TARGET_NR_geteuid:
9447 ret = get_errno(high2lowuid(geteuid()));
9448 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009449#endif
9450#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009451 case TARGET_NR_getegid:
9452 ret = get_errno(high2lowgid(getegid()));
9453 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009454#endif
bellard67867302003-11-23 17:05:30 +00009455 case TARGET_NR_setreuid:
9456 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9457 break;
9458 case TARGET_NR_setregid:
9459 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9460 break;
9461 case TARGET_NR_getgroups:
9462 {
9463 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009464 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009465 gid_t *grouplist;
9466 int i;
9467
9468 grouplist = alloca(gidsetsize * sizeof(gid_t));
9469 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009470 if (gidsetsize == 0)
9471 break;
bellard67867302003-11-23 17:05:30 +00009472 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009473 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009474 if (!target_grouplist)
9475 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009476 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009477 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009478 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009479 }
9480 }
9481 break;
9482 case TARGET_NR_setgroups:
9483 {
9484 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009485 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009486 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009487 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009488 if (gidsetsize) {
9489 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009490 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009491 if (!target_grouplist) {
9492 ret = -TARGET_EFAULT;
9493 goto fail;
9494 }
9495 for (i = 0; i < gidsetsize; i++) {
9496 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9497 }
9498 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009499 }
bellard67867302003-11-23 17:05:30 +00009500 ret = get_errno(setgroups(gidsetsize, grouplist));
9501 }
9502 break;
9503 case TARGET_NR_fchown:
9504 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9505 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009506#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009507 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009508 if (!(p = lock_user_string(arg2)))
9509 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009510 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9511 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009512 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009513 break;
9514#endif
bellard67867302003-11-23 17:05:30 +00009515#ifdef TARGET_NR_setresuid
9516 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009517 ret = get_errno(sys_setresuid(low2highuid(arg1),
9518 low2highuid(arg2),
9519 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009520 break;
9521#endif
9522#ifdef TARGET_NR_getresuid
9523 case TARGET_NR_getresuid:
9524 {
pbrook53a59602006-03-25 19:31:22 +00009525 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009526 ret = get_errno(getresuid(&ruid, &euid, &suid));
9527 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009528 if (put_user_id(high2lowuid(ruid), arg1)
9529 || put_user_id(high2lowuid(euid), arg2)
9530 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009531 goto efault;
bellard67867302003-11-23 17:05:30 +00009532 }
9533 }
9534 break;
9535#endif
9536#ifdef TARGET_NR_getresgid
9537 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009538 ret = get_errno(sys_setresgid(low2highgid(arg1),
9539 low2highgid(arg2),
9540 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009541 break;
9542#endif
9543#ifdef TARGET_NR_getresgid
9544 case TARGET_NR_getresgid:
9545 {
pbrook53a59602006-03-25 19:31:22 +00009546 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009547 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9548 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009549 if (put_user_id(high2lowgid(rgid), arg1)
9550 || put_user_id(high2lowgid(egid), arg2)
9551 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009552 goto efault;
bellard67867302003-11-23 17:05:30 +00009553 }
9554 }
9555 break;
9556#endif
Chen Gang704eff62015-08-21 05:37:33 +08009557#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009558 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009559 if (!(p = lock_user_string(arg1)))
9560 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009561 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9562 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009563 break;
Chen Gang704eff62015-08-21 05:37:33 +08009564#endif
bellard67867302003-11-23 17:05:30 +00009565 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009566 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009567 break;
9568 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009569 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009570 break;
9571 case TARGET_NR_setfsuid:
9572 ret = get_errno(setfsuid(arg1));
9573 break;
9574 case TARGET_NR_setfsgid:
9575 ret = get_errno(setfsgid(arg1));
9576 break;
bellard67867302003-11-23 17:05:30 +00009577
bellarda315a142005-01-30 22:59:18 +00009578#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009579 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009580 if (!(p = lock_user_string(arg1)))
9581 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009582 ret = get_errno(lchown(p, arg2, arg3));
9583 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009584 break;
bellarda315a142005-01-30 22:59:18 +00009585#endif
9586#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009587 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009588 ret = get_errno(getuid());
9589 break;
bellarda315a142005-01-30 22:59:18 +00009590#endif
aurel3264b4d282008-11-14 17:20:15 +00009591
9592#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9593 /* Alpha specific */
9594 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009595 {
9596 uid_t euid;
9597 euid=geteuid();
9598 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9599 }
aurel3264b4d282008-11-14 17:20:15 +00009600 ret = get_errno(getuid());
9601 break;
9602#endif
9603#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9604 /* Alpha specific */
9605 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009606 {
9607 uid_t egid;
9608 egid=getegid();
9609 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9610 }
aurel3264b4d282008-11-14 17:20:15 +00009611 ret = get_errno(getgid());
9612 break;
9613#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009614#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9615 /* Alpha specific */
9616 case TARGET_NR_osf_getsysinfo:
9617 ret = -TARGET_EOPNOTSUPP;
9618 switch (arg1) {
9619 case TARGET_GSI_IEEE_FP_CONTROL:
9620 {
9621 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9622
9623 /* Copied from linux ieee_fpcr_to_swcr. */
9624 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9625 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9626 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9627 | SWCR_TRAP_ENABLE_DZE
9628 | SWCR_TRAP_ENABLE_OVF);
9629 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9630 | SWCR_TRAP_ENABLE_INE);
9631 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9632 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9633
9634 if (put_user_u64 (swcr, arg2))
9635 goto efault;
9636 ret = 0;
9637 }
9638 break;
9639
9640 /* case GSI_IEEE_STATE_AT_SIGNAL:
9641 -- Not implemented in linux kernel.
9642 case GSI_UACPROC:
9643 -- Retrieves current unaligned access state; not much used.
9644 case GSI_PROC_TYPE:
9645 -- Retrieves implver information; surely not used.
9646 case GSI_GET_HWRPB:
9647 -- Grabs a copy of the HWRPB; surely not used.
9648 */
9649 }
9650 break;
9651#endif
9652#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9653 /* Alpha specific */
9654 case TARGET_NR_osf_setsysinfo:
9655 ret = -TARGET_EOPNOTSUPP;
9656 switch (arg1) {
9657 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009658 {
9659 uint64_t swcr, fpcr, orig_fpcr;
9660
Richard Henderson6e06d512012-06-01 09:08:21 -07009661 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009662 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009663 }
9664 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009665 fpcr = orig_fpcr & FPCR_DYN_MASK;
9666
9667 /* Copied from linux ieee_swcr_to_fpcr. */
9668 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9669 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9670 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9671 | SWCR_TRAP_ENABLE_DZE
9672 | SWCR_TRAP_ENABLE_OVF)) << 48;
9673 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9674 | SWCR_TRAP_ENABLE_INE)) << 57;
9675 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9676 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9677
Richard Henderson6e06d512012-06-01 09:08:21 -07009678 cpu_alpha_store_fpcr(cpu_env, fpcr);
9679 ret = 0;
9680 }
9681 break;
9682
9683 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9684 {
9685 uint64_t exc, fpcr, orig_fpcr;
9686 int si_code;
9687
9688 if (get_user_u64(exc, arg2)) {
9689 goto efault;
9690 }
9691
9692 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9693
9694 /* We only add to the exception status here. */
9695 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9696
9697 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009698 ret = 0;
9699
Richard Henderson6e06d512012-06-01 09:08:21 -07009700 /* Old exceptions are not signaled. */
9701 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009702
Richard Henderson6e06d512012-06-01 09:08:21 -07009703 /* If any exceptions set by this call,
9704 and are unmasked, send a signal. */
9705 si_code = 0;
9706 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9707 si_code = TARGET_FPE_FLTRES;
9708 }
9709 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9710 si_code = TARGET_FPE_FLTUND;
9711 }
9712 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9713 si_code = TARGET_FPE_FLTOVF;
9714 }
9715 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9716 si_code = TARGET_FPE_FLTDIV;
9717 }
9718 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9719 si_code = TARGET_FPE_FLTINV;
9720 }
9721 if (si_code != 0) {
9722 target_siginfo_t info;
9723 info.si_signo = SIGFPE;
9724 info.si_errno = 0;
9725 info.si_code = si_code;
9726 info._sifields._sigfault._addr
9727 = ((CPUArchState *)cpu_env)->pc;
9728 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009729 }
9730 }
9731 break;
9732
9733 /* case SSI_NVPAIRS:
9734 -- Used with SSIN_UACPROC to enable unaligned accesses.
9735 case SSI_IEEE_STATE_AT_SIGNAL:
9736 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9737 -- Not implemented in linux kernel
9738 */
9739 }
9740 break;
9741#endif
9742#ifdef TARGET_NR_osf_sigprocmask
9743 /* Alpha specific. */
9744 case TARGET_NR_osf_sigprocmask:
9745 {
9746 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009747 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009748 sigset_t set, oldset;
9749
9750 switch(arg1) {
9751 case TARGET_SIG_BLOCK:
9752 how = SIG_BLOCK;
9753 break;
9754 case TARGET_SIG_UNBLOCK:
9755 how = SIG_UNBLOCK;
9756 break;
9757 case TARGET_SIG_SETMASK:
9758 how = SIG_SETMASK;
9759 break;
9760 default:
9761 ret = -TARGET_EINVAL;
9762 goto fail;
9763 }
9764 mask = arg2;
9765 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00009766 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009767 host_to_target_old_sigset(&mask, &oldset);
9768 ret = mask;
9769 }
9770 break;
9771#endif
aurel3264b4d282008-11-14 17:20:15 +00009772
bellarda315a142005-01-30 22:59:18 +00009773#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009774 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009775 ret = get_errno(getgid());
9776 break;
bellarda315a142005-01-30 22:59:18 +00009777#endif
9778#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009779 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009780 ret = get_errno(geteuid());
9781 break;
bellarda315a142005-01-30 22:59:18 +00009782#endif
9783#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009784 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009785 ret = get_errno(getegid());
9786 break;
bellarda315a142005-01-30 22:59:18 +00009787#endif
9788#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009789 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009790 ret = get_errno(setreuid(arg1, arg2));
9791 break;
bellarda315a142005-01-30 22:59:18 +00009792#endif
9793#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009794 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009795 ret = get_errno(setregid(arg1, arg2));
9796 break;
bellarda315a142005-01-30 22:59:18 +00009797#endif
9798#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009799 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009800 {
9801 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009802 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009803 gid_t *grouplist;
9804 int i;
9805
9806 grouplist = alloca(gidsetsize * sizeof(gid_t));
9807 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009808 if (gidsetsize == 0)
9809 break;
bellard99c475a2005-01-31 20:45:13 +00009810 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009811 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9812 if (!target_grouplist) {
9813 ret = -TARGET_EFAULT;
9814 goto fail;
9815 }
balroga2155fc2008-09-20 02:12:08 +00009816 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009817 target_grouplist[i] = tswap32(grouplist[i]);
9818 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009819 }
9820 }
9821 break;
bellarda315a142005-01-30 22:59:18 +00009822#endif
9823#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009824 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009825 {
9826 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009827 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009828 gid_t *grouplist;
9829 int i;
ths3b46e622007-09-17 08:09:54 +00009830
bellard99c475a2005-01-31 20:45:13 +00009831 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009832 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9833 if (!target_grouplist) {
9834 ret = -TARGET_EFAULT;
9835 goto fail;
9836 }
bellard99c475a2005-01-31 20:45:13 +00009837 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009838 grouplist[i] = tswap32(target_grouplist[i]);
9839 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009840 ret = get_errno(setgroups(gidsetsize, grouplist));
9841 }
9842 break;
bellarda315a142005-01-30 22:59:18 +00009843#endif
9844#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009845 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009846 ret = get_errno(fchown(arg1, arg2, arg3));
9847 break;
bellarda315a142005-01-30 22:59:18 +00009848#endif
9849#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009850 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009851 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +00009852 break;
bellarda315a142005-01-30 22:59:18 +00009853#endif
9854#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009855 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009856 {
pbrook53a59602006-03-25 19:31:22 +00009857 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009858 ret = get_errno(getresuid(&ruid, &euid, &suid));
9859 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009860 if (put_user_u32(ruid, arg1)
9861 || put_user_u32(euid, arg2)
9862 || put_user_u32(suid, arg3))
9863 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009864 }
9865 }
9866 break;
bellarda315a142005-01-30 22:59:18 +00009867#endif
9868#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009869 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009870 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +00009871 break;
bellarda315a142005-01-30 22:59:18 +00009872#endif
9873#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009874 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009875 {
pbrook53a59602006-03-25 19:31:22 +00009876 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009877 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9878 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009879 if (put_user_u32(rgid, arg1)
9880 || put_user_u32(egid, arg2)
9881 || put_user_u32(sgid, arg3))
9882 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009883 }
9884 }
9885 break;
bellarda315a142005-01-30 22:59:18 +00009886#endif
9887#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009888 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009889 if (!(p = lock_user_string(arg1)))
9890 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009891 ret = get_errno(chown(p, arg2, arg3));
9892 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009893 break;
bellarda315a142005-01-30 22:59:18 +00009894#endif
9895#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009896 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009897 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +00009898 break;
bellarda315a142005-01-30 22:59:18 +00009899#endif
9900#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009901 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009902 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +00009903 break;
bellarda315a142005-01-30 22:59:18 +00009904#endif
9905#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009906 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009907 ret = get_errno(setfsuid(arg1));
9908 break;
bellarda315a142005-01-30 22:59:18 +00009909#endif
9910#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00009911 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00009912 ret = get_errno(setfsgid(arg1));
9913 break;
bellarda315a142005-01-30 22:59:18 +00009914#endif
bellard67867302003-11-23 17:05:30 +00009915
bellard31e31b82003-02-18 22:55:36 +00009916 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00009917 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00009918#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00009919 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00009920 {
9921 void *a;
9922 ret = -TARGET_EFAULT;
9923 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
9924 goto efault;
9925 if (!(p = lock_user_string(arg3)))
9926 goto mincore_fail;
9927 ret = get_errno(mincore(a, arg2, p));
9928 unlock_user(p, arg3, ret);
9929 mincore_fail:
9930 unlock_user(a, arg1, 0);
9931 }
9932 break;
bellardffa65c32004-01-04 23:57:22 +00009933#endif
aurel32408321b2008-10-01 21:46:32 +00009934#ifdef TARGET_NR_arm_fadvise64_64
9935 case TARGET_NR_arm_fadvise64_64:
9936 {
9937 /*
9938 * arm_fadvise64_64 looks like fadvise64_64 but
9939 * with different argument order
9940 */
9941 abi_long temp;
9942 temp = arg3;
9943 arg3 = arg4;
9944 arg4 = temp;
9945 }
9946#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009947#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00009948#ifdef TARGET_NR_fadvise64_64
9949 case TARGET_NR_fadvise64_64:
9950#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009951#ifdef TARGET_NR_fadvise64
9952 case TARGET_NR_fadvise64:
9953#endif
9954#ifdef TARGET_S390X
9955 switch (arg4) {
9956 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
9957 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
9958 case 6: arg4 = POSIX_FADV_DONTNEED; break;
9959 case 7: arg4 = POSIX_FADV_NOREUSE; break;
9960 default: break;
9961 }
9962#endif
9963 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00009964 break;
9965#endif
bellardffa65c32004-01-04 23:57:22 +00009966#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00009967 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00009968 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08009969 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00009970 This will break MADV_DONTNEED.
9971 This is a hint, so ignoring and returning success is ok. */
9972 ret = get_errno(0);
9973 break;
bellardffa65c32004-01-04 23:57:22 +00009974#endif
blueswir1992f48a2007-10-14 16:27:31 +00009975#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00009976 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00009977 {
thsb1e341e2007-03-20 21:50:52 +00009978 int cmd;
bellard77e46722003-04-29 20:39:06 +00009979 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00009980 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00009981#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00009982 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00009983#endif
bellard77e46722003-04-29 20:39:06 +00009984
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009985 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00009986 if (cmd == -TARGET_EINVAL) {
9987 ret = cmd;
9988 break;
9989 }
thsb1e341e2007-03-20 21:50:52 +00009990
bellard60cd49d2003-03-16 22:53:56 +00009991 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00009992 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00009993#ifdef TARGET_ARM
9994 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009995 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9996 goto efault;
ths58134272007-03-31 18:59:32 +00009997 fl.l_type = tswap16(target_efl->l_type);
9998 fl.l_whence = tswap16(target_efl->l_whence);
9999 fl.l_start = tswap64(target_efl->l_start);
10000 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010001 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +000010002 unlock_user_struct(target_efl, arg3, 0);
10003 } else
10004#endif
10005 {
bellard9ee1fa22007-11-11 15:11:19 +000010006 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
10007 goto efault;
ths58134272007-03-31 18:59:32 +000010008 fl.l_type = tswap16(target_fl->l_type);
10009 fl.l_whence = tswap16(target_fl->l_whence);
10010 fl.l_start = tswap64(target_fl->l_start);
10011 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010012 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +000010013 unlock_user_struct(target_fl, arg3, 0);
10014 }
thsb1e341e2007-03-20 21:50:52 +000010015 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010016 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +000010017#ifdef TARGET_ARM
10018 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +000010019 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
10020 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010021 target_efl->l_type = tswap16(fl.l_type);
10022 target_efl->l_whence = tswap16(fl.l_whence);
10023 target_efl->l_start = tswap64(fl.l_start);
10024 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010025 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +000010026 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +000010027 } else
10028#endif
10029 {
bellard9ee1fa22007-11-11 15:11:19 +000010030 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
10031 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010032 target_fl->l_type = tswap16(fl.l_type);
10033 target_fl->l_whence = tswap16(fl.l_whence);
10034 target_fl->l_start = tswap64(fl.l_start);
10035 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010036 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +000010037 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +000010038 }
bellard77e46722003-04-29 20:39:06 +000010039 }
10040 break;
10041
thsb1e341e2007-03-20 21:50:52 +000010042 case TARGET_F_SETLK64:
10043 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +000010044#ifdef TARGET_ARM
10045 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +000010046 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
10047 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010048 fl.l_type = tswap16(target_efl->l_type);
10049 fl.l_whence = tswap16(target_efl->l_whence);
10050 fl.l_start = tswap64(target_efl->l_start);
10051 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010052 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +000010053 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +000010054 } else
10055#endif
10056 {
bellard9ee1fa22007-11-11 15:11:19 +000010057 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
10058 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010059 fl.l_type = tswap16(target_fl->l_type);
10060 fl.l_whence = tswap16(target_fl->l_whence);
10061 fl.l_start = tswap64(target_fl->l_start);
10062 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010063 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +000010064 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +000010065 }
thsb1e341e2007-03-20 21:50:52 +000010066 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010067 break;
bellard60cd49d2003-03-16 22:53:56 +000010068 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010069 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010070 break;
10071 }
bellard77e46722003-04-29 20:39:06 +000010072 break;
10073 }
bellard60cd49d2003-03-16 22:53:56 +000010074#endif
ths7d600c82006-12-08 01:32:58 +000010075#ifdef TARGET_NR_cacheflush
10076 case TARGET_NR_cacheflush:
10077 /* self-modifying code is handled automatically, so nothing needed */
10078 ret = 0;
10079 break;
10080#endif
bellardebc05482003-09-30 21:08:41 +000010081#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010082 case TARGET_NR_security:
10083 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010084#endif
bellardc573ff62004-01-04 15:51:36 +000010085#ifdef TARGET_NR_getpagesize
10086 case TARGET_NR_getpagesize:
10087 ret = TARGET_PAGE_SIZE;
10088 break;
10089#endif
bellard31e31b82003-02-18 22:55:36 +000010090 case TARGET_NR_gettid:
10091 ret = get_errno(gettid());
10092 break;
thse5febef2007-04-01 18:31:35 +000010093#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010094 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010095#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010096 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010097 arg2 = arg3;
10098 arg3 = arg4;
10099 arg4 = arg5;
10100 }
aurel322054ac92008-10-13 21:08:07 +000010101 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10102#else
10103 ret = get_errno(readahead(arg1, arg2, arg3));
10104#endif
10105 break;
thse5febef2007-04-01 18:31:35 +000010106#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010107#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010108#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010109 case TARGET_NR_listxattr:
10110 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010111 {
10112 void *p, *b = 0;
10113 if (arg2) {
10114 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10115 if (!b) {
10116 ret = -TARGET_EFAULT;
10117 break;
10118 }
10119 }
10120 p = lock_user_string(arg1);
10121 if (p) {
10122 if (num == TARGET_NR_listxattr) {
10123 ret = get_errno(listxattr(p, b, arg3));
10124 } else {
10125 ret = get_errno(llistxattr(p, b, arg3));
10126 }
10127 } else {
10128 ret = -TARGET_EFAULT;
10129 }
10130 unlock_user(p, arg1, 0);
10131 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010132 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010133 }
10134 case TARGET_NR_flistxattr:
10135 {
10136 void *b = 0;
10137 if (arg2) {
10138 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10139 if (!b) {
10140 ret = -TARGET_EFAULT;
10141 break;
10142 }
10143 }
10144 ret = get_errno(flistxattr(arg1, b, arg3));
10145 unlock_user(b, arg2, arg3);
10146 break;
10147 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010148 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010149 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010150 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010151 void *p, *n, *v = 0;
10152 if (arg3) {
10153 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10154 if (!v) {
10155 ret = -TARGET_EFAULT;
10156 break;
10157 }
10158 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010159 p = lock_user_string(arg1);
10160 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010161 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010162 if (num == TARGET_NR_setxattr) {
10163 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10164 } else {
10165 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10166 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010167 } else {
10168 ret = -TARGET_EFAULT;
10169 }
10170 unlock_user(p, arg1, 0);
10171 unlock_user(n, arg2, 0);
10172 unlock_user(v, arg3, 0);
10173 }
10174 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010175 case TARGET_NR_fsetxattr:
10176 {
10177 void *n, *v = 0;
10178 if (arg3) {
10179 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10180 if (!v) {
10181 ret = -TARGET_EFAULT;
10182 break;
10183 }
10184 }
10185 n = lock_user_string(arg2);
10186 if (n) {
10187 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10188 } else {
10189 ret = -TARGET_EFAULT;
10190 }
10191 unlock_user(n, arg2, 0);
10192 unlock_user(v, arg3, 0);
10193 }
10194 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010195 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010196 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010197 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010198 void *p, *n, *v = 0;
10199 if (arg3) {
10200 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10201 if (!v) {
10202 ret = -TARGET_EFAULT;
10203 break;
10204 }
10205 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010206 p = lock_user_string(arg1);
10207 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010208 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010209 if (num == TARGET_NR_getxattr) {
10210 ret = get_errno(getxattr(p, n, v, arg4));
10211 } else {
10212 ret = get_errno(lgetxattr(p, n, v, arg4));
10213 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010214 } else {
10215 ret = -TARGET_EFAULT;
10216 }
10217 unlock_user(p, arg1, 0);
10218 unlock_user(n, arg2, 0);
10219 unlock_user(v, arg3, arg4);
10220 }
10221 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010222 case TARGET_NR_fgetxattr:
10223 {
10224 void *n, *v = 0;
10225 if (arg3) {
10226 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10227 if (!v) {
10228 ret = -TARGET_EFAULT;
10229 break;
10230 }
10231 }
10232 n = lock_user_string(arg2);
10233 if (n) {
10234 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10235 } else {
10236 ret = -TARGET_EFAULT;
10237 }
10238 unlock_user(n, arg2, 0);
10239 unlock_user(v, arg3, arg4);
10240 }
10241 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010242 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010243 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010244 {
10245 void *p, *n;
10246 p = lock_user_string(arg1);
10247 n = lock_user_string(arg2);
10248 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010249 if (num == TARGET_NR_removexattr) {
10250 ret = get_errno(removexattr(p, n));
10251 } else {
10252 ret = get_errno(lremovexattr(p, n));
10253 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010254 } else {
10255 ret = -TARGET_EFAULT;
10256 }
10257 unlock_user(p, arg1, 0);
10258 unlock_user(n, arg2, 0);
10259 }
10260 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010261 case TARGET_NR_fremovexattr:
10262 {
10263 void *n;
10264 n = lock_user_string(arg2);
10265 if (n) {
10266 ret = get_errno(fremovexattr(arg1, n));
10267 } else {
10268 ret = -TARGET_EFAULT;
10269 }
10270 unlock_user(n, arg2, 0);
10271 }
10272 break;
bellardebc05482003-09-30 21:08:41 +000010273#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010274#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010275#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010276 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010277#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010278 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010279 ret = 0;
10280 break;
edgar_iglef967792009-01-07 14:19:38 +000010281#elif defined(TARGET_CRIS)
10282 if (arg1 & 0xff)
10283 ret = -TARGET_EINVAL;
10284 else {
10285 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10286 ret = 0;
10287 }
10288 break;
bellard8d18e892007-11-14 15:18:40 +000010289#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10290 ret = do_set_thread_area(cpu_env, arg1);
10291 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010292#elif defined(TARGET_M68K)
10293 {
Andreas Färber0429a972013-08-26 18:14:44 +020010294 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010295 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010296 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010297 break;
10298 }
ths6f5b89a2007-03-02 20:48:00 +000010299#else
10300 goto unimplemented_nowarn;
10301#endif
10302#endif
10303#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010304 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010305#if defined(TARGET_I386) && defined(TARGET_ABI32)
10306 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010307 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010308#elif defined(TARGET_M68K)
10309 {
Andreas Färber0429a972013-08-26 18:14:44 +020010310 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010311 ret = ts->tp_value;
10312 break;
10313 }
bellard8d18e892007-11-14 15:18:40 +000010314#else
bellard5cd43932003-03-29 16:54:36 +000010315 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010316#endif
bellard8d18e892007-11-14 15:18:40 +000010317#endif
bellard48dc41e2006-06-21 18:15:50 +000010318#ifdef TARGET_NR_getdomainname
10319 case TARGET_NR_getdomainname:
10320 goto unimplemented_nowarn;
10321#endif
ths6f5b89a2007-03-02 20:48:00 +000010322
thsb5906f92007-03-19 13:32:45 +000010323#ifdef TARGET_NR_clock_gettime
10324 case TARGET_NR_clock_gettime:
10325 {
10326 struct timespec ts;
10327 ret = get_errno(clock_gettime(arg1, &ts));
10328 if (!is_error(ret)) {
10329 host_to_target_timespec(arg2, &ts);
10330 }
10331 break;
10332 }
10333#endif
10334#ifdef TARGET_NR_clock_getres
10335 case TARGET_NR_clock_getres:
10336 {
10337 struct timespec ts;
10338 ret = get_errno(clock_getres(arg1, &ts));
10339 if (!is_error(ret)) {
10340 host_to_target_timespec(arg2, &ts);
10341 }
10342 break;
10343 }
10344#endif
pbrook63d76512008-05-29 13:43:29 +000010345#ifdef TARGET_NR_clock_nanosleep
10346 case TARGET_NR_clock_nanosleep:
10347 {
10348 struct timespec ts;
10349 target_to_host_timespec(&ts, arg3);
10350 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
10351 if (arg4)
10352 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010353
10354#if defined(TARGET_PPC)
10355 /* clock_nanosleep is odd in that it returns positive errno values.
10356 * On PPC, CR0 bit 3 should be set in such a situation. */
10357 if (ret) {
10358 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10359 }
10360#endif
pbrook63d76512008-05-29 13:43:29 +000010361 break;
10362 }
10363#endif
thsb5906f92007-03-19 13:32:45 +000010364
ths6f5b89a2007-03-02 20:48:00 +000010365#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10366 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010367 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10368 break;
ths6f5b89a2007-03-02 20:48:00 +000010369#endif
10370
ths3ae43202007-09-16 21:39:48 +000010371#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +000010372 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +000010373 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010374 break;
10375#endif
10376
ths3ae43202007-09-16 21:39:48 +000010377#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +000010378 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +000010379 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
10380 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +000010381 break;
10382#endif
10383
ths4f2b1fe2007-06-21 21:57:12 +000010384#ifdef TARGET_NR_set_robust_list
10385 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010386 case TARGET_NR_get_robust_list:
10387 /* The ABI for supporting robust futexes has userspace pass
10388 * the kernel a pointer to a linked list which is updated by
10389 * userspace after the syscall; the list is walked by the kernel
10390 * when the thread exits. Since the linked list in QEMU guest
10391 * memory isn't a valid linked list for the host and we have
10392 * no way to reliably intercept the thread-death event, we can't
10393 * support these. Silently return ENOSYS so that guest userspace
10394 * falls back to a non-robust futex implementation (which should
10395 * be OK except in the corner case of the guest crashing while
10396 * holding a mutex that is shared with another process via
10397 * shared memory).
10398 */
10399 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010400#endif
10401
Peter Maydell1acae9f2013-07-02 14:04:12 +010010402#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010403 case TARGET_NR_utimensat:
10404 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010405 struct timespec *tsp, ts[2];
10406 if (!arg3) {
10407 tsp = NULL;
10408 } else {
10409 target_to_host_timespec(ts, arg3);
10410 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10411 tsp = ts;
10412 }
ths9007f0e2007-09-25 17:50:37 +000010413 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010414 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010415 else {
bellard579a97f2007-11-11 14:26:47 +000010416 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010417 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010418 goto fail;
10419 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010420 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010421 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010422 }
10423 }
10424 break;
10425#endif
pbrookbd0c5662008-05-29 14:34:11 +000010426 case TARGET_NR_futex:
10427 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10428 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010429#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010430 case TARGET_NR_inotify_init:
10431 ret = get_errno(sys_inotify_init());
10432 break;
10433#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010434#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010435#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10436 case TARGET_NR_inotify_init1:
10437 ret = get_errno(sys_inotify_init1(arg1));
10438 break;
10439#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010440#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010441#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010442 case TARGET_NR_inotify_add_watch:
10443 p = lock_user_string(arg2);
10444 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10445 unlock_user(p, arg2, 0);
10446 break;
10447#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010448#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010449 case TARGET_NR_inotify_rm_watch:
10450 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10451 break;
10452#endif
ths9007f0e2007-09-25 17:50:37 +000010453
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010454#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010455 case TARGET_NR_mq_open:
10456 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010457 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010458
10459 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010460 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010461 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010462 attrp = &posix_mq_attr;
10463 } else {
10464 attrp = 0;
10465 }
10466 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010467 unlock_user (p, arg1, 0);
10468 }
10469 break;
10470
10471 case TARGET_NR_mq_unlink:
10472 p = lock_user_string(arg1 - 1);
10473 ret = get_errno(mq_unlink(p));
10474 unlock_user (p, arg1, 0);
10475 break;
10476
10477 case TARGET_NR_mq_timedsend:
10478 {
10479 struct timespec ts;
10480
10481 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10482 if (arg5 != 0) {
10483 target_to_host_timespec(&ts, arg5);
10484 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
10485 host_to_target_timespec(arg5, &ts);
10486 }
10487 else
10488 ret = get_errno(mq_send(arg1, p, arg3, arg4));
10489 unlock_user (p, arg2, arg3);
10490 }
10491 break;
10492
10493 case TARGET_NR_mq_timedreceive:
10494 {
10495 struct timespec ts;
10496 unsigned int prio;
10497
10498 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10499 if (arg5 != 0) {
10500 target_to_host_timespec(&ts, arg5);
10501 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
10502 host_to_target_timespec(arg5, &ts);
10503 }
10504 else
10505 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
10506 unlock_user (p, arg2, arg3);
10507 if (arg4 != 0)
10508 put_user_u32(prio, arg4);
10509 }
10510 break;
10511
10512 /* Not implemented for now... */
10513/* case TARGET_NR_mq_notify: */
10514/* break; */
10515
10516 case TARGET_NR_mq_getsetattr:
10517 {
10518 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10519 ret = 0;
10520 if (arg3 != 0) {
10521 ret = mq_getattr(arg1, &posix_mq_attr_out);
10522 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10523 }
10524 if (arg2 != 0) {
10525 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10526 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10527 }
10528
10529 }
10530 break;
10531#endif
10532
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010533#ifdef CONFIG_SPLICE
10534#ifdef TARGET_NR_tee
10535 case TARGET_NR_tee:
10536 {
10537 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10538 }
10539 break;
10540#endif
10541#ifdef TARGET_NR_splice
10542 case TARGET_NR_splice:
10543 {
10544 loff_t loff_in, loff_out;
10545 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010546 if (arg2) {
10547 if (get_user_u64(loff_in, arg2)) {
10548 goto efault;
10549 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010550 ploff_in = &loff_in;
10551 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010552 if (arg4) {
10553 if (get_user_u64(loff_out, arg4)) {
10554 goto efault;
10555 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010556 ploff_out = &loff_out;
10557 }
10558 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010559 if (arg2) {
10560 if (put_user_u64(loff_in, arg2)) {
10561 goto efault;
10562 }
10563 }
10564 if (arg4) {
10565 if (put_user_u64(loff_out, arg4)) {
10566 goto efault;
10567 }
10568 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010569 }
10570 break;
10571#endif
10572#ifdef TARGET_NR_vmsplice
10573 case TARGET_NR_vmsplice:
10574 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010575 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10576 if (vec != NULL) {
10577 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10578 unlock_iovec(vec, arg2, arg3, 0);
10579 } else {
10580 ret = -host_to_target_errno(errno);
10581 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010582 }
10583 break;
10584#endif
10585#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010586#ifdef CONFIG_EVENTFD
10587#if defined(TARGET_NR_eventfd)
10588 case TARGET_NR_eventfd:
10589 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010590 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010591 break;
10592#endif
10593#if defined(TARGET_NR_eventfd2)
10594 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010595 {
10596 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10597 if (arg2 & TARGET_O_NONBLOCK) {
10598 host_flags |= O_NONBLOCK;
10599 }
10600 if (arg2 & TARGET_O_CLOEXEC) {
10601 host_flags |= O_CLOEXEC;
10602 }
10603 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010604 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010605 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010606 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010607#endif
10608#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010609#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10610 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010611#if TARGET_ABI_BITS == 32
10612 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10613 target_offset64(arg5, arg6)));
10614#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010615 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010616#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010617 break;
10618#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010619#if defined(CONFIG_SYNC_FILE_RANGE)
10620#if defined(TARGET_NR_sync_file_range)
10621 case TARGET_NR_sync_file_range:
10622#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010623#if defined(TARGET_MIPS)
10624 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10625 target_offset64(arg5, arg6), arg7));
10626#else
Peter Maydellc727f472011-01-06 11:05:10 +000010627 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10628 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010629#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010630#else
10631 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10632#endif
10633 break;
10634#endif
10635#if defined(TARGET_NR_sync_file_range2)
10636 case TARGET_NR_sync_file_range2:
10637 /* This is like sync_file_range but the arguments are reordered */
10638#if TARGET_ABI_BITS == 32
10639 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10640 target_offset64(arg5, arg6), arg2));
10641#else
10642 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10643#endif
10644 break;
10645#endif
10646#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010647#if defined(TARGET_NR_signalfd4)
10648 case TARGET_NR_signalfd4:
10649 ret = do_signalfd4(arg1, arg2, arg4);
10650 break;
10651#endif
10652#if defined(TARGET_NR_signalfd)
10653 case TARGET_NR_signalfd:
10654 ret = do_signalfd4(arg1, arg2, 0);
10655 break;
10656#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010657#if defined(CONFIG_EPOLL)
10658#if defined(TARGET_NR_epoll_create)
10659 case TARGET_NR_epoll_create:
10660 ret = get_errno(epoll_create(arg1));
10661 break;
10662#endif
10663#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10664 case TARGET_NR_epoll_create1:
10665 ret = get_errno(epoll_create1(arg1));
10666 break;
10667#endif
10668#if defined(TARGET_NR_epoll_ctl)
10669 case TARGET_NR_epoll_ctl:
10670 {
10671 struct epoll_event ep;
10672 struct epoll_event *epp = 0;
10673 if (arg4) {
10674 struct target_epoll_event *target_ep;
10675 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10676 goto efault;
10677 }
10678 ep.events = tswap32(target_ep->events);
10679 /* The epoll_data_t union is just opaque data to the kernel,
10680 * so we transfer all 64 bits across and need not worry what
10681 * actual data type it is.
10682 */
10683 ep.data.u64 = tswap64(target_ep->data.u64);
10684 unlock_user_struct(target_ep, arg4, 0);
10685 epp = &ep;
10686 }
10687 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10688 break;
10689 }
10690#endif
10691
10692#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
10693#define IMPLEMENT_EPOLL_PWAIT
10694#endif
10695#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
10696#if defined(TARGET_NR_epoll_wait)
10697 case TARGET_NR_epoll_wait:
10698#endif
10699#if defined(IMPLEMENT_EPOLL_PWAIT)
10700 case TARGET_NR_epoll_pwait:
10701#endif
10702 {
10703 struct target_epoll_event *target_ep;
10704 struct epoll_event *ep;
10705 int epfd = arg1;
10706 int maxevents = arg3;
10707 int timeout = arg4;
10708
10709 target_ep = lock_user(VERIFY_WRITE, arg2,
10710 maxevents * sizeof(struct target_epoll_event), 1);
10711 if (!target_ep) {
10712 goto efault;
10713 }
10714
10715 ep = alloca(maxevents * sizeof(struct epoll_event));
10716
10717 switch (num) {
10718#if defined(IMPLEMENT_EPOLL_PWAIT)
10719 case TARGET_NR_epoll_pwait:
10720 {
10721 target_sigset_t *target_set;
10722 sigset_t _set, *set = &_set;
10723
10724 if (arg5) {
10725 target_set = lock_user(VERIFY_READ, arg5,
10726 sizeof(target_sigset_t), 1);
10727 if (!target_set) {
10728 unlock_user(target_ep, arg2, 0);
10729 goto efault;
10730 }
10731 target_to_host_sigset(set, target_set);
10732 unlock_user(target_set, arg5, 0);
10733 } else {
10734 set = NULL;
10735 }
10736
10737 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
10738 break;
10739 }
10740#endif
10741#if defined(TARGET_NR_epoll_wait)
10742 case TARGET_NR_epoll_wait:
10743 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
10744 break;
10745#endif
10746 default:
10747 ret = -TARGET_ENOSYS;
10748 }
10749 if (!is_error(ret)) {
10750 int i;
10751 for (i = 0; i < ret; i++) {
10752 target_ep[i].events = tswap32(ep[i].events);
10753 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10754 }
10755 }
10756 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10757 break;
10758 }
10759#endif
10760#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010761#ifdef TARGET_NR_prlimit64
10762 case TARGET_NR_prlimit64:
10763 {
10764 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10765 struct target_rlimit64 *target_rnew, *target_rold;
10766 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010767 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010768 if (arg3) {
10769 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10770 goto efault;
10771 }
10772 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10773 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10774 unlock_user_struct(target_rnew, arg3, 0);
10775 rnewp = &rnew;
10776 }
10777
Felix Janda95018012014-12-02 22:11:17 +010010778 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010779 if (!is_error(ret) && arg4) {
10780 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10781 goto efault;
10782 }
10783 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10784 target_rold->rlim_max = tswap64(rold.rlim_max);
10785 unlock_user_struct(target_rold, arg4, 1);
10786 }
10787 break;
10788 }
10789#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010790#ifdef TARGET_NR_gethostname
10791 case TARGET_NR_gethostname:
10792 {
10793 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10794 if (name) {
10795 ret = get_errno(gethostname(name, arg2));
10796 unlock_user(name, arg1, arg2);
10797 } else {
10798 ret = -TARGET_EFAULT;
10799 }
10800 break;
10801 }
10802#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010803#ifdef TARGET_NR_atomic_cmpxchg_32
10804 case TARGET_NR_atomic_cmpxchg_32:
10805 {
10806 /* should use start_exclusive from main.c */
10807 abi_ulong mem_value;
10808 if (get_user_u32(mem_value, arg6)) {
10809 target_siginfo_t info;
10810 info.si_signo = SIGSEGV;
10811 info.si_errno = 0;
10812 info.si_code = TARGET_SEGV_MAPERR;
10813 info._sifields._sigfault._addr = arg6;
10814 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10815 ret = 0xdeadbeef;
10816
10817 }
10818 if (mem_value == arg2)
10819 put_user_u32(arg1, arg6);
10820 ret = mem_value;
10821 break;
10822 }
10823#endif
10824#ifdef TARGET_NR_atomic_barrier
10825 case TARGET_NR_atomic_barrier:
10826 {
10827 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010828 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010829 break;
10830 }
10831#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010832
10833#ifdef TARGET_NR_timer_create
10834 case TARGET_NR_timer_create:
10835 {
10836 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10837
10838 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010839
10840 int clkid = arg1;
10841 int timer_index = next_free_host_timer();
10842
10843 if (timer_index < 0) {
10844 ret = -TARGET_EAGAIN;
10845 } else {
10846 timer_t *phtimer = g_posix_timers + timer_index;
10847
10848 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010849 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010850 ret = target_to_host_sigevent(phost_sevp, arg2);
10851 if (ret != 0) {
10852 break;
10853 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010854 }
10855
10856 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10857 if (ret) {
10858 phtimer = NULL;
10859 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010860 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010861 goto efault;
10862 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010863 }
10864 }
10865 break;
10866 }
10867#endif
10868
10869#ifdef TARGET_NR_timer_settime
10870 case TARGET_NR_timer_settime:
10871 {
10872 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
10873 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010874 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010875
Alexander Grafaecc8862014-11-10 21:33:03 +010010876 if (timerid < 0) {
10877 ret = timerid;
10878 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010879 ret = -TARGET_EINVAL;
10880 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010881 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010882 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
10883
10884 target_to_host_itimerspec(&hspec_new, arg3);
10885 ret = get_errno(
10886 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
10887 host_to_target_itimerspec(arg2, &hspec_old);
10888 }
10889 break;
10890 }
10891#endif
10892
10893#ifdef TARGET_NR_timer_gettime
10894 case TARGET_NR_timer_gettime:
10895 {
10896 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010897 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010898
Alexander Grafaecc8862014-11-10 21:33:03 +010010899 if (timerid < 0) {
10900 ret = timerid;
10901 } else if (!arg2) {
10902 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010903 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010904 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010905 struct itimerspec hspec;
10906 ret = get_errno(timer_gettime(htimer, &hspec));
10907
10908 if (host_to_target_itimerspec(arg2, &hspec)) {
10909 ret = -TARGET_EFAULT;
10910 }
10911 }
10912 break;
10913 }
10914#endif
10915
10916#ifdef TARGET_NR_timer_getoverrun
10917 case TARGET_NR_timer_getoverrun:
10918 {
10919 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010920 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010921
Alexander Grafaecc8862014-11-10 21:33:03 +010010922 if (timerid < 0) {
10923 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010924 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010925 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010926 ret = get_errno(timer_getoverrun(htimer));
10927 }
Laurent Viviere36800c2015-10-02 14:48:09 +020010928 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010929 break;
10930 }
10931#endif
10932
10933#ifdef TARGET_NR_timer_delete
10934 case TARGET_NR_timer_delete:
10935 {
10936 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010937 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010938
Alexander Grafaecc8862014-11-10 21:33:03 +010010939 if (timerid < 0) {
10940 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010941 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010942 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010943 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020010944 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010945 }
10946 break;
10947 }
10948#endif
10949
Riku Voipio51834342014-06-22 11:25:42 +010010950#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
10951 case TARGET_NR_timerfd_create:
10952 ret = get_errno(timerfd_create(arg1,
10953 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
10954 break;
10955#endif
10956
10957#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
10958 case TARGET_NR_timerfd_gettime:
10959 {
10960 struct itimerspec its_curr;
10961
10962 ret = get_errno(timerfd_gettime(arg1, &its_curr));
10963
10964 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
10965 goto efault;
10966 }
10967 }
10968 break;
10969#endif
10970
10971#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
10972 case TARGET_NR_timerfd_settime:
10973 {
10974 struct itimerspec its_new, its_old, *p_new;
10975
10976 if (arg3) {
10977 if (target_to_host_itimerspec(&its_new, arg3)) {
10978 goto efault;
10979 }
10980 p_new = &its_new;
10981 } else {
10982 p_new = NULL;
10983 }
10984
10985 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
10986
10987 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
10988 goto efault;
10989 }
10990 }
10991 break;
10992#endif
10993
Paul Burtonab31cda2014-06-22 11:25:43 +010010994#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
10995 case TARGET_NR_ioprio_get:
10996 ret = get_errno(ioprio_get(arg1, arg2));
10997 break;
10998#endif
10999
11000#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11001 case TARGET_NR_ioprio_set:
11002 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11003 break;
11004#endif
11005
Riku Voipio9af5c902014-08-12 15:58:57 +030011006#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11007 case TARGET_NR_setns:
11008 ret = get_errno(setns(arg1, arg2));
11009 break;
11010#endif
11011#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11012 case TARGET_NR_unshare:
11013 ret = get_errno(unshare(arg1));
11014 break;
11015#endif
11016
bellard31e31b82003-02-18 22:55:36 +000011017 default:
11018 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011019 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011020#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 +000011021 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011022#endif
ths0da46a62007-10-20 20:23:07 +000011023 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011024 break;
11025 }
bellard579a97f2007-11-11 14:26:47 +000011026fail:
bellardc573ff62004-01-04 15:51:36 +000011027#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011028 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011029#endif
thsb92c47c2007-11-01 00:07:38 +000011030 if(do_strace)
11031 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000011032 return ret;
bellard579a97f2007-11-11 14:26:47 +000011033efault:
11034 ret = -TARGET_EFAULT;
11035 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011036}