blob: c9c2ae9903fd132833eeaf0f6a972dd59b20906c [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>
pbrookd7e40362008-05-23 16:06:43 +0000104#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200105#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000106
bellard3ef693a2003-03-23 20:17:16 +0000107#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000108
pbrookd865bab2008-06-07 22:12:17 +0000109#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
110 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000111
bellard72f03902003-02-18 23:33:18 +0000112//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100113/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
114 * once. This exercises the codepaths for restart.
115 */
116//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000117
bellard1a9353d2003-03-16 20:28:50 +0000118//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000119#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
120#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000121
bellard70a194b2003-08-11 22:20:16 +0000122
bellard70a194b2003-08-11 22:20:16 +0000123#undef _syscall0
124#undef _syscall1
125#undef _syscall2
126#undef _syscall3
127#undef _syscall4
128#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000129#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000130
bellard83fcb512006-06-14 13:37:16 +0000131#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000132static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000133{ \
134 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000135}
136
bellard83fcb512006-06-14 13:37:16 +0000137#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000138static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000139{ \
140 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000141}
142
bellard83fcb512006-06-14 13:37:16 +0000143#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000144static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000145{ \
146 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000147}
148
bellard83fcb512006-06-14 13:37:16 +0000149#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000150static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000151{ \
152 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000153}
154
bellard83fcb512006-06-14 13:37:16 +0000155#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000156static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000157{ \
158 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000159}
160
bellard83fcb512006-06-14 13:37:16 +0000161#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
162 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000163static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000164{ \
165 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000166}
bellard83fcb512006-06-14 13:37:16 +0000167
168
169#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
170 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000171static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
172 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000173{ \
174 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
175}
176
bellard70a194b2003-08-11 22:20:16 +0000177
bellard31e31b82003-02-18 22:55:36 +0000178#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000179#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000180#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000181#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000182#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000183#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000184#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000185#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000186#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000187#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000188#define __NR_sys_inotify_init __NR_inotify_init
189#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
190#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000191
Alexander Graf42a39fb2011-04-15 17:32:45 +0200192#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
193 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000194#define __NR__llseek __NR_lseek
195#endif
196
James Hogana29e5ba2014-03-25 21:51:08 +0000197/* Newer kernel ports have llseek() instead of _llseek() */
198#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
199#define TARGET_NR__llseek TARGET_NR_llseek
200#endif
201
bellard72f03902003-02-18 23:33:18 +0000202#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000203_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000204#else
ths0da46a62007-10-20 20:23:07 +0000205/* This is a replacement for the host gettid() and must return a host
206 errno. */
bellard72f03902003-02-18 23:33:18 +0000207static int gettid(void) {
208 return -ENOSYS;
209}
210#endif
Chen Gang704eff62015-08-21 05:37:33 +0800211#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000212_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100213#endif
214#if !defined(__NR_getdents) || \
215 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000216_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
217#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700218#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000219_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
220 loff_t *, res, uint, wh);
221#endif
222_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
223_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
224#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
225_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
226#endif
227#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
228_syscall2(int,sys_tkill,int,tid,int,sig)
229#endif
230#ifdef __NR_exit_group
231_syscall1(int,exit_group,int,error_code)
232#endif
233#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
234_syscall1(int,set_tid_address,int *,tidptr)
235#endif
aurel323b3f24a2009-04-15 16:12:13 +0000236#if defined(TARGET_NR_futex) && defined(__NR_futex)
237_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
238 const struct timespec *,timeout,int *,uaddr2,int,val3)
239#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500240#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
241_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
242 unsigned long *, user_mask_ptr);
243#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
244_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
245 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200246_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
247 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000248_syscall2(int, capget, struct __user_cap_header_struct *, header,
249 struct __user_cap_data_struct *, data);
250_syscall2(int, capset, struct __user_cap_header_struct *, header,
251 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100252#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
253_syscall2(int, ioprio_get, int, which, int, who)
254#endif
255#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
256_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
257#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100258#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
259_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
260#endif
aurel323b3f24a2009-04-15 16:12:13 +0000261
262static bitmask_transtbl fcntl_flags_tbl[] = {
263 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
264 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
265 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
266 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
267 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
268 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
269 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
270 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700271 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000272 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
273 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
274 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
275 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000276#if defined(O_DIRECT)
277 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
278#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700279#if defined(O_NOATIME)
280 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
281#endif
282#if defined(O_CLOEXEC)
283 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
284#endif
285#if defined(O_PATH)
286 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
287#endif
288 /* Don't terminate the list prematurely on 64-bit host+guest. */
289#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
290 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
291#endif
aurel323b3f24a2009-04-15 16:12:13 +0000292 { 0, 0, 0, 0 }
293};
294
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100295typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100296typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200297typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100298 TargetFdDataFunc host_to_target_data;
299 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100300 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200301} TargetFdTrans;
302
303static TargetFdTrans **target_fd_trans;
304
305static unsigned int target_fd_max;
306
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100307static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200308{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100309 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100310 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200311 }
312 return NULL;
313}
314
Laurent Vivier7b36f782015-10-28 21:40:44 +0100315static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
316{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100317 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100318 return target_fd_trans[fd]->target_to_host_addr;
319 }
320 return NULL;
321}
322
Laurent Viviere36800c2015-10-02 14:48:09 +0200323static void fd_trans_register(int fd, TargetFdTrans *trans)
324{
325 unsigned int oldmax;
326
327 if (fd >= target_fd_max) {
328 oldmax = target_fd_max;
329 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100330 target_fd_trans = g_renew(TargetFdTrans *,
331 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200332 memset((void *)(target_fd_trans + oldmax), 0,
333 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
334 }
335 target_fd_trans[fd] = trans;
336}
337
338static void fd_trans_unregister(int fd)
339{
340 if (fd >= 0 && fd < target_fd_max) {
341 target_fd_trans[fd] = NULL;
342 }
343}
344
345static void fd_trans_dup(int oldfd, int newfd)
346{
347 fd_trans_unregister(newfd);
348 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
349 fd_trans_register(newfd, target_fd_trans[oldfd]);
350 }
351}
352
aurel323b3f24a2009-04-15 16:12:13 +0000353static int sys_getcwd1(char *buf, size_t size)
354{
355 if (getcwd(buf, size) == NULL) {
356 /* getcwd() sets errno */
357 return (-1);
358 }
aurel32aaf4ad32009-04-16 14:17:14 +0000359 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000360}
361
Peter Maydell1acae9f2013-07-02 14:04:12 +0100362#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300363#ifdef CONFIG_UTIMENSAT
364static int sys_utimensat(int dirfd, const char *pathname,
365 const struct timespec times[2], int flags)
366{
367 if (pathname == NULL)
368 return futimens(dirfd, times);
369 else
370 return utimensat(dirfd, pathname, times, flags);
371}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100372#elif defined(__NR_utimensat)
373#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000374_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
375 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100376#else
377static int sys_utimensat(int dirfd, const char *pathname,
378 const struct timespec times[2], int flags)
379{
380 errno = ENOSYS;
381 return -1;
382}
ths9007f0e2007-09-25 17:50:37 +0000383#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100384#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000385
386#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000387#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000388
aurel3239b59762008-10-01 21:46:50 +0000389#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000390static int sys_inotify_init(void)
391{
392 return (inotify_init());
393}
aurel3239b59762008-10-01 21:46:50 +0000394#endif
395#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000396static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
397{
398 return (inotify_add_watch(fd, pathname, mask));
399}
aurel3239b59762008-10-01 21:46:50 +0000400#endif
401#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000402static int sys_inotify_rm_watch(int fd, int32_t wd)
403{
aurel328690e422009-04-17 13:50:32 +0000404 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000405}
aurel3239b59762008-10-01 21:46:50 +0000406#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000407#ifdef CONFIG_INOTIFY1
408#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
409static int sys_inotify_init1(int flags)
410{
411 return (inotify_init1(flags));
412}
413#endif
414#endif
aurel323b3f24a2009-04-15 16:12:13 +0000415#else
416/* Userspace can usually survive runtime without inotify */
417#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000418#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000419#undef TARGET_NR_inotify_add_watch
420#undef TARGET_NR_inotify_rm_watch
421#endif /* CONFIG_INOTIFY */
422
Mike Frysingerd8035d42011-02-07 01:05:51 -0500423#if defined(TARGET_NR_ppoll)
424#ifndef __NR_ppoll
425# define __NR_ppoll -1
426#endif
427#define __NR_sys_ppoll __NR_ppoll
428_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200429 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500430 size_t, sigsetsize)
431#endif
bellard66fb9762003-03-23 01:06:05 +0000432
Peter Maydell163a05a2011-06-27 17:44:52 +0100433#if defined(TARGET_NR_prlimit64)
434#ifndef __NR_prlimit64
435# define __NR_prlimit64 -1
436#endif
437#define __NR_sys_prlimit64 __NR_prlimit64
438/* The glibc rlimit structure may not be that used by the underlying syscall */
439struct host_rlimit64 {
440 uint64_t rlim_cur;
441 uint64_t rlim_max;
442};
443_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
444 const struct host_rlimit64 *, new_limit,
445 struct host_rlimit64 *, old_limit)
446#endif
447
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100448
449#if defined(TARGET_NR_timer_create)
450/* Maxiumum of 32 active POSIX timers allowed at any one time. */
451static timer_t g_posix_timers[32] = { 0, } ;
452
453static inline int next_free_host_timer(void)
454{
455 int k ;
456 /* FIXME: Does finding the next free slot require a lock? */
457 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
458 if (g_posix_timers[k] == 0) {
459 g_posix_timers[k] = (timer_t) 1;
460 return k;
461 }
462 }
463 return -1;
464}
465#endif
466
Riku Voipio48e515d2011-07-12 15:40:51 +0300467/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000468#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300469static inline int regpairs_aligned(void *cpu_env) {
470 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
471}
472#elif defined(TARGET_MIPS)
473static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000474#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
475/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
476 * of registers which translates to the same as ARM/MIPS, because we start with
477 * r3 as arg1 */
478static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300479#else
480static inline int regpairs_aligned(void *cpu_env) { return 0; }
481#endif
482
thsb92c47c2007-11-01 00:07:38 +0000483#define ERRNO_TABLE_SIZE 1200
484
485/* target_to_host_errno_table[] is initialized from
486 * host_to_target_errno_table[] in syscall_init(). */
487static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
488};
489
ths637947f2007-06-01 12:09:19 +0000490/*
thsfe8f0962007-07-12 10:59:21 +0000491 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000492 * minus the errnos that are not actually generic to all archs.
493 */
thsb92c47c2007-11-01 00:07:38 +0000494static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800495 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000496 [EIDRM] = TARGET_EIDRM,
497 [ECHRNG] = TARGET_ECHRNG,
498 [EL2NSYNC] = TARGET_EL2NSYNC,
499 [EL3HLT] = TARGET_EL3HLT,
500 [EL3RST] = TARGET_EL3RST,
501 [ELNRNG] = TARGET_ELNRNG,
502 [EUNATCH] = TARGET_EUNATCH,
503 [ENOCSI] = TARGET_ENOCSI,
504 [EL2HLT] = TARGET_EL2HLT,
505 [EDEADLK] = TARGET_EDEADLK,
506 [ENOLCK] = TARGET_ENOLCK,
507 [EBADE] = TARGET_EBADE,
508 [EBADR] = TARGET_EBADR,
509 [EXFULL] = TARGET_EXFULL,
510 [ENOANO] = TARGET_ENOANO,
511 [EBADRQC] = TARGET_EBADRQC,
512 [EBADSLT] = TARGET_EBADSLT,
513 [EBFONT] = TARGET_EBFONT,
514 [ENOSTR] = TARGET_ENOSTR,
515 [ENODATA] = TARGET_ENODATA,
516 [ETIME] = TARGET_ETIME,
517 [ENOSR] = TARGET_ENOSR,
518 [ENONET] = TARGET_ENONET,
519 [ENOPKG] = TARGET_ENOPKG,
520 [EREMOTE] = TARGET_EREMOTE,
521 [ENOLINK] = TARGET_ENOLINK,
522 [EADV] = TARGET_EADV,
523 [ESRMNT] = TARGET_ESRMNT,
524 [ECOMM] = TARGET_ECOMM,
525 [EPROTO] = TARGET_EPROTO,
526 [EDOTDOT] = TARGET_EDOTDOT,
527 [EMULTIHOP] = TARGET_EMULTIHOP,
528 [EBADMSG] = TARGET_EBADMSG,
529 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
530 [EOVERFLOW] = TARGET_EOVERFLOW,
531 [ENOTUNIQ] = TARGET_ENOTUNIQ,
532 [EBADFD] = TARGET_EBADFD,
533 [EREMCHG] = TARGET_EREMCHG,
534 [ELIBACC] = TARGET_ELIBACC,
535 [ELIBBAD] = TARGET_ELIBBAD,
536 [ELIBSCN] = TARGET_ELIBSCN,
537 [ELIBMAX] = TARGET_ELIBMAX,
538 [ELIBEXEC] = TARGET_ELIBEXEC,
539 [EILSEQ] = TARGET_EILSEQ,
540 [ENOSYS] = TARGET_ENOSYS,
541 [ELOOP] = TARGET_ELOOP,
542 [ERESTART] = TARGET_ERESTART,
543 [ESTRPIPE] = TARGET_ESTRPIPE,
544 [ENOTEMPTY] = TARGET_ENOTEMPTY,
545 [EUSERS] = TARGET_EUSERS,
546 [ENOTSOCK] = TARGET_ENOTSOCK,
547 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
548 [EMSGSIZE] = TARGET_EMSGSIZE,
549 [EPROTOTYPE] = TARGET_EPROTOTYPE,
550 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
551 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
552 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
553 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
554 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
555 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
556 [EADDRINUSE] = TARGET_EADDRINUSE,
557 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
558 [ENETDOWN] = TARGET_ENETDOWN,
559 [ENETUNREACH] = TARGET_ENETUNREACH,
560 [ENETRESET] = TARGET_ENETRESET,
561 [ECONNABORTED] = TARGET_ECONNABORTED,
562 [ECONNRESET] = TARGET_ECONNRESET,
563 [ENOBUFS] = TARGET_ENOBUFS,
564 [EISCONN] = TARGET_EISCONN,
565 [ENOTCONN] = TARGET_ENOTCONN,
566 [EUCLEAN] = TARGET_EUCLEAN,
567 [ENOTNAM] = TARGET_ENOTNAM,
568 [ENAVAIL] = TARGET_ENAVAIL,
569 [EISNAM] = TARGET_EISNAM,
570 [EREMOTEIO] = TARGET_EREMOTEIO,
571 [ESHUTDOWN] = TARGET_ESHUTDOWN,
572 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
573 [ETIMEDOUT] = TARGET_ETIMEDOUT,
574 [ECONNREFUSED] = TARGET_ECONNREFUSED,
575 [EHOSTDOWN] = TARGET_EHOSTDOWN,
576 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
577 [EALREADY] = TARGET_EALREADY,
578 [EINPROGRESS] = TARGET_EINPROGRESS,
579 [ESTALE] = TARGET_ESTALE,
580 [ECANCELED] = TARGET_ECANCELED,
581 [ENOMEDIUM] = TARGET_ENOMEDIUM,
582 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000583#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000584 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000585#endif
586#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000587 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000588#endif
589#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000590 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000591#endif
592#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000593 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000594#endif
595#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000596 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000597#endif
598#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000599 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000600#endif
thsb92c47c2007-11-01 00:07:38 +0000601};
ths637947f2007-06-01 12:09:19 +0000602
603static inline int host_to_target_errno(int err)
604{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100605 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
606 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000607 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100608 }
ths637947f2007-06-01 12:09:19 +0000609 return err;
610}
611
thsb92c47c2007-11-01 00:07:38 +0000612static inline int target_to_host_errno(int err)
613{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100614 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
615 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000616 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100617 }
thsb92c47c2007-11-01 00:07:38 +0000618 return err;
619}
620
blueswir1992f48a2007-10-14 16:27:31 +0000621static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000622{
623 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000624 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000625 else
626 return ret;
627}
628
blueswir1992f48a2007-10-14 16:27:31 +0000629static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000630{
blueswir1992f48a2007-10-14 16:27:31 +0000631 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000632}
633
thsb92c47c2007-11-01 00:07:38 +0000634char *target_strerror(int err)
635{
Alexander Graf962b2892011-11-21 12:04:07 +0100636 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
637 return NULL;
638 }
thsb92c47c2007-11-01 00:07:38 +0000639 return strerror(target_to_host_errno(err));
640}
641
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100642#define safe_syscall0(type, name) \
643static type safe_##name(void) \
644{ \
645 return safe_syscall(__NR_##name); \
646}
647
648#define safe_syscall1(type, name, type1, arg1) \
649static type safe_##name(type1 arg1) \
650{ \
651 return safe_syscall(__NR_##name, arg1); \
652}
653
654#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
655static type safe_##name(type1 arg1, type2 arg2) \
656{ \
657 return safe_syscall(__NR_##name, arg1, arg2); \
658}
659
660#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
661static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
662{ \
663 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
664}
665
666#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
667 type4, arg4) \
668static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
669{ \
670 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
671}
672
673#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
674 type4, arg4, type5, arg5) \
675static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
676 type5 arg5) \
677{ \
678 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
679}
680
681#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
682 type4, arg4, type5, arg5, type6, arg6) \
683static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
684 type5 arg5, type6 arg6) \
685{ \
686 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
687}
688
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100689safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
690safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100691safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
692 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100693safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
694 struct rusage *, rusage)
695safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
696 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100697safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100698safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
699 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100700
Paul Burton8289d112014-06-22 11:25:33 +0100701static inline int host_to_target_sock_type(int host_type)
702{
703 int target_type;
704
705 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
706 case SOCK_DGRAM:
707 target_type = TARGET_SOCK_DGRAM;
708 break;
709 case SOCK_STREAM:
710 target_type = TARGET_SOCK_STREAM;
711 break;
712 default:
713 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
714 break;
715 }
716
717#if defined(SOCK_CLOEXEC)
718 if (host_type & SOCK_CLOEXEC) {
719 target_type |= TARGET_SOCK_CLOEXEC;
720 }
721#endif
722
723#if defined(SOCK_NONBLOCK)
724 if (host_type & SOCK_NONBLOCK) {
725 target_type |= TARGET_SOCK_NONBLOCK;
726 }
727#endif
728
729 return target_type;
730}
731
blueswir1992f48a2007-10-14 16:27:31 +0000732static abi_ulong target_brk;
733static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000734static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000735
blueswir1992f48a2007-10-14 16:27:31 +0000736void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000737{
blueswir14c1de732007-07-07 20:45:44 +0000738 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000739 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000740}
741
vincent4d1de872011-06-14 21:56:33 +0000742//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
743#define DEBUGF_BRK(message, args...)
744
ths0da46a62007-10-20 20:23:07 +0000745/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000746abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000747{
blueswir1992f48a2007-10-14 16:27:31 +0000748 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000749 int new_alloc_size;
750
Paul Brook3a0c6c42012-02-09 19:04:27 +0000751 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000752
vincent4d1de872011-06-14 21:56:33 +0000753 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000754 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000755 return target_brk;
756 }
757 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000758 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
759 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000760 return target_brk;
761 }
bellard31e31b82003-02-18 22:55:36 +0000762
vincent4d1de872011-06-14 21:56:33 +0000763 /* If the new brk is less than the highest page reserved to the
764 * target heap allocation, set it and we're almost done... */
765 if (new_brk <= brk_page) {
766 /* Heap contents are initialized to zero, as for anonymous
767 * mapped pages. */
768 if (new_brk > target_brk) {
769 memset(g2h(target_brk), 0, new_brk - target_brk);
770 }
bellard31e31b82003-02-18 22:55:36 +0000771 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000772 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000773 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000774 }
775
Peter Maydell00faf082011-04-18 16:34:24 +0100776 /* We need to allocate more memory after the brk... Note that
777 * we don't use MAP_FIXED because that will map over the top of
778 * any existing mapping (like the one with the host libc or qemu
779 * itself); instead we treat "mapped but at wrong address" as
780 * a failure and unmap again.
781 */
vincent4d1de872011-06-14 21:56:33 +0000782 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000783 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000784 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100785 MAP_ANON|MAP_PRIVATE, 0, 0));
786
787 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200788 /* Heap contents are initialized to zero, as for anonymous
789 * mapped pages. Technically the new pages are already
790 * initialized to zero since they *are* anonymous mapped
791 * pages, however we have to take care with the contents that
792 * come from the remaining part of the previous page: it may
793 * contains garbage data due to a previous heap usage (grown
794 * then shrunken). */
795 memset(g2h(target_brk), 0, brk_page - target_brk);
796
Peter Maydell00faf082011-04-18 16:34:24 +0100797 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000798 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000799 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
800 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100801 return target_brk;
802 } else if (mapped_addr != -1) {
803 /* Mapped but at wrong address, meaning there wasn't actually
804 * enough space for this brk.
805 */
806 target_munmap(mapped_addr, new_alloc_size);
807 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000808 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000809 }
810 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000811 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100812 }
balrog7ab240a2008-04-26 12:17:34 +0000813
Richard Henderson7dd46c02010-05-03 10:07:49 -0700814#if defined(TARGET_ALPHA)
815 /* We (partially) emulate OSF/1 on Alpha, which requires we
816 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100817 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700818#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100819 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000820 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000821}
822
ths26edcf42007-12-09 02:25:24 +0000823static inline abi_long copy_from_user_fdset(fd_set *fds,
824 abi_ulong target_fds_addr,
825 int n)
bellard31e31b82003-02-18 22:55:36 +0000826{
ths26edcf42007-12-09 02:25:24 +0000827 int i, nw, j, k;
828 abi_ulong b, *target_fds;
829
830 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
831 if (!(target_fds = lock_user(VERIFY_READ,
832 target_fds_addr,
833 sizeof(abi_ulong) * nw,
834 1)))
835 return -TARGET_EFAULT;
836
837 FD_ZERO(fds);
838 k = 0;
839 for (i = 0; i < nw; i++) {
840 /* grab the abi_ulong */
841 __get_user(b, &target_fds[i]);
842 for (j = 0; j < TARGET_ABI_BITS; j++) {
843 /* check the bit inside the abi_ulong */
844 if ((b >> j) & 1)
845 FD_SET(k, fds);
846 k++;
bellard31e31b82003-02-18 22:55:36 +0000847 }
bellard31e31b82003-02-18 22:55:36 +0000848 }
ths26edcf42007-12-09 02:25:24 +0000849
850 unlock_user(target_fds, target_fds_addr, 0);
851
852 return 0;
bellard31e31b82003-02-18 22:55:36 +0000853}
854
Mike Frysinger055e0902011-06-03 17:01:49 -0400855static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
856 abi_ulong target_fds_addr,
857 int n)
858{
859 if (target_fds_addr) {
860 if (copy_from_user_fdset(fds, target_fds_addr, n))
861 return -TARGET_EFAULT;
862 *fds_ptr = fds;
863 } else {
864 *fds_ptr = NULL;
865 }
866 return 0;
867}
868
ths26edcf42007-12-09 02:25:24 +0000869static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
870 const fd_set *fds,
871 int n)
bellard31e31b82003-02-18 22:55:36 +0000872{
bellard31e31b82003-02-18 22:55:36 +0000873 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000874 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000875 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000876
ths26edcf42007-12-09 02:25:24 +0000877 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
878 if (!(target_fds = lock_user(VERIFY_WRITE,
879 target_fds_addr,
880 sizeof(abi_ulong) * nw,
881 0)))
882 return -TARGET_EFAULT;
883
884 k = 0;
885 for (i = 0; i < nw; i++) {
886 v = 0;
887 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000888 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000889 k++;
bellard31e31b82003-02-18 22:55:36 +0000890 }
ths26edcf42007-12-09 02:25:24 +0000891 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000892 }
ths26edcf42007-12-09 02:25:24 +0000893
894 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
895
896 return 0;
bellard31e31b82003-02-18 22:55:36 +0000897}
898
bellardc596ed12003-07-13 17:32:31 +0000899#if defined(__alpha__)
900#define HOST_HZ 1024
901#else
902#define HOST_HZ 100
903#endif
904
blueswir1992f48a2007-10-14 16:27:31 +0000905static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000906{
907#if HOST_HZ == TARGET_HZ
908 return ticks;
909#else
910 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
911#endif
912}
913
bellard579a97f2007-11-11 14:26:47 +0000914static inline abi_long host_to_target_rusage(abi_ulong target_addr,
915 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000916{
pbrook53a59602006-03-25 19:31:22 +0000917 struct target_rusage *target_rusage;
918
bellard579a97f2007-11-11 14:26:47 +0000919 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
920 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200921 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
922 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
923 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
924 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
925 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
926 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
927 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
928 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
929 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
930 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
931 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
932 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
933 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
934 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
935 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
936 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
937 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
938 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000939 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000940
941 return 0;
bellardb4091862003-05-16 15:39:34 +0000942}
943
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200944static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900945{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200946 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300947 rlim_t result;
948
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200949 target_rlim_swap = tswapal(target_rlim);
950 if (target_rlim_swap == TARGET_RLIM_INFINITY)
951 return RLIM_INFINITY;
952
953 result = target_rlim_swap;
954 if (target_rlim_swap != (rlim_t)result)
955 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300956
957 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900958}
959
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200960static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900961{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200962 abi_ulong target_rlim_swap;
963 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300964
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200965 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300966 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900967 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300968 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200969 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300970
971 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900972}
973
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300974static inline int target_to_host_resource(int code)
975{
976 switch (code) {
977 case TARGET_RLIMIT_AS:
978 return RLIMIT_AS;
979 case TARGET_RLIMIT_CORE:
980 return RLIMIT_CORE;
981 case TARGET_RLIMIT_CPU:
982 return RLIMIT_CPU;
983 case TARGET_RLIMIT_DATA:
984 return RLIMIT_DATA;
985 case TARGET_RLIMIT_FSIZE:
986 return RLIMIT_FSIZE;
987 case TARGET_RLIMIT_LOCKS:
988 return RLIMIT_LOCKS;
989 case TARGET_RLIMIT_MEMLOCK:
990 return RLIMIT_MEMLOCK;
991 case TARGET_RLIMIT_MSGQUEUE:
992 return RLIMIT_MSGQUEUE;
993 case TARGET_RLIMIT_NICE:
994 return RLIMIT_NICE;
995 case TARGET_RLIMIT_NOFILE:
996 return RLIMIT_NOFILE;
997 case TARGET_RLIMIT_NPROC:
998 return RLIMIT_NPROC;
999 case TARGET_RLIMIT_RSS:
1000 return RLIMIT_RSS;
1001 case TARGET_RLIMIT_RTPRIO:
1002 return RLIMIT_RTPRIO;
1003 case TARGET_RLIMIT_SIGPENDING:
1004 return RLIMIT_SIGPENDING;
1005 case TARGET_RLIMIT_STACK:
1006 return RLIMIT_STACK;
1007 default:
1008 return code;
1009 }
1010}
1011
ths788f5ec2007-12-09 02:37:05 +00001012static inline abi_long copy_from_user_timeval(struct timeval *tv,
1013 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001014{
pbrook53a59602006-03-25 19:31:22 +00001015 struct target_timeval *target_tv;
1016
ths788f5ec2007-12-09 02:37:05 +00001017 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001018 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001019
1020 __get_user(tv->tv_sec, &target_tv->tv_sec);
1021 __get_user(tv->tv_usec, &target_tv->tv_usec);
1022
1023 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001024
1025 return 0;
bellard31e31b82003-02-18 22:55:36 +00001026}
1027
ths788f5ec2007-12-09 02:37:05 +00001028static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1029 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001030{
pbrook53a59602006-03-25 19:31:22 +00001031 struct target_timeval *target_tv;
1032
ths788f5ec2007-12-09 02:37:05 +00001033 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001034 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001035
1036 __put_user(tv->tv_sec, &target_tv->tv_sec);
1037 __put_user(tv->tv_usec, &target_tv->tv_usec);
1038
1039 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001040
1041 return 0;
bellard31e31b82003-02-18 22:55:36 +00001042}
1043
Paul Burtonef4467e2014-06-22 11:25:40 +01001044static inline abi_long copy_from_user_timezone(struct timezone *tz,
1045 abi_ulong target_tz_addr)
1046{
1047 struct target_timezone *target_tz;
1048
1049 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1050 return -TARGET_EFAULT;
1051 }
1052
1053 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1054 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1055
1056 unlock_user_struct(target_tz, target_tz_addr, 0);
1057
1058 return 0;
1059}
1060
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001061#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1062#include <mqueue.h>
1063
aurel3224e10032009-04-15 16:11:43 +00001064static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1065 abi_ulong target_mq_attr_addr)
1066{
1067 struct target_mq_attr *target_mq_attr;
1068
1069 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1070 target_mq_attr_addr, 1))
1071 return -TARGET_EFAULT;
1072
1073 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1074 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1075 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1076 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1077
1078 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1079
1080 return 0;
1081}
1082
1083static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1084 const struct mq_attr *attr)
1085{
1086 struct target_mq_attr *target_mq_attr;
1087
1088 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1089 target_mq_attr_addr, 0))
1090 return -TARGET_EFAULT;
1091
1092 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1093 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1094 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1095 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1096
1097 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1098
1099 return 0;
1100}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001101#endif
bellard31e31b82003-02-18 22:55:36 +00001102
Mike Frysinger055e0902011-06-03 17:01:49 -04001103#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001104/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001105static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001106 abi_ulong rfd_addr, abi_ulong wfd_addr,
1107 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001108{
1109 fd_set rfds, wfds, efds;
1110 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001111 struct timeval tv;
1112 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001113 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001114
Mike Frysinger055e0902011-06-03 17:01:49 -04001115 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1116 if (ret) {
1117 return ret;
pbrook53a59602006-03-25 19:31:22 +00001118 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001119 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1120 if (ret) {
1121 return ret;
pbrook53a59602006-03-25 19:31:22 +00001122 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001123 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1124 if (ret) {
1125 return ret;
pbrook53a59602006-03-25 19:31:22 +00001126 }
ths3b46e622007-09-17 08:09:54 +00001127
ths26edcf42007-12-09 02:25:24 +00001128 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001129 if (copy_from_user_timeval(&tv, target_tv_addr))
1130 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001131 ts.tv_sec = tv.tv_sec;
1132 ts.tv_nsec = tv.tv_usec * 1000;
1133 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001134 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001135 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001136 }
ths26edcf42007-12-09 02:25:24 +00001137
Peter Maydell6df9d382016-05-12 18:47:51 +01001138 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1139 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001140
ths26edcf42007-12-09 02:25:24 +00001141 if (!is_error(ret)) {
1142 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1143 return -TARGET_EFAULT;
1144 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1145 return -TARGET_EFAULT;
1146 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1147 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001148
Peter Maydell6df9d382016-05-12 18:47:51 +01001149 if (target_tv_addr) {
1150 tv.tv_sec = ts.tv_sec;
1151 tv.tv_usec = ts.tv_nsec / 1000;
1152 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1153 return -TARGET_EFAULT;
1154 }
1155 }
bellard31e31b82003-02-18 22:55:36 +00001156 }
bellard579a97f2007-11-11 14:26:47 +00001157
bellard31e31b82003-02-18 22:55:36 +00001158 return ret;
1159}
Mike Frysinger055e0902011-06-03 17:01:49 -04001160#endif
bellard31e31b82003-02-18 22:55:36 +00001161
Riku Voipio099d6b02009-05-05 12:10:04 +03001162static abi_long do_pipe2(int host_pipe[], int flags)
1163{
1164#ifdef CONFIG_PIPE2
1165 return pipe2(host_pipe, flags);
1166#else
1167 return -ENOSYS;
1168#endif
1169}
1170
Richard Hendersonfb41a662010-05-03 10:07:52 -07001171static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1172 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001173{
1174 int host_pipe[2];
1175 abi_long ret;
1176 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1177
1178 if (is_error(ret))
1179 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001180
1181 /* Several targets have special calling conventions for the original
1182 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1183 if (!is_pipe2) {
1184#if defined(TARGET_ALPHA)
1185 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1186 return host_pipe[0];
1187#elif defined(TARGET_MIPS)
1188 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1189 return host_pipe[0];
1190#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001191 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001192 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001193#elif defined(TARGET_SPARC)
1194 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1195 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001196#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001197 }
1198
Riku Voipio099d6b02009-05-05 12:10:04 +03001199 if (put_user_s32(host_pipe[0], pipedes)
1200 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1201 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001202 return get_errno(ret);
1203}
1204
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001205static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1206 abi_ulong target_addr,
1207 socklen_t len)
1208{
1209 struct target_ip_mreqn *target_smreqn;
1210
1211 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1212 if (!target_smreqn)
1213 return -TARGET_EFAULT;
1214 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1215 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1216 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001217 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001218 unlock_user(target_smreqn, target_addr, 0);
1219
1220 return 0;
1221}
1222
Laurent Vivier7b36f782015-10-28 21:40:44 +01001223static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001224 abi_ulong target_addr,
1225 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001226{
aurel32607175e2009-04-15 16:11:59 +00001227 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1228 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001229 struct target_sockaddr *target_saddr;
1230
Laurent Vivier7b36f782015-10-28 21:40:44 +01001231 if (fd_trans_target_to_host_addr(fd)) {
1232 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1233 }
1234
bellard579a97f2007-11-11 14:26:47 +00001235 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1236 if (!target_saddr)
1237 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001238
1239 sa_family = tswap16(target_saddr->sa_family);
1240
1241 /* Oops. The caller might send a incomplete sun_path; sun_path
1242 * must be terminated by \0 (see the manual page), but
1243 * unfortunately it is quite common to specify sockaddr_un
1244 * length as "strlen(x->sun_path)" while it should be
1245 * "strlen(...) + 1". We'll fix that here if needed.
1246 * Linux kernel has a similar feature.
1247 */
1248
1249 if (sa_family == AF_UNIX) {
1250 if (len < unix_maxlen && len > 0) {
1251 char *cp = (char*)target_saddr;
1252
1253 if ( cp[len-1] && !cp[len] )
1254 len++;
1255 }
1256 if (len > unix_maxlen)
1257 len = unix_maxlen;
1258 }
1259
pbrook53a59602006-03-25 19:31:22 +00001260 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001261 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001262 if (sa_family == AF_PACKET) {
1263 struct target_sockaddr_ll *lladdr;
1264
1265 lladdr = (struct target_sockaddr_ll *)addr;
1266 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1267 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1268 }
pbrook53a59602006-03-25 19:31:22 +00001269 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001270
1271 return 0;
bellard7854b052003-03-29 17:22:23 +00001272}
1273
bellard579a97f2007-11-11 14:26:47 +00001274static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1275 struct sockaddr *addr,
1276 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001277{
pbrook53a59602006-03-25 19:31:22 +00001278 struct target_sockaddr *target_saddr;
1279
bellard579a97f2007-11-11 14:26:47 +00001280 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1281 if (!target_saddr)
1282 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001283 memcpy(target_saddr, addr, len);
1284 target_saddr->sa_family = tswap16(addr->sa_family);
1285 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001286
1287 return 0;
bellard7854b052003-03-29 17:22:23 +00001288}
1289
bellard5a4a8982007-11-11 17:39:18 +00001290static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1291 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001292{
1293 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001294 abi_long msg_controllen;
1295 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001296 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001297 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001298
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001299 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001300 if (msg_controllen < sizeof (struct target_cmsghdr))
1301 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001302 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001303 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001304 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001305 if (!target_cmsg)
1306 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001307
1308 while (cmsg && target_cmsg) {
1309 void *data = CMSG_DATA(cmsg);
1310 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1311
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001312 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001313 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1314
1315 space += CMSG_SPACE(len);
1316 if (space > msgh->msg_controllen) {
1317 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001318 /* This is a QEMU bug, since we allocated the payload
1319 * area ourselves (unlike overflow in host-to-target
1320 * conversion, which is just the guest giving us a buffer
1321 * that's too small). It can't happen for the payload types
1322 * we currently support; if it becomes an issue in future
1323 * we would need to improve our allocation strategy to
1324 * something more intelligent than "twice the size of the
1325 * target buffer we're reading from".
1326 */
bellard31febb72005-12-18 20:03:27 +00001327 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001328 break;
1329 }
1330
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001331 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1332 cmsg->cmsg_level = SOL_SOCKET;
1333 } else {
1334 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1335 }
bellard7854b052003-03-29 17:22:23 +00001336 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1337 cmsg->cmsg_len = CMSG_LEN(len);
1338
Alex Suykov30b8b682014-12-23 07:52:58 +02001339 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001340 int *fd = (int *)data;
1341 int *target_fd = (int *)target_data;
1342 int i, numfds = len / sizeof(int);
1343
Peter Maydell876e23c2015-05-26 19:46:32 +01001344 for (i = 0; i < numfds; i++) {
1345 __get_user(fd[i], target_fd + i);
1346 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001347 } else if (cmsg->cmsg_level == SOL_SOCKET
1348 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1349 struct ucred *cred = (struct ucred *)data;
1350 struct target_ucred *target_cred =
1351 (struct target_ucred *)target_data;
1352
Peter Maydell876e23c2015-05-26 19:46:32 +01001353 __get_user(cred->pid, &target_cred->pid);
1354 __get_user(cred->uid, &target_cred->uid);
1355 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001356 } else {
1357 gemu_log("Unsupported ancillary data: %d/%d\n",
1358 cmsg->cmsg_level, cmsg->cmsg_type);
1359 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001360 }
1361
1362 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001363 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1364 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001365 }
bellard5a4a8982007-11-11 17:39:18 +00001366 unlock_user(target_cmsg, target_cmsg_addr, 0);
1367 the_end:
bellard7854b052003-03-29 17:22:23 +00001368 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001369 return 0;
bellard7854b052003-03-29 17:22:23 +00001370}
1371
bellard5a4a8982007-11-11 17:39:18 +00001372static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1373 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001374{
1375 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001376 abi_long msg_controllen;
1377 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001378 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001379 socklen_t space = 0;
1380
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001381 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001382 if (msg_controllen < sizeof (struct target_cmsghdr))
1383 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001384 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001385 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001386 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001387 if (!target_cmsg)
1388 return -TARGET_EFAULT;
1389
bellard7854b052003-03-29 17:22:23 +00001390 while (cmsg && target_cmsg) {
1391 void *data = CMSG_DATA(cmsg);
1392 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1393
1394 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001395 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001396
Peter Maydellc2aeb252015-05-26 19:46:31 +01001397 /* We never copy a half-header but may copy half-data;
1398 * this is Linux's behaviour in put_cmsg(). Note that
1399 * truncation here is a guest problem (which we report
1400 * to the guest via the CTRUNC bit), unlike truncation
1401 * in target_to_host_cmsg, which is a QEMU bug.
1402 */
1403 if (msg_controllen < sizeof(struct cmsghdr)) {
1404 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001405 break;
1406 }
1407
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001408 if (cmsg->cmsg_level == SOL_SOCKET) {
1409 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1410 } else {
1411 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1412 }
bellard7854b052003-03-29 17:22:23 +00001413 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001414
Peter Maydellc2aeb252015-05-26 19:46:31 +01001415 tgt_len = TARGET_CMSG_LEN(len);
1416
1417 /* Payload types which need a different size of payload on
1418 * the target must adjust tgt_len here.
1419 */
1420 switch (cmsg->cmsg_level) {
1421 case SOL_SOCKET:
1422 switch (cmsg->cmsg_type) {
1423 case SO_TIMESTAMP:
1424 tgt_len = sizeof(struct target_timeval);
1425 break;
1426 default:
1427 break;
1428 }
1429 default:
1430 break;
1431 }
1432
1433 if (msg_controllen < tgt_len) {
1434 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1435 tgt_len = msg_controllen;
1436 }
1437
1438 /* We must now copy-and-convert len bytes of payload
1439 * into tgt_len bytes of destination space. Bear in mind
1440 * that in both source and destination we may be dealing
1441 * with a truncated value!
1442 */
Huw Davies52b65492014-04-17 14:02:47 +01001443 switch (cmsg->cmsg_level) {
1444 case SOL_SOCKET:
1445 switch (cmsg->cmsg_type) {
1446 case SCM_RIGHTS:
1447 {
1448 int *fd = (int *)data;
1449 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001450 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001451
Peter Maydell876e23c2015-05-26 19:46:32 +01001452 for (i = 0; i < numfds; i++) {
1453 __put_user(fd[i], target_fd + i);
1454 }
Huw Davies52b65492014-04-17 14:02:47 +01001455 break;
1456 }
1457 case SO_TIMESTAMP:
1458 {
1459 struct timeval *tv = (struct timeval *)data;
1460 struct target_timeval *target_tv =
1461 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001462
Peter Maydellc2aeb252015-05-26 19:46:31 +01001463 if (len != sizeof(struct timeval) ||
1464 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001465 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001466 }
Huw Davies52b65492014-04-17 14:02:47 +01001467
1468 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001469 __put_user(tv->tv_sec, &target_tv->tv_sec);
1470 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001471 break;
1472 }
Huw Davies4bc29752014-04-17 14:02:48 +01001473 case SCM_CREDENTIALS:
1474 {
1475 struct ucred *cred = (struct ucred *)data;
1476 struct target_ucred *target_cred =
1477 (struct target_ucred *)target_data;
1478
1479 __put_user(cred->pid, &target_cred->pid);
1480 __put_user(cred->uid, &target_cred->uid);
1481 __put_user(cred->gid, &target_cred->gid);
1482 break;
1483 }
Huw Davies52b65492014-04-17 14:02:47 +01001484 default:
1485 goto unimplemented;
1486 }
1487 break;
1488
1489 default:
1490 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001491 gemu_log("Unsupported ancillary data: %d/%d\n",
1492 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001493 memcpy(target_data, data, MIN(len, tgt_len));
1494 if (tgt_len > len) {
1495 memset(target_data + len, 0, tgt_len - len);
1496 }
bellard7854b052003-03-29 17:22:23 +00001497 }
1498
Peter Maydellc2aeb252015-05-26 19:46:31 +01001499 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001500 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001501 if (msg_controllen < tgt_space) {
1502 tgt_space = msg_controllen;
1503 }
1504 msg_controllen -= tgt_space;
1505 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001506 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001507 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1508 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001509 }
bellard5a4a8982007-11-11 17:39:18 +00001510 unlock_user(target_cmsg, target_cmsg_addr, space);
1511 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001512 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001513 return 0;
bellard7854b052003-03-29 17:22:23 +00001514}
1515
ths0da46a62007-10-20 20:23:07 +00001516/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001517static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001518 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001519{
blueswir1992f48a2007-10-14 16:27:31 +00001520 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001521 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001522 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001523 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001524
bellard8853f862004-02-22 14:57:26 +00001525 switch(level) {
1526 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001527 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001528 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001529 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001530
bellard2f619692007-11-16 10:46:05 +00001531 if (get_user_u32(val, optval_addr))
1532 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001533 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1534 break;
1535 case SOL_IP:
1536 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001537 case IP_TOS:
1538 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001539 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001540 case IP_ROUTER_ALERT:
1541 case IP_RECVOPTS:
1542 case IP_RETOPTS:
1543 case IP_PKTINFO:
1544 case IP_MTU_DISCOVER:
1545 case IP_RECVERR:
1546 case IP_RECVTOS:
1547#ifdef IP_FREEBIND
1548 case IP_FREEBIND:
1549#endif
1550 case IP_MULTICAST_TTL:
1551 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001552 val = 0;
1553 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001554 if (get_user_u32(val, optval_addr))
1555 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001556 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001557 if (get_user_u8(val, optval_addr))
1558 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001559 }
1560 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1561 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001562 case IP_ADD_MEMBERSHIP:
1563 case IP_DROP_MEMBERSHIP:
1564 if (optlen < sizeof (struct target_ip_mreq) ||
1565 optlen > sizeof (struct target_ip_mreqn))
1566 return -TARGET_EINVAL;
1567
1568 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1569 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1570 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1571 break;
1572
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001573 case IP_BLOCK_SOURCE:
1574 case IP_UNBLOCK_SOURCE:
1575 case IP_ADD_SOURCE_MEMBERSHIP:
1576 case IP_DROP_SOURCE_MEMBERSHIP:
1577 if (optlen != sizeof (struct target_ip_mreq_source))
1578 return -TARGET_EINVAL;
1579
1580 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1581 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1582 unlock_user (ip_mreq_source, optval_addr, 0);
1583 break;
1584
bellard8853f862004-02-22 14:57:26 +00001585 default:
1586 goto unimplemented;
1587 }
1588 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001589 case SOL_IPV6:
1590 switch (optname) {
1591 case IPV6_MTU_DISCOVER:
1592 case IPV6_MTU:
1593 case IPV6_V6ONLY:
1594 case IPV6_RECVPKTINFO:
1595 val = 0;
1596 if (optlen < sizeof(uint32_t)) {
1597 return -TARGET_EINVAL;
1598 }
1599 if (get_user_u32(val, optval_addr)) {
1600 return -TARGET_EFAULT;
1601 }
1602 ret = get_errno(setsockopt(sockfd, level, optname,
1603 &val, sizeof(val)));
1604 break;
1605 default:
1606 goto unimplemented;
1607 }
1608 break;
Jing Huang920394d2012-07-24 13:59:23 +00001609 case SOL_RAW:
1610 switch (optname) {
1611 case ICMP_FILTER:
1612 /* struct icmp_filter takes an u32 value */
1613 if (optlen < sizeof(uint32_t)) {
1614 return -TARGET_EINVAL;
1615 }
1616
1617 if (get_user_u32(val, optval_addr)) {
1618 return -TARGET_EFAULT;
1619 }
1620 ret = get_errno(setsockopt(sockfd, level, optname,
1621 &val, sizeof(val)));
1622 break;
1623
1624 default:
1625 goto unimplemented;
1626 }
1627 break;
bellard3532fa72006-06-24 15:06:03 +00001628 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001629 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001630 case TARGET_SO_RCVTIMEO:
1631 {
1632 struct timeval tv;
1633
1634 optname = SO_RCVTIMEO;
1635
1636set_timeout:
1637 if (optlen != sizeof(struct target_timeval)) {
1638 return -TARGET_EINVAL;
1639 }
1640
1641 if (copy_from_user_timeval(&tv, optval_addr)) {
1642 return -TARGET_EFAULT;
1643 }
1644
1645 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1646 &tv, sizeof(tv)));
1647 return ret;
1648 }
1649 case TARGET_SO_SNDTIMEO:
1650 optname = SO_SNDTIMEO;
1651 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001652 case TARGET_SO_ATTACH_FILTER:
1653 {
1654 struct target_sock_fprog *tfprog;
1655 struct target_sock_filter *tfilter;
1656 struct sock_fprog fprog;
1657 struct sock_filter *filter;
1658 int i;
1659
1660 if (optlen != sizeof(*tfprog)) {
1661 return -TARGET_EINVAL;
1662 }
1663 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1664 return -TARGET_EFAULT;
1665 }
1666 if (!lock_user_struct(VERIFY_READ, tfilter,
1667 tswapal(tfprog->filter), 0)) {
1668 unlock_user_struct(tfprog, optval_addr, 1);
1669 return -TARGET_EFAULT;
1670 }
1671
1672 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301673 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001674 if (filter == NULL) {
1675 unlock_user_struct(tfilter, tfprog->filter, 1);
1676 unlock_user_struct(tfprog, optval_addr, 1);
1677 return -TARGET_ENOMEM;
1678 }
1679 for (i = 0; i < fprog.len; i++) {
1680 filter[i].code = tswap16(tfilter[i].code);
1681 filter[i].jt = tfilter[i].jt;
1682 filter[i].jf = tfilter[i].jf;
1683 filter[i].k = tswap32(tfilter[i].k);
1684 }
1685 fprog.filter = filter;
1686
1687 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1688 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301689 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001690
1691 unlock_user_struct(tfilter, tfprog->filter, 1);
1692 unlock_user_struct(tfprog, optval_addr, 1);
1693 return ret;
1694 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001695 case TARGET_SO_BINDTODEVICE:
1696 {
1697 char *dev_ifname, *addr_ifname;
1698
1699 if (optlen > IFNAMSIZ - 1) {
1700 optlen = IFNAMSIZ - 1;
1701 }
1702 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1703 if (!dev_ifname) {
1704 return -TARGET_EFAULT;
1705 }
1706 optname = SO_BINDTODEVICE;
1707 addr_ifname = alloca(IFNAMSIZ);
1708 memcpy(addr_ifname, dev_ifname, optlen);
1709 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08001710 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1711 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001712 unlock_user (dev_ifname, optval_addr, 0);
1713 return ret;
1714 }
bellard8853f862004-02-22 14:57:26 +00001715 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001716 case TARGET_SO_DEBUG:
1717 optname = SO_DEBUG;
1718 break;
1719 case TARGET_SO_REUSEADDR:
1720 optname = SO_REUSEADDR;
1721 break;
1722 case TARGET_SO_TYPE:
1723 optname = SO_TYPE;
1724 break;
1725 case TARGET_SO_ERROR:
1726 optname = SO_ERROR;
1727 break;
1728 case TARGET_SO_DONTROUTE:
1729 optname = SO_DONTROUTE;
1730 break;
1731 case TARGET_SO_BROADCAST:
1732 optname = SO_BROADCAST;
1733 break;
1734 case TARGET_SO_SNDBUF:
1735 optname = SO_SNDBUF;
1736 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001737 case TARGET_SO_SNDBUFFORCE:
1738 optname = SO_SNDBUFFORCE;
1739 break;
bellard3532fa72006-06-24 15:06:03 +00001740 case TARGET_SO_RCVBUF:
1741 optname = SO_RCVBUF;
1742 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001743 case TARGET_SO_RCVBUFFORCE:
1744 optname = SO_RCVBUFFORCE;
1745 break;
bellard3532fa72006-06-24 15:06:03 +00001746 case TARGET_SO_KEEPALIVE:
1747 optname = SO_KEEPALIVE;
1748 break;
1749 case TARGET_SO_OOBINLINE:
1750 optname = SO_OOBINLINE;
1751 break;
1752 case TARGET_SO_NO_CHECK:
1753 optname = SO_NO_CHECK;
1754 break;
1755 case TARGET_SO_PRIORITY:
1756 optname = SO_PRIORITY;
1757 break;
bellard5e83e8e2005-03-01 22:32:06 +00001758#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001759 case TARGET_SO_BSDCOMPAT:
1760 optname = SO_BSDCOMPAT;
1761 break;
bellard5e83e8e2005-03-01 22:32:06 +00001762#endif
bellard3532fa72006-06-24 15:06:03 +00001763 case TARGET_SO_PASSCRED:
1764 optname = SO_PASSCRED;
1765 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001766 case TARGET_SO_PASSSEC:
1767 optname = SO_PASSSEC;
1768 break;
bellard3532fa72006-06-24 15:06:03 +00001769 case TARGET_SO_TIMESTAMP:
1770 optname = SO_TIMESTAMP;
1771 break;
1772 case TARGET_SO_RCVLOWAT:
1773 optname = SO_RCVLOWAT;
1774 break;
bellard8853f862004-02-22 14:57:26 +00001775 break;
1776 default:
1777 goto unimplemented;
1778 }
bellard3532fa72006-06-24 15:06:03 +00001779 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001780 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001781
bellard2f619692007-11-16 10:46:05 +00001782 if (get_user_u32(val, optval_addr))
1783 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001784 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001785 break;
bellard7854b052003-03-29 17:22:23 +00001786 default:
bellard8853f862004-02-22 14:57:26 +00001787 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001788 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001789 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001790 }
bellard8853f862004-02-22 14:57:26 +00001791 return ret;
bellard7854b052003-03-29 17:22:23 +00001792}
1793
ths0da46a62007-10-20 20:23:07 +00001794/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001795static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001796 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001797{
blueswir1992f48a2007-10-14 16:27:31 +00001798 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001799 int len, val;
1800 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001801
1802 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001803 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001804 level = SOL_SOCKET;
1805 switch (optname) {
1806 /* These don't just return a single integer */
1807 case TARGET_SO_LINGER:
1808 case TARGET_SO_RCVTIMEO:
1809 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001810 case TARGET_SO_PEERNAME:
1811 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001812 case TARGET_SO_PEERCRED: {
1813 struct ucred cr;
1814 socklen_t crlen;
1815 struct target_ucred *tcr;
1816
1817 if (get_user_u32(len, optlen)) {
1818 return -TARGET_EFAULT;
1819 }
1820 if (len < 0) {
1821 return -TARGET_EINVAL;
1822 }
1823
1824 crlen = sizeof(cr);
1825 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1826 &cr, &crlen));
1827 if (ret < 0) {
1828 return ret;
1829 }
1830 if (len > crlen) {
1831 len = crlen;
1832 }
1833 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1834 return -TARGET_EFAULT;
1835 }
1836 __put_user(cr.pid, &tcr->pid);
1837 __put_user(cr.uid, &tcr->uid);
1838 __put_user(cr.gid, &tcr->gid);
1839 unlock_user_struct(tcr, optval_addr, 1);
1840 if (put_user_u32(len, optlen)) {
1841 return -TARGET_EFAULT;
1842 }
1843 break;
1844 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001845 /* Options with 'int' argument. */
1846 case TARGET_SO_DEBUG:
1847 optname = SO_DEBUG;
1848 goto int_case;
1849 case TARGET_SO_REUSEADDR:
1850 optname = SO_REUSEADDR;
1851 goto int_case;
1852 case TARGET_SO_TYPE:
1853 optname = SO_TYPE;
1854 goto int_case;
1855 case TARGET_SO_ERROR:
1856 optname = SO_ERROR;
1857 goto int_case;
1858 case TARGET_SO_DONTROUTE:
1859 optname = SO_DONTROUTE;
1860 goto int_case;
1861 case TARGET_SO_BROADCAST:
1862 optname = SO_BROADCAST;
1863 goto int_case;
1864 case TARGET_SO_SNDBUF:
1865 optname = SO_SNDBUF;
1866 goto int_case;
1867 case TARGET_SO_RCVBUF:
1868 optname = SO_RCVBUF;
1869 goto int_case;
1870 case TARGET_SO_KEEPALIVE:
1871 optname = SO_KEEPALIVE;
1872 goto int_case;
1873 case TARGET_SO_OOBINLINE:
1874 optname = SO_OOBINLINE;
1875 goto int_case;
1876 case TARGET_SO_NO_CHECK:
1877 optname = SO_NO_CHECK;
1878 goto int_case;
1879 case TARGET_SO_PRIORITY:
1880 optname = SO_PRIORITY;
1881 goto int_case;
1882#ifdef SO_BSDCOMPAT
1883 case TARGET_SO_BSDCOMPAT:
1884 optname = SO_BSDCOMPAT;
1885 goto int_case;
1886#endif
1887 case TARGET_SO_PASSCRED:
1888 optname = SO_PASSCRED;
1889 goto int_case;
1890 case TARGET_SO_TIMESTAMP:
1891 optname = SO_TIMESTAMP;
1892 goto int_case;
1893 case TARGET_SO_RCVLOWAT:
1894 optname = SO_RCVLOWAT;
1895 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001896 case TARGET_SO_ACCEPTCONN:
1897 optname = SO_ACCEPTCONN;
1898 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001899 default:
bellard2efbe912005-07-23 15:10:20 +00001900 goto int_case;
1901 }
1902 break;
1903 case SOL_TCP:
1904 /* TCP options all take an 'int' value. */
1905 int_case:
bellard2f619692007-11-16 10:46:05 +00001906 if (get_user_u32(len, optlen))
1907 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001908 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001909 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001910 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001911 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1912 if (ret < 0)
1913 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001914 if (optname == SO_TYPE) {
1915 val = host_to_target_sock_type(val);
1916 }
bellard2efbe912005-07-23 15:10:20 +00001917 if (len > lv)
1918 len = lv;
bellard2f619692007-11-16 10:46:05 +00001919 if (len == 4) {
1920 if (put_user_u32(val, optval_addr))
1921 return -TARGET_EFAULT;
1922 } else {
1923 if (put_user_u8(val, optval_addr))
1924 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001925 }
bellard2f619692007-11-16 10:46:05 +00001926 if (put_user_u32(len, optlen))
1927 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001928 break;
1929 case SOL_IP:
1930 switch(optname) {
1931 case IP_TOS:
1932 case IP_TTL:
1933 case IP_HDRINCL:
1934 case IP_ROUTER_ALERT:
1935 case IP_RECVOPTS:
1936 case IP_RETOPTS:
1937 case IP_PKTINFO:
1938 case IP_MTU_DISCOVER:
1939 case IP_RECVERR:
1940 case IP_RECVTOS:
1941#ifdef IP_FREEBIND
1942 case IP_FREEBIND:
1943#endif
1944 case IP_MULTICAST_TTL:
1945 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001946 if (get_user_u32(len, optlen))
1947 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001948 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001949 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001950 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001951 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1952 if (ret < 0)
1953 return ret;
bellard2efbe912005-07-23 15:10:20 +00001954 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001955 len = 1;
bellard2f619692007-11-16 10:46:05 +00001956 if (put_user_u32(len, optlen)
1957 || put_user_u8(val, optval_addr))
1958 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001959 } else {
bellard2efbe912005-07-23 15:10:20 +00001960 if (len > sizeof(int))
1961 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001962 if (put_user_u32(len, optlen)
1963 || put_user_u32(val, optval_addr))
1964 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001965 }
bellard8853f862004-02-22 14:57:26 +00001966 break;
bellard2efbe912005-07-23 15:10:20 +00001967 default:
thsc02f4992007-12-18 02:39:59 +00001968 ret = -TARGET_ENOPROTOOPT;
1969 break;
bellard8853f862004-02-22 14:57:26 +00001970 }
1971 break;
1972 default:
1973 unimplemented:
1974 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1975 level, optname);
thsc02f4992007-12-18 02:39:59 +00001976 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001977 break;
1978 }
1979 return ret;
bellard7854b052003-03-29 17:22:23 +00001980}
1981
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001982static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1983 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001984{
1985 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001986 struct iovec *vec;
1987 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001988 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001989 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001990 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001991
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001992 if (count == 0) {
1993 errno = 0;
1994 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001995 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001996 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001997 errno = EINVAL;
1998 return NULL;
1999 }
2000
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302001 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002002 if (vec == NULL) {
2003 errno = ENOMEM;
2004 return NULL;
2005 }
2006
2007 target_vec = lock_user(VERIFY_READ, target_addr,
2008 count * sizeof(struct target_iovec), 1);
2009 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002010 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002011 goto fail2;
2012 }
2013
2014 /* ??? If host page size > target page size, this will result in a
2015 value larger than what we can actually support. */
2016 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2017 total_len = 0;
2018
2019 for (i = 0; i < count; i++) {
2020 abi_ulong base = tswapal(target_vec[i].iov_base);
2021 abi_long len = tswapal(target_vec[i].iov_len);
2022
2023 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002024 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002025 goto fail;
2026 } else if (len == 0) {
2027 /* Zero length pointer is ignored. */
2028 vec[i].iov_base = 0;
2029 } else {
2030 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002031 /* If the first buffer pointer is bad, this is a fault. But
2032 * subsequent bad buffers will result in a partial write; this
2033 * is realized by filling the vector with null pointers and
2034 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002035 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002036 if (i == 0) {
2037 err = EFAULT;
2038 goto fail;
2039 } else {
2040 bad_address = true;
2041 }
2042 }
2043 if (bad_address) {
2044 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002045 }
2046 if (len > max_len - total_len) {
2047 len = max_len - total_len;
2048 }
2049 }
2050 vec[i].iov_len = len;
2051 total_len += len;
2052 }
2053
2054 unlock_user(target_vec, target_addr, 0);
2055 return vec;
2056
2057 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002058 while (--i >= 0) {
2059 if (tswapal(target_vec[i].iov_len) > 0) {
2060 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2061 }
2062 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002063 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002064 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302065 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002066 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002067 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002068}
2069
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002070static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2071 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002072{
2073 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002074 int i;
2075
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002076 target_vec = lock_user(VERIFY_READ, target_addr,
2077 count * sizeof(struct target_iovec), 1);
2078 if (target_vec) {
2079 for (i = 0; i < count; i++) {
2080 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002081 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002082 if (len < 0) {
2083 break;
2084 }
balrogd732dcb2008-10-28 10:21:03 +00002085 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2086 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002087 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002088 }
bellard579a97f2007-11-11 14:26:47 +00002089
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302090 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002091}
2092
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002093static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002094{
2095 int host_type = 0;
2096 int target_type = *type;
2097
2098 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2099 case TARGET_SOCK_DGRAM:
2100 host_type = SOCK_DGRAM;
2101 break;
2102 case TARGET_SOCK_STREAM:
2103 host_type = SOCK_STREAM;
2104 break;
2105 default:
2106 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2107 break;
2108 }
2109 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002110#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002111 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002112#else
2113 return -TARGET_EINVAL;
2114#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002115 }
2116 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002117#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002118 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002119#elif !defined(O_NONBLOCK)
2120 return -TARGET_EINVAL;
2121#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002122 }
2123 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002124 return 0;
2125}
2126
2127/* Try to emulate socket type flags after socket creation. */
2128static int sock_flags_fixup(int fd, int target_type)
2129{
2130#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2131 if (target_type & TARGET_SOCK_NONBLOCK) {
2132 int flags = fcntl(fd, F_GETFL);
2133 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2134 close(fd);
2135 return -TARGET_EINVAL;
2136 }
2137 }
2138#endif
2139 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002140}
2141
Laurent Vivier0cf22722015-10-28 21:40:45 +01002142static abi_long packet_target_to_host_sockaddr(void *host_addr,
2143 abi_ulong target_addr,
2144 socklen_t len)
2145{
2146 struct sockaddr *addr = host_addr;
2147 struct target_sockaddr *target_saddr;
2148
2149 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2150 if (!target_saddr) {
2151 return -TARGET_EFAULT;
2152 }
2153
2154 memcpy(addr, target_saddr, len);
2155 addr->sa_family = tswap16(target_saddr->sa_family);
2156 /* spkt_protocol is big-endian */
2157
2158 unlock_user(target_saddr, target_addr, 0);
2159 return 0;
2160}
2161
2162static TargetFdTrans target_packet_trans = {
2163 .target_to_host_addr = packet_target_to_host_sockaddr,
2164};
2165
ths0da46a62007-10-20 20:23:07 +00002166/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002167static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002168{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002169 int target_type = type;
2170 int ret;
2171
2172 ret = target_to_host_sock_type(&type);
2173 if (ret) {
2174 return ret;
2175 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002176
balrog12bc92a2007-10-30 21:06:14 +00002177 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07002178 return -TARGET_EAFNOSUPPORT;
Laurent Vivierff626f22015-10-28 21:40:42 +01002179
2180 if (domain == AF_PACKET ||
2181 (domain == AF_INET && type == SOCK_PACKET)) {
2182 protocol = tswap16(protocol);
2183 }
2184
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002185 ret = get_errno(socket(domain, type, protocol));
2186 if (ret >= 0) {
2187 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002188 if (type == SOCK_PACKET) {
2189 /* Manage an obsolete case :
2190 * if socket type is SOCK_PACKET, bind by name
2191 */
2192 fd_trans_register(ret, &target_packet_trans);
2193 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002194 }
2195 return ret;
bellard3532fa72006-06-24 15:06:03 +00002196}
2197
ths0da46a62007-10-20 20:23:07 +00002198/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002199static abi_long do_bind(int sockfd, abi_ulong target_addr,
2200 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002201{
aurel328f7aeaf2009-01-30 19:47:57 +00002202 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002203 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002204
Blue Swirl38724252010-09-18 05:53:14 +00002205 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002206 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002207 }
aurel328f7aeaf2009-01-30 19:47:57 +00002208
aurel32607175e2009-04-15 16:11:59 +00002209 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002210
Laurent Vivier7b36f782015-10-28 21:40:44 +01002211 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002212 if (ret)
2213 return ret;
2214
bellard3532fa72006-06-24 15:06:03 +00002215 return get_errno(bind(sockfd, addr, addrlen));
2216}
2217
ths0da46a62007-10-20 20:23:07 +00002218/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002219static abi_long do_connect(int sockfd, abi_ulong target_addr,
2220 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002221{
aurel328f7aeaf2009-01-30 19:47:57 +00002222 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002223 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002224
Blue Swirl38724252010-09-18 05:53:14 +00002225 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002226 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002227 }
aurel328f7aeaf2009-01-30 19:47:57 +00002228
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002229 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002230
Laurent Vivier7b36f782015-10-28 21:40:44 +01002231 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002232 if (ret)
2233 return ret;
2234
bellard3532fa72006-06-24 15:06:03 +00002235 return get_errno(connect(sockfd, addr, addrlen));
2236}
2237
Alexander Graff19e00d2014-03-02 19:36:42 +00002238/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2239static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2240 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002241{
balrog6de645c2008-10-28 10:26:29 +00002242 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002243 struct msghdr msg;
2244 int count;
2245 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002246 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002247
bellard3532fa72006-06-24 15:06:03 +00002248 if (msgp->msg_name) {
2249 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002250 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002251 ret = target_to_host_sockaddr(fd, msg.msg_name,
2252 tswapal(msgp->msg_name),
2253 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002254 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002255 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002256 }
bellard3532fa72006-06-24 15:06:03 +00002257 } else {
2258 msg.msg_name = NULL;
2259 msg.msg_namelen = 0;
2260 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002261 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002262 msg.msg_control = alloca(msg.msg_controllen);
2263 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002264
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002265 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002266 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002267 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2268 target_vec, count, send);
2269 if (vec == NULL) {
2270 ret = -host_to_target_errno(errno);
2271 goto out2;
2272 }
bellard3532fa72006-06-24 15:06:03 +00002273 msg.msg_iovlen = count;
2274 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002275
bellard3532fa72006-06-24 15:06:03 +00002276 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002277 ret = target_to_host_cmsg(&msg, msgp);
2278 if (ret == 0)
2279 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002280 } else {
2281 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002282 if (!is_error(ret)) {
2283 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002284 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002285 if (!is_error(ret)) {
2286 msgp->msg_namelen = tswap32(msg.msg_namelen);
2287 if (msg.msg_name != NULL) {
2288 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2289 msg.msg_name, msg.msg_namelen);
2290 if (ret) {
2291 goto out;
2292 }
2293 }
2294
balrog6de645c2008-10-28 10:26:29 +00002295 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002296 }
balrog6de645c2008-10-28 10:26:29 +00002297 }
bellard3532fa72006-06-24 15:06:03 +00002298 }
Jing Huangca619062012-07-24 13:58:02 +00002299
2300out:
bellard3532fa72006-06-24 15:06:03 +00002301 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002302out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002303 return ret;
2304}
2305
2306static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2307 int flags, int send)
2308{
2309 abi_long ret;
2310 struct target_msghdr *msgp;
2311
2312 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2313 msgp,
2314 target_msg,
2315 send ? 1 : 0)) {
2316 return -TARGET_EFAULT;
2317 }
2318 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002319 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002320 return ret;
2321}
2322
Alexander Graff19e00d2014-03-02 19:36:42 +00002323/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2324 * so it might not have this *mmsg-specific flag either.
2325 */
2326#ifndef MSG_WAITFORONE
2327#define MSG_WAITFORONE 0x10000
2328#endif
2329
2330static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2331 unsigned int vlen, unsigned int flags,
2332 int send)
2333{
2334 struct target_mmsghdr *mmsgp;
2335 abi_long ret = 0;
2336 int i;
2337
2338 if (vlen > UIO_MAXIOV) {
2339 vlen = UIO_MAXIOV;
2340 }
2341
2342 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2343 if (!mmsgp) {
2344 return -TARGET_EFAULT;
2345 }
2346
2347 for (i = 0; i < vlen; i++) {
2348 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2349 if (is_error(ret)) {
2350 break;
2351 }
2352 mmsgp[i].msg_len = tswap32(ret);
2353 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2354 if (flags & MSG_WAITFORONE) {
2355 flags |= MSG_DONTWAIT;
2356 }
2357 }
2358
2359 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2360
2361 /* Return number of datagrams sent if we sent any at all;
2362 * otherwise return the error.
2363 */
2364 if (i) {
2365 return i;
2366 }
2367 return ret;
2368}
Alexander Graff19e00d2014-03-02 19:36:42 +00002369
Peter Maydella94b4982013-02-08 04:35:04 +00002370/* If we don't have a system accept4() then just call accept.
2371 * The callsites to do_accept4() will ensure that they don't
2372 * pass a non-zero flags argument in this config.
2373 */
2374#ifndef CONFIG_ACCEPT4
2375static inline int accept4(int sockfd, struct sockaddr *addr,
2376 socklen_t *addrlen, int flags)
2377{
2378 assert(flags == 0);
2379 return accept(sockfd, addr, addrlen);
2380}
2381#endif
2382
2383/* do_accept4() Must return target values and target errnos. */
2384static abi_long do_accept4(int fd, abi_ulong target_addr,
2385 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002386{
bellard2f619692007-11-16 10:46:05 +00002387 socklen_t addrlen;
2388 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002389 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002390 int host_flags;
2391
2392 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002393
Peter Maydella94b4982013-02-08 04:35:04 +00002394 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002395 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002396 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002397
2398 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002399 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002400 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002401
Blue Swirl38724252010-09-18 05:53:14 +00002402 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002403 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002404 }
aurel328f7aeaf2009-01-30 19:47:57 +00002405
Arnaud Patard917507b2009-06-19 10:44:45 +03002406 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2407 return -TARGET_EINVAL;
2408
bellard2f619692007-11-16 10:46:05 +00002409 addr = alloca(addrlen);
2410
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002411 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002412 if (!is_error(ret)) {
2413 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002414 if (put_user_u32(addrlen, target_addrlen_addr))
2415 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002416 }
2417 return ret;
2418}
2419
ths0da46a62007-10-20 20:23:07 +00002420/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002421static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002422 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002423{
bellard2f619692007-11-16 10:46:05 +00002424 socklen_t addrlen;
2425 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002426 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002427
bellard2f619692007-11-16 10:46:05 +00002428 if (get_user_u32(addrlen, target_addrlen_addr))
2429 return -TARGET_EFAULT;
2430
Blue Swirl38724252010-09-18 05:53:14 +00002431 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002432 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002433 }
aurel328f7aeaf2009-01-30 19:47:57 +00002434
Arnaud Patard917507b2009-06-19 10:44:45 +03002435 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2436 return -TARGET_EFAULT;
2437
bellard2f619692007-11-16 10:46:05 +00002438 addr = alloca(addrlen);
2439
pbrook1be9e1d2006-11-19 15:26:04 +00002440 ret = get_errno(getpeername(fd, addr, &addrlen));
2441 if (!is_error(ret)) {
2442 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002443 if (put_user_u32(addrlen, target_addrlen_addr))
2444 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002445 }
2446 return ret;
2447}
2448
ths0da46a62007-10-20 20:23:07 +00002449/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002450static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002451 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002452{
bellard2f619692007-11-16 10:46:05 +00002453 socklen_t addrlen;
2454 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002455 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002456
bellard2f619692007-11-16 10:46:05 +00002457 if (get_user_u32(addrlen, target_addrlen_addr))
2458 return -TARGET_EFAULT;
2459
Blue Swirl38724252010-09-18 05:53:14 +00002460 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002461 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002462 }
aurel328f7aeaf2009-01-30 19:47:57 +00002463
Arnaud Patard917507b2009-06-19 10:44:45 +03002464 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2465 return -TARGET_EFAULT;
2466
bellard2f619692007-11-16 10:46:05 +00002467 addr = alloca(addrlen);
2468
pbrook1be9e1d2006-11-19 15:26:04 +00002469 ret = get_errno(getsockname(fd, addr, &addrlen));
2470 if (!is_error(ret)) {
2471 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002472 if (put_user_u32(addrlen, target_addrlen_addr))
2473 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002474 }
2475 return ret;
2476}
2477
ths0da46a62007-10-20 20:23:07 +00002478/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002479static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002480 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002481{
2482 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002483 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002484
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002485 target_to_host_sock_type(&type);
2486
pbrook1be9e1d2006-11-19 15:26:04 +00002487 ret = get_errno(socketpair(domain, type, protocol, tab));
2488 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002489 if (put_user_s32(tab[0], target_tab_addr)
2490 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2491 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002492 }
2493 return ret;
2494}
2495
ths0da46a62007-10-20 20:23:07 +00002496/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002497static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2498 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002499{
2500 void *addr;
2501 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002502 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002503
Blue Swirl38724252010-09-18 05:53:14 +00002504 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002505 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002506 }
aurel328f7aeaf2009-01-30 19:47:57 +00002507
bellard579a97f2007-11-11 14:26:47 +00002508 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2509 if (!host_msg)
2510 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002511 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002512 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002513 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002514 if (ret) {
2515 unlock_user(host_msg, msg, 0);
2516 return ret;
2517 }
pbrook1be9e1d2006-11-19 15:26:04 +00002518 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2519 } else {
2520 ret = get_errno(send(fd, host_msg, len, flags));
2521 }
2522 unlock_user(host_msg, msg, 0);
2523 return ret;
2524}
2525
ths0da46a62007-10-20 20:23:07 +00002526/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002527static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2528 abi_ulong target_addr,
2529 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002530{
2531 socklen_t addrlen;
2532 void *addr;
2533 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002534 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002535
bellard579a97f2007-11-11 14:26:47 +00002536 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2537 if (!host_msg)
2538 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002539 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002540 if (get_user_u32(addrlen, target_addrlen)) {
2541 ret = -TARGET_EFAULT;
2542 goto fail;
2543 }
Blue Swirl38724252010-09-18 05:53:14 +00002544 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002545 ret = -TARGET_EINVAL;
2546 goto fail;
2547 }
pbrook1be9e1d2006-11-19 15:26:04 +00002548 addr = alloca(addrlen);
2549 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2550 } else {
2551 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002552 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002553 }
2554 if (!is_error(ret)) {
2555 if (target_addr) {
2556 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002557 if (put_user_u32(addrlen, target_addrlen)) {
2558 ret = -TARGET_EFAULT;
2559 goto fail;
2560 }
pbrook1be9e1d2006-11-19 15:26:04 +00002561 }
2562 unlock_user(host_msg, msg, len);
2563 } else {
bellard2f619692007-11-16 10:46:05 +00002564fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002565 unlock_user(host_msg, msg, 0);
2566 }
2567 return ret;
2568}
2569
j_mayer32407102007-09-26 23:01:49 +00002570#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002571/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002572static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002573{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002574 static const unsigned ac[] = { /* number of arguments per call */
2575 [SOCKOP_socket] = 3, /* domain, type, protocol */
2576 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2577 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2578 [SOCKOP_listen] = 2, /* sockfd, backlog */
2579 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2580 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2581 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2582 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2583 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2584 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2585 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2586 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2587 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2588 [SOCKOP_shutdown] = 2, /* sockfd, how */
2589 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2590 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002591 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
2592 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002593 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2594 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2595 };
2596 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002597
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002598 /* first, collect the arguments in a[] according to ac[] */
2599 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2600 unsigned i;
2601 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2602 for (i = 0; i < ac[num]; ++i) {
2603 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002604 return -TARGET_EFAULT;
2605 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002606 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002607 }
bellard2f619692007-11-16 10:46:05 +00002608
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002609 /* now when we have the args, actually handle the call */
2610 switch (num) {
2611 case SOCKOP_socket: /* domain, type, protocol */
2612 return do_socket(a[0], a[1], a[2]);
2613 case SOCKOP_bind: /* sockfd, addr, addrlen */
2614 return do_bind(a[0], a[1], a[2]);
2615 case SOCKOP_connect: /* sockfd, addr, addrlen */
2616 return do_connect(a[0], a[1], a[2]);
2617 case SOCKOP_listen: /* sockfd, backlog */
2618 return get_errno(listen(a[0], a[1]));
2619 case SOCKOP_accept: /* sockfd, addr, addrlen */
2620 return do_accept4(a[0], a[1], a[2], 0);
2621 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2622 return do_accept4(a[0], a[1], a[2], a[3]);
2623 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2624 return do_getsockname(a[0], a[1], a[2]);
2625 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2626 return do_getpeername(a[0], a[1], a[2]);
2627 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2628 return do_socketpair(a[0], a[1], a[2], a[3]);
2629 case SOCKOP_send: /* sockfd, msg, len, flags */
2630 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2631 case SOCKOP_recv: /* sockfd, msg, len, flags */
2632 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2633 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2634 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2635 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2636 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2637 case SOCKOP_shutdown: /* sockfd, how */
2638 return get_errno(shutdown(a[0], a[1]));
2639 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2640 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2641 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2642 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002643 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
2644 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
2645 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
2646 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002647 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2648 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2649 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2650 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002651 default:
2652 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002653 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002654 }
bellard31e31b82003-02-18 22:55:36 +00002655}
j_mayer32407102007-09-26 23:01:49 +00002656#endif
bellard31e31b82003-02-18 22:55:36 +00002657
bellard8853f862004-02-22 14:57:26 +00002658#define N_SHM_REGIONS 32
2659
2660static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00002661 abi_ulong start;
2662 abi_ulong size;
2663 bool in_use;
bellard8853f862004-02-22 14:57:26 +00002664} shm_regions[N_SHM_REGIONS];
2665
ths3eb6b042007-06-03 14:26:27 +00002666struct target_semid_ds
2667{
2668 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002669 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002670#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002671 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002672#endif
blueswir1992f48a2007-10-14 16:27:31 +00002673 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002674#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002675 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002676#endif
blueswir1992f48a2007-10-14 16:27:31 +00002677 abi_ulong sem_nsems;
2678 abi_ulong __unused3;
2679 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002680};
2681
bellard579a97f2007-11-11 14:26:47 +00002682static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2683 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002684{
2685 struct target_ipc_perm *target_ip;
2686 struct target_semid_ds *target_sd;
2687
bellard579a97f2007-11-11 14:26:47 +00002688 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2689 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002690 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002691 host_ip->__key = tswap32(target_ip->__key);
2692 host_ip->uid = tswap32(target_ip->uid);
2693 host_ip->gid = tswap32(target_ip->gid);
2694 host_ip->cuid = tswap32(target_ip->cuid);
2695 host_ip->cgid = tswap32(target_ip->cgid);
2696#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2697 host_ip->mode = tswap32(target_ip->mode);
2698#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002699 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002700#endif
2701#if defined(TARGET_PPC)
2702 host_ip->__seq = tswap32(target_ip->__seq);
2703#else
2704 host_ip->__seq = tswap16(target_ip->__seq);
2705#endif
ths3eb6b042007-06-03 14:26:27 +00002706 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002707 return 0;
ths3eb6b042007-06-03 14:26:27 +00002708}
2709
bellard579a97f2007-11-11 14:26:47 +00002710static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2711 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002712{
2713 struct target_ipc_perm *target_ip;
2714 struct target_semid_ds *target_sd;
2715
bellard579a97f2007-11-11 14:26:47 +00002716 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2717 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002718 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002719 target_ip->__key = tswap32(host_ip->__key);
2720 target_ip->uid = tswap32(host_ip->uid);
2721 target_ip->gid = tswap32(host_ip->gid);
2722 target_ip->cuid = tswap32(host_ip->cuid);
2723 target_ip->cgid = tswap32(host_ip->cgid);
2724#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2725 target_ip->mode = tswap32(host_ip->mode);
2726#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002727 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002728#endif
2729#if defined(TARGET_PPC)
2730 target_ip->__seq = tswap32(host_ip->__seq);
2731#else
2732 target_ip->__seq = tswap16(host_ip->__seq);
2733#endif
ths3eb6b042007-06-03 14:26:27 +00002734 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002735 return 0;
ths3eb6b042007-06-03 14:26:27 +00002736}
2737
bellard579a97f2007-11-11 14:26:47 +00002738static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2739 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002740{
2741 struct target_semid_ds *target_sd;
2742
bellard579a97f2007-11-11 14:26:47 +00002743 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2744 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002745 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2746 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002747 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2748 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2749 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002750 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002751 return 0;
ths3eb6b042007-06-03 14:26:27 +00002752}
2753
bellard579a97f2007-11-11 14:26:47 +00002754static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2755 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002756{
2757 struct target_semid_ds *target_sd;
2758
bellard579a97f2007-11-11 14:26:47 +00002759 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2760 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002761 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002762 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002763 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2764 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2765 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002766 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002767 return 0;
ths3eb6b042007-06-03 14:26:27 +00002768}
2769
aurel32e5289082009-04-18 16:16:12 +00002770struct target_seminfo {
2771 int semmap;
2772 int semmni;
2773 int semmns;
2774 int semmnu;
2775 int semmsl;
2776 int semopm;
2777 int semume;
2778 int semusz;
2779 int semvmx;
2780 int semaem;
2781};
2782
2783static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2784 struct seminfo *host_seminfo)
2785{
2786 struct target_seminfo *target_seminfo;
2787 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2788 return -TARGET_EFAULT;
2789 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2790 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2791 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2792 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2793 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2794 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2795 __put_user(host_seminfo->semume, &target_seminfo->semume);
2796 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2797 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2798 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2799 unlock_user_struct(target_seminfo, target_addr, 1);
2800 return 0;
2801}
2802
thsfa294812007-02-02 22:05:00 +00002803union semun {
2804 int val;
ths3eb6b042007-06-03 14:26:27 +00002805 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002806 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002807 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002808};
2809
ths3eb6b042007-06-03 14:26:27 +00002810union target_semun {
2811 int val;
aurel32e5289082009-04-18 16:16:12 +00002812 abi_ulong buf;
2813 abi_ulong array;
2814 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002815};
2816
aurel32e5289082009-04-18 16:16:12 +00002817static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2818 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002819{
aurel32e5289082009-04-18 16:16:12 +00002820 int nsems;
2821 unsigned short *array;
2822 union semun semun;
2823 struct semid_ds semid_ds;
2824 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002825
aurel32e5289082009-04-18 16:16:12 +00002826 semun.buf = &semid_ds;
2827
2828 ret = semctl(semid, 0, IPC_STAT, semun);
2829 if (ret == -1)
2830 return get_errno(ret);
2831
2832 nsems = semid_ds.sem_nsems;
2833
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302834 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00002835 if (!*host_array) {
2836 return -TARGET_ENOMEM;
2837 }
aurel32e5289082009-04-18 16:16:12 +00002838 array = lock_user(VERIFY_READ, target_addr,
2839 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002840 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302841 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002842 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002843 }
aurel32e5289082009-04-18 16:16:12 +00002844
2845 for(i=0; i<nsems; i++) {
2846 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002847 }
aurel32e5289082009-04-18 16:16:12 +00002848 unlock_user(array, target_addr, 0);
2849
bellard579a97f2007-11-11 14:26:47 +00002850 return 0;
ths3eb6b042007-06-03 14:26:27 +00002851}
2852
aurel32e5289082009-04-18 16:16:12 +00002853static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2854 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002855{
aurel32e5289082009-04-18 16:16:12 +00002856 int nsems;
2857 unsigned short *array;
2858 union semun semun;
2859 struct semid_ds semid_ds;
2860 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002861
aurel32e5289082009-04-18 16:16:12 +00002862 semun.buf = &semid_ds;
2863
2864 ret = semctl(semid, 0, IPC_STAT, semun);
2865 if (ret == -1)
2866 return get_errno(ret);
2867
2868 nsems = semid_ds.sem_nsems;
2869
2870 array = lock_user(VERIFY_WRITE, target_addr,
2871 nsems*sizeof(unsigned short), 0);
2872 if (!array)
2873 return -TARGET_EFAULT;
2874
2875 for(i=0; i<nsems; i++) {
2876 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002877 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302878 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002879 unlock_user(array, target_addr, 1);
2880
bellard579a97f2007-11-11 14:26:47 +00002881 return 0;
ths3eb6b042007-06-03 14:26:27 +00002882}
2883
aurel32e5289082009-04-18 16:16:12 +00002884static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01002885 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00002886{
Stefan Weild1c002b2015-02-08 15:40:58 +01002887 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00002888 union semun arg;
2889 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302890 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002891 struct seminfo seminfo;
2892 abi_long ret = -TARGET_EINVAL;
2893 abi_long err;
2894 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002895
2896 switch( cmd ) {
2897 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002898 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002899 /* In 64 bit cross-endian situations, we will erroneously pick up
2900 * the wrong half of the union for the "val" element. To rectify
2901 * this, the entire 8-byte structure is byteswapped, followed by
2902 * a swap of the 4 byte val field. In other cases, the data is
2903 * already in proper host byte order. */
2904 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2905 target_su.buf = tswapal(target_su.buf);
2906 arg.val = tswap32(target_su.val);
2907 } else {
2908 arg.val = target_su.val;
2909 }
aurel32e5289082009-04-18 16:16:12 +00002910 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002911 break;
2912 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002913 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002914 err = target_to_host_semarray(semid, &array, target_su.array);
2915 if (err)
2916 return err;
2917 arg.array = array;
2918 ret = get_errno(semctl(semid, semnum, cmd, arg));
2919 err = host_to_target_semarray(semid, target_su.array, &array);
2920 if (err)
2921 return err;
ths3eb6b042007-06-03 14:26:27 +00002922 break;
2923 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002924 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002925 case SEM_STAT:
2926 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2927 if (err)
2928 return err;
2929 arg.buf = &dsarg;
2930 ret = get_errno(semctl(semid, semnum, cmd, arg));
2931 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2932 if (err)
2933 return err;
ths3eb6b042007-06-03 14:26:27 +00002934 break;
aurel32e5289082009-04-18 16:16:12 +00002935 case IPC_INFO:
2936 case SEM_INFO:
2937 arg.__buf = &seminfo;
2938 ret = get_errno(semctl(semid, semnum, cmd, arg));
2939 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2940 if (err)
2941 return err;
2942 break;
2943 case IPC_RMID:
2944 case GETPID:
2945 case GETNCNT:
2946 case GETZCNT:
2947 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2948 break;
ths3eb6b042007-06-03 14:26:27 +00002949 }
2950
2951 return ret;
2952}
2953
aurel32e5289082009-04-18 16:16:12 +00002954struct target_sembuf {
2955 unsigned short sem_num;
2956 short sem_op;
2957 short sem_flg;
2958};
2959
2960static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2961 abi_ulong target_addr,
2962 unsigned nsops)
2963{
2964 struct target_sembuf *target_sembuf;
2965 int i;
2966
2967 target_sembuf = lock_user(VERIFY_READ, target_addr,
2968 nsops*sizeof(struct target_sembuf), 1);
2969 if (!target_sembuf)
2970 return -TARGET_EFAULT;
2971
2972 for(i=0; i<nsops; i++) {
2973 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2974 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2975 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2976 }
2977
2978 unlock_user(target_sembuf, target_addr, 0);
2979
2980 return 0;
2981}
2982
2983static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2984{
2985 struct sembuf sops[nsops];
2986
2987 if (target_to_host_sembuf(sops, ptr, nsops))
2988 return -TARGET_EFAULT;
2989
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002990 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002991}
2992
ths1bc012f2007-06-03 14:27:49 +00002993struct target_msqid_ds
2994{
aurel321c54ff92008-10-13 21:08:44 +00002995 struct target_ipc_perm msg_perm;
2996 abi_ulong msg_stime;
2997#if TARGET_ABI_BITS == 32
2998 abi_ulong __unused1;
2999#endif
3000 abi_ulong msg_rtime;
3001#if TARGET_ABI_BITS == 32
3002 abi_ulong __unused2;
3003#endif
3004 abi_ulong msg_ctime;
3005#if TARGET_ABI_BITS == 32
3006 abi_ulong __unused3;
3007#endif
3008 abi_ulong __msg_cbytes;
3009 abi_ulong msg_qnum;
3010 abi_ulong msg_qbytes;
3011 abi_ulong msg_lspid;
3012 abi_ulong msg_lrpid;
3013 abi_ulong __unused4;
3014 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003015};
3016
bellard579a97f2007-11-11 14:26:47 +00003017static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3018 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003019{
3020 struct target_msqid_ds *target_md;
3021
bellard579a97f2007-11-11 14:26:47 +00003022 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3023 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003024 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3025 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003026 host_md->msg_stime = tswapal(target_md->msg_stime);
3027 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3028 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3029 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3030 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3031 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3032 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3033 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003034 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003035 return 0;
ths1bc012f2007-06-03 14:27:49 +00003036}
3037
bellard579a97f2007-11-11 14:26:47 +00003038static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3039 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003040{
3041 struct target_msqid_ds *target_md;
3042
bellard579a97f2007-11-11 14:26:47 +00003043 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3044 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003045 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3046 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003047 target_md->msg_stime = tswapal(host_md->msg_stime);
3048 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3049 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3050 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3051 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3052 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3053 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3054 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003055 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003056 return 0;
ths1bc012f2007-06-03 14:27:49 +00003057}
3058
aurel321c54ff92008-10-13 21:08:44 +00003059struct target_msginfo {
3060 int msgpool;
3061 int msgmap;
3062 int msgmax;
3063 int msgmnb;
3064 int msgmni;
3065 int msgssz;
3066 int msgtql;
3067 unsigned short int msgseg;
3068};
3069
3070static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3071 struct msginfo *host_msginfo)
3072{
3073 struct target_msginfo *target_msginfo;
3074 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3075 return -TARGET_EFAULT;
3076 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3077 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3078 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3079 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3080 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3081 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3082 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3083 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3084 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003085 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003086}
3087
3088static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003089{
3090 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003091 struct msginfo msginfo;
3092 abi_long ret = -TARGET_EINVAL;
3093
3094 cmd &= 0xff;
3095
3096 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003097 case IPC_STAT:
3098 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003099 case MSG_STAT:
3100 if (target_to_host_msqid_ds(&dsarg,ptr))
3101 return -TARGET_EFAULT;
3102 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3103 if (host_to_target_msqid_ds(ptr,&dsarg))
3104 return -TARGET_EFAULT;
3105 break;
3106 case IPC_RMID:
3107 ret = get_errno(msgctl(msgid, cmd, NULL));
3108 break;
3109 case IPC_INFO:
3110 case MSG_INFO:
3111 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3112 if (host_to_target_msginfo(ptr, &msginfo))
3113 return -TARGET_EFAULT;
3114 break;
ths1bc012f2007-06-03 14:27:49 +00003115 }
aurel321c54ff92008-10-13 21:08:44 +00003116
ths1bc012f2007-06-03 14:27:49 +00003117 return ret;
3118}
3119
3120struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003121 abi_long mtype;
3122 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003123};
3124
blueswir1992f48a2007-10-14 16:27:31 +00003125static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003126 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003127{
3128 struct target_msgbuf *target_mb;
3129 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003130 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003131
Tom Mustaedcc5f92014-08-12 13:53:37 -05003132 if (msgsz < 0) {
3133 return -TARGET_EINVAL;
3134 }
3135
bellard579a97f2007-11-11 14:26:47 +00003136 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3137 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303138 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003139 if (!host_mb) {
3140 unlock_user_struct(target_mb, msgp, 0);
3141 return -TARGET_ENOMEM;
3142 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003143 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003144 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00003145 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303146 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003147 unlock_user_struct(target_mb, msgp, 0);
3148
3149 return ret;
3150}
3151
blueswir1992f48a2007-10-14 16:27:31 +00003152static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00003153 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003154 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003155{
3156 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003157 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003158 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003159 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003160
bellard579a97f2007-11-11 14:26:47 +00003161 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3162 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003163
Jim Meyering0d07fe42012-08-22 13:55:53 +02003164 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003165 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003166
bellard579a97f2007-11-11 14:26:47 +00003167 if (ret > 0) {
3168 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3169 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3170 if (!target_mtext) {
3171 ret = -TARGET_EFAULT;
3172 goto end;
3173 }
aurel321c54ff92008-10-13 21:08:44 +00003174 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003175 unlock_user(target_mtext, target_mtext_addr, ret);
3176 }
aurel321c54ff92008-10-13 21:08:44 +00003177
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003178 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003179
bellard579a97f2007-11-11 14:26:47 +00003180end:
3181 if (target_mb)
3182 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003183 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003184 return ret;
3185}
3186
Riku Voipio88a8c982009-04-03 10:42:00 +03003187static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3188 abi_ulong target_addr)
3189{
3190 struct target_shmid_ds *target_sd;
3191
3192 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3193 return -TARGET_EFAULT;
3194 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3195 return -TARGET_EFAULT;
3196 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3197 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3198 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3199 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3200 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3201 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3202 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3203 unlock_user_struct(target_sd, target_addr, 0);
3204 return 0;
3205}
3206
3207static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3208 struct shmid_ds *host_sd)
3209{
3210 struct target_shmid_ds *target_sd;
3211
3212 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3213 return -TARGET_EFAULT;
3214 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3215 return -TARGET_EFAULT;
3216 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3217 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3218 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3219 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3220 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3221 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3222 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3223 unlock_user_struct(target_sd, target_addr, 1);
3224 return 0;
3225}
3226
3227struct target_shminfo {
3228 abi_ulong shmmax;
3229 abi_ulong shmmin;
3230 abi_ulong shmmni;
3231 abi_ulong shmseg;
3232 abi_ulong shmall;
3233};
3234
3235static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3236 struct shminfo *host_shminfo)
3237{
3238 struct target_shminfo *target_shminfo;
3239 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3240 return -TARGET_EFAULT;
3241 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3242 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3243 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3244 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3245 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3246 unlock_user_struct(target_shminfo, target_addr, 1);
3247 return 0;
3248}
3249
3250struct target_shm_info {
3251 int used_ids;
3252 abi_ulong shm_tot;
3253 abi_ulong shm_rss;
3254 abi_ulong shm_swp;
3255 abi_ulong swap_attempts;
3256 abi_ulong swap_successes;
3257};
3258
3259static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3260 struct shm_info *host_shm_info)
3261{
3262 struct target_shm_info *target_shm_info;
3263 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3264 return -TARGET_EFAULT;
3265 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3266 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3267 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3268 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3269 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3270 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3271 unlock_user_struct(target_shm_info, target_addr, 1);
3272 return 0;
3273}
3274
3275static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3276{
3277 struct shmid_ds dsarg;
3278 struct shminfo shminfo;
3279 struct shm_info shm_info;
3280 abi_long ret = -TARGET_EINVAL;
3281
3282 cmd &= 0xff;
3283
3284 switch(cmd) {
3285 case IPC_STAT:
3286 case IPC_SET:
3287 case SHM_STAT:
3288 if (target_to_host_shmid_ds(&dsarg, buf))
3289 return -TARGET_EFAULT;
3290 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3291 if (host_to_target_shmid_ds(buf, &dsarg))
3292 return -TARGET_EFAULT;
3293 break;
3294 case IPC_INFO:
3295 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3296 if (host_to_target_shminfo(buf, &shminfo))
3297 return -TARGET_EFAULT;
3298 break;
3299 case SHM_INFO:
3300 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3301 if (host_to_target_shm_info(buf, &shm_info))
3302 return -TARGET_EFAULT;
3303 break;
3304 case IPC_RMID:
3305 case SHM_LOCK:
3306 case SHM_UNLOCK:
3307 ret = get_errno(shmctl(shmid, cmd, NULL));
3308 break;
3309 }
3310
3311 return ret;
3312}
3313
3314static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3315{
3316 abi_long raddr;
3317 void *host_raddr;
3318 struct shmid_ds shm_info;
3319 int i,ret;
3320
3321 /* find out the length of the shared memory segment */
3322 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3323 if (is_error(ret)) {
3324 /* can't get length, bail out */
3325 return ret;
3326 }
3327
3328 mmap_lock();
3329
3330 if (shmaddr)
3331 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3332 else {
3333 abi_ulong mmap_start;
3334
3335 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3336
3337 if (mmap_start == -1) {
3338 errno = ENOMEM;
3339 host_raddr = (void *)-1;
3340 } else
3341 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3342 }
3343
3344 if (host_raddr == (void *)-1) {
3345 mmap_unlock();
3346 return get_errno((long)host_raddr);
3347 }
3348 raddr=h2g((unsigned long)host_raddr);
3349
3350 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3351 PAGE_VALID | PAGE_READ |
3352 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3353
3354 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003355 if (!shm_regions[i].in_use) {
3356 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03003357 shm_regions[i].start = raddr;
3358 shm_regions[i].size = shm_info.shm_segsz;
3359 break;
3360 }
3361 }
3362
3363 mmap_unlock();
3364 return raddr;
3365
3366}
3367
3368static inline abi_long do_shmdt(abi_ulong shmaddr)
3369{
3370 int i;
3371
3372 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003373 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
3374 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003375 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003376 break;
3377 }
3378 }
3379
3380 return get_errno(shmdt(g2h(shmaddr)));
3381}
3382
aurel321c54ff92008-10-13 21:08:44 +00003383#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003384/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003385/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003386static abi_long do_ipc(unsigned int call, abi_long first,
3387 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003388 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003389{
3390 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003391 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003392
3393 version = call >> 16;
3394 call &= 0xffff;
3395
3396 switch (call) {
thsfa294812007-02-02 22:05:00 +00003397 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003398 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003399 break;
3400
3401 case IPCOP_semget:
3402 ret = get_errno(semget(first, second, third));
3403 break;
3404
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003405 case IPCOP_semctl: {
3406 /* The semun argument to semctl is passed by value, so dereference the
3407 * ptr argument. */
3408 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003409 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01003410 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00003411 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003412 }
thsd96372e2007-02-02 22:05:44 +00003413
aurel321c54ff92008-10-13 21:08:44 +00003414 case IPCOP_msgget:
3415 ret = get_errno(msgget(first, second));
3416 break;
thsd96372e2007-02-02 22:05:44 +00003417
aurel321c54ff92008-10-13 21:08:44 +00003418 case IPCOP_msgsnd:
3419 ret = do_msgsnd(first, ptr, second, third);
3420 break;
thsd96372e2007-02-02 22:05:44 +00003421
aurel321c54ff92008-10-13 21:08:44 +00003422 case IPCOP_msgctl:
3423 ret = do_msgctl(first, second, ptr);
3424 break;
thsd96372e2007-02-02 22:05:44 +00003425
aurel321c54ff92008-10-13 21:08:44 +00003426 case IPCOP_msgrcv:
3427 switch (version) {
3428 case 0:
3429 {
3430 struct target_ipc_kludge {
3431 abi_long msgp;
3432 abi_long msgtyp;
3433 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003434
aurel321c54ff92008-10-13 21:08:44 +00003435 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3436 ret = -TARGET_EFAULT;
3437 break;
ths1bc012f2007-06-03 14:27:49 +00003438 }
aurel321c54ff92008-10-13 21:08:44 +00003439
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003440 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003441
3442 unlock_user_struct(tmp, ptr, 0);
3443 break;
3444 }
3445 default:
3446 ret = do_msgrcv(first, ptr, second, fifth, third);
3447 }
3448 break;
thsd96372e2007-02-02 22:05:44 +00003449
bellard8853f862004-02-22 14:57:26 +00003450 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003451 switch (version) {
3452 default:
bellard5a4a8982007-11-11 17:39:18 +00003453 {
3454 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003455 raddr = do_shmat(first, ptr, second);
3456 if (is_error(raddr))
3457 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003458 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003459 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003460 break;
3461 }
3462 case 1:
3463 ret = -TARGET_EINVAL;
3464 break;
bellard5a4a8982007-11-11 17:39:18 +00003465 }
bellard8853f862004-02-22 14:57:26 +00003466 break;
3467 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003468 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003469 break;
3470
3471 case IPCOP_shmget:
3472 /* IPC_* flag values are the same on all linux platforms */
3473 ret = get_errno(shmget(first, second, third));
3474 break;
3475
3476 /* IPC_* and SHM_* command values are the same on all linux platforms */
3477 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003478 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003479 break;
3480 default:
j_mayer32407102007-09-26 23:01:49 +00003481 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003482 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003483 break;
3484 }
3485 return ret;
3486}
j_mayer32407102007-09-26 23:01:49 +00003487#endif
bellard8853f862004-02-22 14:57:26 +00003488
bellard31e31b82003-02-18 22:55:36 +00003489/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003490
Blue Swirl001faf32009-05-13 17:53:17 +00003491#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003492#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3493enum {
3494#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02003495STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00003496};
3497#undef STRUCT
3498#undef STRUCT_SPECIAL
3499
Blue Swirl001faf32009-05-13 17:53:17 +00003500#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003501#define STRUCT_SPECIAL(name)
3502#include "syscall_types.h"
3503#undef STRUCT
3504#undef STRUCT_SPECIAL
3505
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003506typedef struct IOCTLEntry IOCTLEntry;
3507
3508typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003509 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003510
3511struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08003512 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00003513 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003514 const char *name;
3515 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003516 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003517 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003518};
bellard31e31b82003-02-18 22:55:36 +00003519
3520#define IOC_R 0x0001
3521#define IOC_W 0x0002
3522#define IOC_RW (IOC_R | IOC_W)
3523
3524#define MAX_STRUCT_SIZE 4096
3525
Peter Maydelldace20d2011-01-10 13:11:24 +00003526#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003527/* So fiemap access checks don't overflow on 32 bit systems.
3528 * This is very slightly smaller than the limit imposed by
3529 * the underlying kernel.
3530 */
3531#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3532 / sizeof(struct fiemap_extent))
3533
3534static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003535 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00003536{
3537 /* The parameter for this ioctl is a struct fiemap followed
3538 * by an array of struct fiemap_extent whose size is set
3539 * in fiemap->fm_extent_count. The array is filled in by the
3540 * ioctl.
3541 */
3542 int target_size_in, target_size_out;
3543 struct fiemap *fm;
3544 const argtype *arg_type = ie->arg_type;
3545 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3546 void *argptr, *p;
3547 abi_long ret;
3548 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3549 uint32_t outbufsz;
3550 int free_fm = 0;
3551
3552 assert(arg_type[0] == TYPE_PTR);
3553 assert(ie->access == IOC_RW);
3554 arg_type++;
3555 target_size_in = thunk_type_size(arg_type, 0);
3556 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3557 if (!argptr) {
3558 return -TARGET_EFAULT;
3559 }
3560 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3561 unlock_user(argptr, arg, 0);
3562 fm = (struct fiemap *)buf_temp;
3563 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3564 return -TARGET_EINVAL;
3565 }
3566
3567 outbufsz = sizeof (*fm) +
3568 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3569
3570 if (outbufsz > MAX_STRUCT_SIZE) {
3571 /* We can't fit all the extents into the fixed size buffer.
3572 * Allocate one that is large enough and use it instead.
3573 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303574 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00003575 if (!fm) {
3576 return -TARGET_ENOMEM;
3577 }
3578 memcpy(fm, buf_temp, sizeof(struct fiemap));
3579 free_fm = 1;
3580 }
3581 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3582 if (!is_error(ret)) {
3583 target_size_out = target_size_in;
3584 /* An extent_count of 0 means we were only counting the extents
3585 * so there are no structs to copy
3586 */
3587 if (fm->fm_extent_count != 0) {
3588 target_size_out += fm->fm_mapped_extents * extent_size;
3589 }
3590 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3591 if (!argptr) {
3592 ret = -TARGET_EFAULT;
3593 } else {
3594 /* Convert the struct fiemap */
3595 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3596 if (fm->fm_extent_count != 0) {
3597 p = argptr + target_size_in;
3598 /* ...and then all the struct fiemap_extents */
3599 for (i = 0; i < fm->fm_mapped_extents; i++) {
3600 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3601 THUNK_TARGET);
3602 p += extent_size;
3603 }
3604 }
3605 unlock_user(argptr, arg, target_size_out);
3606 }
3607 }
3608 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303609 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00003610 }
3611 return ret;
3612}
Peter Maydelldace20d2011-01-10 13:11:24 +00003613#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003614
Laurent Vivier059c2f22011-03-30 00:12:12 +02003615static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003616 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02003617{
3618 const argtype *arg_type = ie->arg_type;
3619 int target_size;
3620 void *argptr;
3621 int ret;
3622 struct ifconf *host_ifconf;
3623 uint32_t outbufsz;
3624 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3625 int target_ifreq_size;
3626 int nb_ifreq;
3627 int free_buf = 0;
3628 int i;
3629 int target_ifc_len;
3630 abi_long target_ifc_buf;
3631 int host_ifc_len;
3632 char *host_ifc_buf;
3633
3634 assert(arg_type[0] == TYPE_PTR);
3635 assert(ie->access == IOC_RW);
3636
3637 arg_type++;
3638 target_size = thunk_type_size(arg_type, 0);
3639
3640 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3641 if (!argptr)
3642 return -TARGET_EFAULT;
3643 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3644 unlock_user(argptr, arg, 0);
3645
3646 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3647 target_ifc_len = host_ifconf->ifc_len;
3648 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3649
3650 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3651 nb_ifreq = target_ifc_len / target_ifreq_size;
3652 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3653
3654 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3655 if (outbufsz > MAX_STRUCT_SIZE) {
3656 /* We can't fit all the extents into the fixed size buffer.
3657 * Allocate one that is large enough and use it instead.
3658 */
3659 host_ifconf = malloc(outbufsz);
3660 if (!host_ifconf) {
3661 return -TARGET_ENOMEM;
3662 }
3663 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3664 free_buf = 1;
3665 }
3666 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3667
3668 host_ifconf->ifc_len = host_ifc_len;
3669 host_ifconf->ifc_buf = host_ifc_buf;
3670
3671 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3672 if (!is_error(ret)) {
3673 /* convert host ifc_len to target ifc_len */
3674
3675 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3676 target_ifc_len = nb_ifreq * target_ifreq_size;
3677 host_ifconf->ifc_len = target_ifc_len;
3678
3679 /* restore target ifc_buf */
3680
3681 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3682
3683 /* copy struct ifconf to target user */
3684
3685 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3686 if (!argptr)
3687 return -TARGET_EFAULT;
3688 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3689 unlock_user(argptr, arg, target_size);
3690
3691 /* copy ifreq[] to target user */
3692
3693 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3694 for (i = 0; i < nb_ifreq ; i++) {
3695 thunk_convert(argptr + i * target_ifreq_size,
3696 host_ifc_buf + i * sizeof(struct ifreq),
3697 ifreq_arg_type, THUNK_TARGET);
3698 }
3699 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3700 }
3701
3702 if (free_buf) {
3703 free(host_ifconf);
3704 }
3705
3706 return ret;
3707}
3708
Alexander Graf56e904e2012-01-31 18:42:06 +01003709static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003710 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01003711{
3712 void *argptr;
3713 struct dm_ioctl *host_dm;
3714 abi_long guest_data;
3715 uint32_t guest_data_size;
3716 int target_size;
3717 const argtype *arg_type = ie->arg_type;
3718 abi_long ret;
3719 void *big_buf = NULL;
3720 char *host_data;
3721
3722 arg_type++;
3723 target_size = thunk_type_size(arg_type, 0);
3724 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3725 if (!argptr) {
3726 ret = -TARGET_EFAULT;
3727 goto out;
3728 }
3729 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3730 unlock_user(argptr, arg, 0);
3731
3732 /* buf_temp is too small, so fetch things into a bigger buffer */
3733 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3734 memcpy(big_buf, buf_temp, target_size);
3735 buf_temp = big_buf;
3736 host_dm = big_buf;
3737
3738 guest_data = arg + host_dm->data_start;
3739 if ((guest_data - arg) < 0) {
3740 ret = -EINVAL;
3741 goto out;
3742 }
3743 guest_data_size = host_dm->data_size - host_dm->data_start;
3744 host_data = (char*)host_dm + host_dm->data_start;
3745
3746 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3747 switch (ie->host_cmd) {
3748 case DM_REMOVE_ALL:
3749 case DM_LIST_DEVICES:
3750 case DM_DEV_CREATE:
3751 case DM_DEV_REMOVE:
3752 case DM_DEV_SUSPEND:
3753 case DM_DEV_STATUS:
3754 case DM_DEV_WAIT:
3755 case DM_TABLE_STATUS:
3756 case DM_TABLE_CLEAR:
3757 case DM_TABLE_DEPS:
3758 case DM_LIST_VERSIONS:
3759 /* no input data */
3760 break;
3761 case DM_DEV_RENAME:
3762 case DM_DEV_SET_GEOMETRY:
3763 /* data contains only strings */
3764 memcpy(host_data, argptr, guest_data_size);
3765 break;
3766 case DM_TARGET_MSG:
3767 memcpy(host_data, argptr, guest_data_size);
3768 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3769 break;
3770 case DM_TABLE_LOAD:
3771 {
3772 void *gspec = argptr;
3773 void *cur_data = host_data;
3774 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3775 int spec_size = thunk_type_size(arg_type, 0);
3776 int i;
3777
3778 for (i = 0; i < host_dm->target_count; i++) {
3779 struct dm_target_spec *spec = cur_data;
3780 uint32_t next;
3781 int slen;
3782
3783 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3784 slen = strlen((char*)gspec + spec_size) + 1;
3785 next = spec->next;
3786 spec->next = sizeof(*spec) + slen;
3787 strcpy((char*)&spec[1], gspec + spec_size);
3788 gspec += next;
3789 cur_data += spec->next;
3790 }
3791 break;
3792 }
3793 default:
3794 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08003795 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003796 goto out;
3797 }
3798 unlock_user(argptr, guest_data, 0);
3799
3800 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3801 if (!is_error(ret)) {
3802 guest_data = arg + host_dm->data_start;
3803 guest_data_size = host_dm->data_size - host_dm->data_start;
3804 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3805 switch (ie->host_cmd) {
3806 case DM_REMOVE_ALL:
3807 case DM_DEV_CREATE:
3808 case DM_DEV_REMOVE:
3809 case DM_DEV_RENAME:
3810 case DM_DEV_SUSPEND:
3811 case DM_DEV_STATUS:
3812 case DM_TABLE_LOAD:
3813 case DM_TABLE_CLEAR:
3814 case DM_TARGET_MSG:
3815 case DM_DEV_SET_GEOMETRY:
3816 /* no return data */
3817 break;
3818 case DM_LIST_DEVICES:
3819 {
3820 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3821 uint32_t remaining_data = guest_data_size;
3822 void *cur_data = argptr;
3823 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3824 int nl_size = 12; /* can't use thunk_size due to alignment */
3825
3826 while (1) {
3827 uint32_t next = nl->next;
3828 if (next) {
3829 nl->next = nl_size + (strlen(nl->name) + 1);
3830 }
3831 if (remaining_data < nl->next) {
3832 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3833 break;
3834 }
3835 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3836 strcpy(cur_data + nl_size, nl->name);
3837 cur_data += nl->next;
3838 remaining_data -= nl->next;
3839 if (!next) {
3840 break;
3841 }
3842 nl = (void*)nl + next;
3843 }
3844 break;
3845 }
3846 case DM_DEV_WAIT:
3847 case DM_TABLE_STATUS:
3848 {
3849 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3850 void *cur_data = argptr;
3851 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3852 int spec_size = thunk_type_size(arg_type, 0);
3853 int i;
3854
3855 for (i = 0; i < host_dm->target_count; i++) {
3856 uint32_t next = spec->next;
3857 int slen = strlen((char*)&spec[1]) + 1;
3858 spec->next = (cur_data - argptr) + spec_size + slen;
3859 if (guest_data_size < spec->next) {
3860 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3861 break;
3862 }
3863 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3864 strcpy(cur_data + spec_size, (char*)&spec[1]);
3865 cur_data = argptr + spec->next;
3866 spec = (void*)host_dm + host_dm->data_start + next;
3867 }
3868 break;
3869 }
3870 case DM_TABLE_DEPS:
3871 {
3872 void *hdata = (void*)host_dm + host_dm->data_start;
3873 int count = *(uint32_t*)hdata;
3874 uint64_t *hdev = hdata + 8;
3875 uint64_t *gdev = argptr + 8;
3876 int i;
3877
3878 *(uint32_t*)argptr = tswap32(count);
3879 for (i = 0; i < count; i++) {
3880 *gdev = tswap64(*hdev);
3881 gdev++;
3882 hdev++;
3883 }
3884 break;
3885 }
3886 case DM_LIST_VERSIONS:
3887 {
3888 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3889 uint32_t remaining_data = guest_data_size;
3890 void *cur_data = argptr;
3891 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3892 int vers_size = thunk_type_size(arg_type, 0);
3893
3894 while (1) {
3895 uint32_t next = vers->next;
3896 if (next) {
3897 vers->next = vers_size + (strlen(vers->name) + 1);
3898 }
3899 if (remaining_data < vers->next) {
3900 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3901 break;
3902 }
3903 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3904 strcpy(cur_data + vers_size, vers->name);
3905 cur_data += vers->next;
3906 remaining_data -= vers->next;
3907 if (!next) {
3908 break;
3909 }
3910 vers = (void*)vers + next;
3911 }
3912 break;
3913 }
3914 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08003915 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003916 ret = -TARGET_EINVAL;
3917 goto out;
3918 }
3919 unlock_user(argptr, guest_data, guest_data_size);
3920
3921 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3922 if (!argptr) {
3923 ret = -TARGET_EFAULT;
3924 goto out;
3925 }
3926 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3927 unlock_user(argptr, arg, target_size);
3928 }
3929out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003930 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003931 return ret;
3932}
3933
Alexander Grafa59b5e32014-08-22 13:15:50 +02003934static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003935 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02003936{
3937 void *argptr;
3938 int target_size;
3939 const argtype *arg_type = ie->arg_type;
3940 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3941 abi_long ret;
3942
3943 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3944 struct blkpg_partition host_part;
3945
3946 /* Read and convert blkpg */
3947 arg_type++;
3948 target_size = thunk_type_size(arg_type, 0);
3949 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3950 if (!argptr) {
3951 ret = -TARGET_EFAULT;
3952 goto out;
3953 }
3954 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3955 unlock_user(argptr, arg, 0);
3956
3957 switch (host_blkpg->op) {
3958 case BLKPG_ADD_PARTITION:
3959 case BLKPG_DEL_PARTITION:
3960 /* payload is struct blkpg_partition */
3961 break;
3962 default:
3963 /* Unknown opcode */
3964 ret = -TARGET_EINVAL;
3965 goto out;
3966 }
3967
3968 /* Read and convert blkpg->data */
3969 arg = (abi_long)(uintptr_t)host_blkpg->data;
3970 target_size = thunk_type_size(part_arg_type, 0);
3971 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3972 if (!argptr) {
3973 ret = -TARGET_EFAULT;
3974 goto out;
3975 }
3976 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3977 unlock_user(argptr, arg, 0);
3978
3979 /* Swizzle the data pointer to our local copy and call! */
3980 host_blkpg->data = &host_part;
3981 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3982
3983out:
3984 return ret;
3985}
3986
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003987static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003988 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003989{
3990 const argtype *arg_type = ie->arg_type;
3991 const StructEntry *se;
3992 const argtype *field_types;
3993 const int *dst_offsets, *src_offsets;
3994 int target_size;
3995 void *argptr;
3996 abi_ulong *target_rt_dev_ptr;
3997 unsigned long *host_rt_dev_ptr;
3998 abi_long ret;
3999 int i;
4000
4001 assert(ie->access == IOC_W);
4002 assert(*arg_type == TYPE_PTR);
4003 arg_type++;
4004 assert(*arg_type == TYPE_STRUCT);
4005 target_size = thunk_type_size(arg_type, 0);
4006 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4007 if (!argptr) {
4008 return -TARGET_EFAULT;
4009 }
4010 arg_type++;
4011 assert(*arg_type == (int)STRUCT_rtentry);
4012 se = struct_entries + *arg_type++;
4013 assert(se->convert[0] == NULL);
4014 /* convert struct here to be able to catch rt_dev string */
4015 field_types = se->field_types;
4016 dst_offsets = se->field_offsets[THUNK_HOST];
4017 src_offsets = se->field_offsets[THUNK_TARGET];
4018 for (i = 0; i < se->nb_fields; i++) {
4019 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4020 assert(*field_types == TYPE_PTRVOID);
4021 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4022 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4023 if (*target_rt_dev_ptr != 0) {
4024 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4025 tswapal(*target_rt_dev_ptr));
4026 if (!*host_rt_dev_ptr) {
4027 unlock_user(argptr, arg, 0);
4028 return -TARGET_EFAULT;
4029 }
4030 } else {
4031 *host_rt_dev_ptr = 0;
4032 }
4033 field_types++;
4034 continue;
4035 }
4036 field_types = thunk_convert(buf_temp + dst_offsets[i],
4037 argptr + src_offsets[i],
4038 field_types, THUNK_HOST);
4039 }
4040 unlock_user(argptr, arg, 0);
4041
4042 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4043 if (*host_rt_dev_ptr != 0) {
4044 unlock_user((void *)*host_rt_dev_ptr,
4045 *target_rt_dev_ptr, 0);
4046 }
4047 return ret;
4048}
4049
Paul Burtonca56f5b2014-06-22 11:25:47 +01004050static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004051 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004052{
4053 int sig = target_to_host_signal(arg);
4054 return get_errno(ioctl(fd, ie->host_cmd, sig));
4055}
4056
blueswir19f106a72008-10-05 10:52:52 +00004057static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004058#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004059 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4060#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4061 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004062#include "ioctls.h"
4063 { 0, 0, },
4064};
4065
pbrook53a59602006-03-25 19:31:22 +00004066/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004067/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004068static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004069{
4070 const IOCTLEntry *ie;
4071 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004072 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004073 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004074 int target_size;
4075 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004076
4077 ie = ioctl_entries;
4078 for(;;) {
4079 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004080 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004081 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004082 }
4083 if (ie->target_cmd == cmd)
4084 break;
4085 ie++;
4086 }
4087 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004088#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004089 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004090#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004091 if (ie->do_ioctl) {
4092 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4093 }
4094
bellard31e31b82003-02-18 22:55:36 +00004095 switch(arg_type[0]) {
4096 case TYPE_NULL:
4097 /* no argument */
4098 ret = get_errno(ioctl(fd, ie->host_cmd));
4099 break;
4100 case TYPE_PTRVOID:
4101 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004102 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4103 break;
4104 case TYPE_PTR:
4105 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004106 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004107 switch(ie->access) {
4108 case IOC_R:
4109 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4110 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004111 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4112 if (!argptr)
4113 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004114 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4115 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004116 }
4117 break;
4118 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004119 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4120 if (!argptr)
4121 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004122 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4123 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004124 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4125 break;
4126 default:
4127 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004128 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4129 if (!argptr)
4130 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004131 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4132 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004133 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4134 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004135 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4136 if (!argptr)
4137 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004138 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4139 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004140 }
4141 break;
4142 }
4143 break;
4144 default:
j_mayer32407102007-09-26 23:01:49 +00004145 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4146 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004147 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004148 break;
4149 }
4150 return ret;
4151}
4152
blueswir1b39bc502008-10-05 10:51:10 +00004153static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004154 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4155 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4156 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4157 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4158 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4159 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4160 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4161 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4162 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4163 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4164 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4165 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4166 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4167 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4168 { 0, 0, 0, 0 }
4169};
4170
blueswir1b39bc502008-10-05 10:51:10 +00004171static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004172 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4173 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4174 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4175 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4176 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4177 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4178 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4179 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4180 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4181 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4182 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4183 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4184 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4185 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4186 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4187 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4188 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4189 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4190 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4191 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4192 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4193 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4194 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4195 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4196 { 0, 0, 0, 0 }
4197};
4198
blueswir1b39bc502008-10-05 10:51:10 +00004199static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004200 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4201 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4202 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4203 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4204 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4205 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4206 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4207 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4208 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4209 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4210 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4211 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4212 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4213 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4214 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4215 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4216 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4217 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4218 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4219 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4220 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4221 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4222 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4223 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4224 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4225 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4226 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4227 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4228 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4229 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4230 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4231 { 0, 0, 0, 0 }
4232};
4233
blueswir1b39bc502008-10-05 10:51:10 +00004234static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004235 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4236 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4237 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4238 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4239 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4240 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4241 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4242 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4243 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4244 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4245 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4246 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4247 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4248 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4249 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4250 { 0, 0, 0, 0 }
4251};
4252
4253static void target_to_host_termios (void *dst, const void *src)
4254{
4255 struct host_termios *host = dst;
4256 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004257
ths5fafdf22007-09-16 21:08:06 +00004258 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004259 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004260 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004261 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004262 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004263 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004264 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004265 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4266 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004267
Arnaud Patard44607122009-04-21 17:39:08 +03004268 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004269 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4270 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004271 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004272 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004273 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004274 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004275 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004276 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004277 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004278 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4279 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004280 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4281 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4282 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4283 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4284 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004285 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004286}
ths3b46e622007-09-17 08:09:54 +00004287
bellard31e31b82003-02-18 22:55:36 +00004288static void host_to_target_termios (void *dst, const void *src)
4289{
4290 struct target_termios *target = dst;
4291 const struct host_termios *host = src;
4292
ths5fafdf22007-09-16 21:08:06 +00004293 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004294 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004295 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004296 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004297 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004298 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004299 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004300 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4301 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004302
Arnaud Patard44607122009-04-21 17:39:08 +03004303 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004304 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4305 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4306 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4307 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4308 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4309 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4310 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4311 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4312 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4313 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4314 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4315 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4316 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4317 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4318 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4319 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4320 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4321}
4322
blueswir18e853dc2008-10-05 10:49:32 +00004323static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004324 .convert = { host_to_target_termios, target_to_host_termios },
4325 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4326 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4327};
4328
bellard5286db72003-06-05 00:57:30 +00004329static bitmask_transtbl mmap_flags_tbl[] = {
4330 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4331 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4332 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4333 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4334 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4335 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4336 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4337 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004338 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4339 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004340 { 0, 0, 0, 0 }
4341};
4342
bellard2ab83ea2003-06-15 19:56:46 +00004343#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004344
4345/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004346static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004347
bellard03acab62007-11-11 14:57:14 +00004348static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004349{
4350 int size;
pbrook53a59602006-03-25 19:31:22 +00004351 void *p;
bellard6dbad632003-03-16 18:05:05 +00004352
4353 if (!ldt_table)
4354 return 0;
4355 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4356 if (size > bytecount)
4357 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004358 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4359 if (!p)
bellard03acab62007-11-11 14:57:14 +00004360 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004361 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004362 memcpy(p, ldt_table, size);
4363 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004364 return size;
4365}
4366
4367/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004368static abi_long write_ldt(CPUX86State *env,
4369 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004370{
4371 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004372 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004373 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004374 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004375 uint32_t *lp, entry_1, entry_2;
4376
4377 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004378 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004379 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004380 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004381 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004382 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004383 ldt_info.limit = tswap32(target_ldt_info->limit);
4384 ldt_info.flags = tswap32(target_ldt_info->flags);
4385 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004386
bellard6dbad632003-03-16 18:05:05 +00004387 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004388 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004389 seg_32bit = ldt_info.flags & 1;
4390 contents = (ldt_info.flags >> 1) & 3;
4391 read_exec_only = (ldt_info.flags >> 3) & 1;
4392 limit_in_pages = (ldt_info.flags >> 4) & 1;
4393 seg_not_present = (ldt_info.flags >> 5) & 1;
4394 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004395#ifdef TARGET_ABI32
4396 lm = 0;
4397#else
4398 lm = (ldt_info.flags >> 7) & 1;
4399#endif
bellard6dbad632003-03-16 18:05:05 +00004400 if (contents == 3) {
4401 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004402 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004403 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004404 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004405 }
4406 /* allocate the LDT */
4407 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004408 env->ldt.base = target_mmap(0,
4409 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4410 PROT_READ|PROT_WRITE,
4411 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4412 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004413 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004414 memset(g2h(env->ldt.base), 0,
4415 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004416 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004417 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004418 }
4419
4420 /* NOTE: same code as Linux kernel */
4421 /* Allow LDTs to be cleared by the user. */
4422 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4423 if (oldmode ||
4424 (contents == 0 &&
4425 read_exec_only == 1 &&
4426 seg_32bit == 0 &&
4427 limit_in_pages == 0 &&
4428 seg_not_present == 1 &&
4429 useable == 0 )) {
4430 entry_1 = 0;
4431 entry_2 = 0;
4432 goto install;
4433 }
4434 }
ths3b46e622007-09-17 08:09:54 +00004435
bellard6dbad632003-03-16 18:05:05 +00004436 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4437 (ldt_info.limit & 0x0ffff);
4438 entry_2 = (ldt_info.base_addr & 0xff000000) |
4439 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4440 (ldt_info.limit & 0xf0000) |
4441 ((read_exec_only ^ 1) << 9) |
4442 (contents << 10) |
4443 ((seg_not_present ^ 1) << 15) |
4444 (seg_32bit << 22) |
4445 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004446 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004447 0x7000;
4448 if (!oldmode)
4449 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004450
bellard6dbad632003-03-16 18:05:05 +00004451 /* Install the new entry ... */
4452install:
4453 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4454 lp[0] = tswap32(entry_1);
4455 lp[1] = tswap32(entry_2);
4456 return 0;
4457}
4458
4459/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004460static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4461 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004462{
bellard03acab62007-11-11 14:57:14 +00004463 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004464
bellard6dbad632003-03-16 18:05:05 +00004465 switch (func) {
4466 case 0:
4467 ret = read_ldt(ptr, bytecount);
4468 break;
4469 case 1:
4470 ret = write_ldt(env, ptr, bytecount, 1);
4471 break;
4472 case 0x11:
4473 ret = write_ldt(env, ptr, bytecount, 0);
4474 break;
bellard03acab62007-11-11 14:57:14 +00004475 default:
4476 ret = -TARGET_ENOSYS;
4477 break;
bellard6dbad632003-03-16 18:05:05 +00004478 }
4479 return ret;
4480}
bellard1b6b0292003-03-22 17:31:38 +00004481
blueswir14583f582008-08-24 10:35:55 +00004482#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004483abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004484{
4485 uint64_t *gdt_table = g2h(env->gdt.base);
4486 struct target_modify_ldt_ldt_s ldt_info;
4487 struct target_modify_ldt_ldt_s *target_ldt_info;
4488 int seg_32bit, contents, read_exec_only, limit_in_pages;
4489 int seg_not_present, useable, lm;
4490 uint32_t *lp, entry_1, entry_2;
4491 int i;
4492
4493 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4494 if (!target_ldt_info)
4495 return -TARGET_EFAULT;
4496 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004497 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004498 ldt_info.limit = tswap32(target_ldt_info->limit);
4499 ldt_info.flags = tswap32(target_ldt_info->flags);
4500 if (ldt_info.entry_number == -1) {
4501 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4502 if (gdt_table[i] == 0) {
4503 ldt_info.entry_number = i;
4504 target_ldt_info->entry_number = tswap32(i);
4505 break;
4506 }
4507 }
4508 }
4509 unlock_user_struct(target_ldt_info, ptr, 1);
4510
4511 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4512 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4513 return -TARGET_EINVAL;
4514 seg_32bit = ldt_info.flags & 1;
4515 contents = (ldt_info.flags >> 1) & 3;
4516 read_exec_only = (ldt_info.flags >> 3) & 1;
4517 limit_in_pages = (ldt_info.flags >> 4) & 1;
4518 seg_not_present = (ldt_info.flags >> 5) & 1;
4519 useable = (ldt_info.flags >> 6) & 1;
4520#ifdef TARGET_ABI32
4521 lm = 0;
4522#else
4523 lm = (ldt_info.flags >> 7) & 1;
4524#endif
4525
4526 if (contents == 3) {
4527 if (seg_not_present == 0)
4528 return -TARGET_EINVAL;
4529 }
4530
4531 /* NOTE: same code as Linux kernel */
4532 /* Allow LDTs to be cleared by the user. */
4533 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4534 if ((contents == 0 &&
4535 read_exec_only == 1 &&
4536 seg_32bit == 0 &&
4537 limit_in_pages == 0 &&
4538 seg_not_present == 1 &&
4539 useable == 0 )) {
4540 entry_1 = 0;
4541 entry_2 = 0;
4542 goto install;
4543 }
4544 }
4545
4546 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4547 (ldt_info.limit & 0x0ffff);
4548 entry_2 = (ldt_info.base_addr & 0xff000000) |
4549 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4550 (ldt_info.limit & 0xf0000) |
4551 ((read_exec_only ^ 1) << 9) |
4552 (contents << 10) |
4553 ((seg_not_present ^ 1) << 15) |
4554 (seg_32bit << 22) |
4555 (limit_in_pages << 23) |
4556 (useable << 20) |
4557 (lm << 21) |
4558 0x7000;
4559
4560 /* Install the new entry ... */
4561install:
4562 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4563 lp[0] = tswap32(entry_1);
4564 lp[1] = tswap32(entry_2);
4565 return 0;
4566}
4567
blueswir18fcd3692008-08-17 20:26:25 +00004568static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004569{
4570 struct target_modify_ldt_ldt_s *target_ldt_info;
4571 uint64_t *gdt_table = g2h(env->gdt.base);
4572 uint32_t base_addr, limit, flags;
4573 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4574 int seg_not_present, useable, lm;
4575 uint32_t *lp, entry_1, entry_2;
4576
4577 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4578 if (!target_ldt_info)
4579 return -TARGET_EFAULT;
4580 idx = tswap32(target_ldt_info->entry_number);
4581 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4582 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4583 unlock_user_struct(target_ldt_info, ptr, 1);
4584 return -TARGET_EINVAL;
4585 }
4586 lp = (uint32_t *)(gdt_table + idx);
4587 entry_1 = tswap32(lp[0]);
4588 entry_2 = tswap32(lp[1]);
4589
4590 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4591 contents = (entry_2 >> 10) & 3;
4592 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4593 seg_32bit = (entry_2 >> 22) & 1;
4594 limit_in_pages = (entry_2 >> 23) & 1;
4595 useable = (entry_2 >> 20) & 1;
4596#ifdef TARGET_ABI32
4597 lm = 0;
4598#else
4599 lm = (entry_2 >> 21) & 1;
4600#endif
4601 flags = (seg_32bit << 0) | (contents << 1) |
4602 (read_exec_only << 3) | (limit_in_pages << 4) |
4603 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4604 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4605 base_addr = (entry_1 >> 16) |
4606 (entry_2 & 0xff000000) |
4607 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004608 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004609 target_ldt_info->limit = tswap32(limit);
4610 target_ldt_info->flags = tswap32(flags);
4611 unlock_user_struct(target_ldt_info, ptr, 1);
4612 return 0;
4613}
blueswir14583f582008-08-24 10:35:55 +00004614#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004615
bellardd2fd1af2007-11-14 18:08:56 +00004616#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004617abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004618{
Juan Quintela1add8692011-06-16 17:37:09 +01004619 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004620 abi_ulong val;
4621 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004622
bellardd2fd1af2007-11-14 18:08:56 +00004623 switch(code) {
4624 case TARGET_ARCH_SET_GS:
4625 case TARGET_ARCH_SET_FS:
4626 if (code == TARGET_ARCH_SET_GS)
4627 idx = R_GS;
4628 else
4629 idx = R_FS;
4630 cpu_x86_load_seg(env, idx, 0);
4631 env->segs[idx].base = addr;
4632 break;
4633 case TARGET_ARCH_GET_GS:
4634 case TARGET_ARCH_GET_FS:
4635 if (code == TARGET_ARCH_GET_GS)
4636 idx = R_GS;
4637 else
4638 idx = R_FS;
4639 val = env->segs[idx].base;
4640 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004641 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004642 break;
4643 default:
4644 ret = -TARGET_EINVAL;
4645 break;
4646 }
Juan Quintela1add8692011-06-16 17:37:09 +01004647 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004648}
4649#endif
4650
bellard2ab83ea2003-06-15 19:56:46 +00004651#endif /* defined(TARGET_I386) */
4652
Riku Voipio05098a92011-03-04 15:27:29 +02004653#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004654
pbrookd865bab2008-06-07 22:12:17 +00004655
4656static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4657typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004658 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004659 pthread_mutex_t mutex;
4660 pthread_cond_t cond;
4661 pthread_t thread;
4662 uint32_t tid;
4663 abi_ulong child_tidptr;
4664 abi_ulong parent_tidptr;
4665 sigset_t sigmask;
4666} new_thread_info;
4667
4668static void *clone_func(void *arg)
4669{
4670 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004671 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004672 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004673 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004674
Emilio G. Cota70903762015-08-23 20:23:41 -04004675 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00004676 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004677 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004678 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004679 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004680 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004681 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004682 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004683 if (info->child_tidptr)
4684 put_user_u32(info->tid, info->child_tidptr);
4685 if (info->parent_tidptr)
4686 put_user_u32(info->tid, info->parent_tidptr);
4687 /* Enable signals. */
4688 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4689 /* Signal to the parent that we're ready. */
4690 pthread_mutex_lock(&info->mutex);
4691 pthread_cond_broadcast(&info->cond);
4692 pthread_mutex_unlock(&info->mutex);
4693 /* Wait until the parent has finshed initializing the tls state. */
4694 pthread_mutex_lock(&clone_lock);
4695 pthread_mutex_unlock(&clone_lock);
4696 cpu_loop(env);
4697 /* never exits */
4698 return NULL;
4699}
bellard1b6b0292003-03-22 17:31:38 +00004700
ths0da46a62007-10-20 20:23:07 +00004701/* do_fork() Must return host values and target errnos (unlike most
4702 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004703static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004704 abi_ulong parent_tidptr, target_ulong newtls,
4705 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004706{
Andreas Färber0429a972013-08-26 18:14:44 +02004707 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004708 int ret;
bellard5cd43932003-03-29 16:54:36 +00004709 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004710 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004711 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004712 unsigned int nptl_flags;
4713 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004714
balrog436d1242008-09-21 02:39:45 +00004715 /* Emulate vfork() with fork() */
4716 if (flags & CLONE_VFORK)
4717 flags &= ~(CLONE_VFORK | CLONE_VM);
4718
bellard1b6b0292003-03-22 17:31:38 +00004719 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004720 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004721 new_thread_info info;
4722 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004723
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02004724 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00004725 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004726 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004727 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004728 /* Init regs that differ from the parent. */
4729 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004730 new_cpu = ENV_GET_CPU(new_env);
4731 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004732 ts->bprm = parent_ts->bprm;
4733 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004734 nptl_flags = flags;
4735 flags &= ~CLONE_NPTL_FLAGS2;
4736
pbrookc2764712009-03-07 15:24:59 +00004737 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4738 ts->child_tidptr = child_tidptr;
4739 }
4740
pbrookd865bab2008-06-07 22:12:17 +00004741 if (nptl_flags & CLONE_SETTLS)
4742 cpu_set_tls (new_env, newtls);
4743
4744 /* Grab a mutex so that thread setup appears atomic. */
4745 pthread_mutex_lock(&clone_lock);
4746
4747 memset(&info, 0, sizeof(info));
4748 pthread_mutex_init(&info.mutex, NULL);
4749 pthread_mutex_lock(&info.mutex);
4750 pthread_cond_init(&info.cond, NULL);
4751 info.env = new_env;
4752 if (nptl_flags & CLONE_CHILD_SETTID)
4753 info.child_tidptr = child_tidptr;
4754 if (nptl_flags & CLONE_PARENT_SETTID)
4755 info.parent_tidptr = parent_tidptr;
4756
4757 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004758 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4759 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004760 /* It is not safe to deliver signals until the child has finished
4761 initializing, so temporarily block all signals. */
4762 sigfillset(&sigmask);
4763 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4764
4765 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004766 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004767
4768 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4769 pthread_attr_destroy(&attr);
4770 if (ret == 0) {
4771 /* Wait for the child to initialize. */
4772 pthread_cond_wait(&info.cond, &info.mutex);
4773 ret = info.tid;
4774 if (flags & CLONE_PARENT_SETTID)
4775 put_user_u32(ret, parent_tidptr);
4776 } else {
4777 ret = -1;
4778 }
4779 pthread_mutex_unlock(&info.mutex);
4780 pthread_cond_destroy(&info.cond);
4781 pthread_mutex_destroy(&info.mutex);
4782 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004783 } else {
4784 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01004785 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
4786 return -TARGET_EINVAL;
4787 }
pbrookd865bab2008-06-07 22:12:17 +00004788 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004789 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004790 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004791 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02004792 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00004793 cpu_clone_regs(env, newsp);
4794 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004795 /* There is a race condition here. The parent process could
4796 theoretically read the TID in the child process before the child
4797 tid is set. This would require using either ptrace
4798 (not implemented) or having *_tidptr to point at a shared memory
4799 mapping. We can't repeat the spinlock hack used above because
4800 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004801 if (flags & CLONE_CHILD_SETTID)
4802 put_user_u32(gettid(), child_tidptr);
4803 if (flags & CLONE_PARENT_SETTID)
4804 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004805 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004806 if (flags & CLONE_SETTLS)
4807 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004808 if (flags & CLONE_CHILD_CLEARTID)
4809 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004810 } else {
4811 fork_end(0);
4812 }
bellard1b6b0292003-03-22 17:31:38 +00004813 }
4814 return ret;
4815}
4816
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004817/* warning : doesn't handle linux specific flags... */
4818static int target_to_host_fcntl_cmd(int cmd)
4819{
4820 switch(cmd) {
4821 case TARGET_F_DUPFD:
4822 case TARGET_F_GETFD:
4823 case TARGET_F_SETFD:
4824 case TARGET_F_GETFL:
4825 case TARGET_F_SETFL:
4826 return cmd;
4827 case TARGET_F_GETLK:
4828 return F_GETLK;
4829 case TARGET_F_SETLK:
4830 return F_SETLK;
4831 case TARGET_F_SETLKW:
4832 return F_SETLKW;
4833 case TARGET_F_GETOWN:
4834 return F_GETOWN;
4835 case TARGET_F_SETOWN:
4836 return F_SETOWN;
4837 case TARGET_F_GETSIG:
4838 return F_GETSIG;
4839 case TARGET_F_SETSIG:
4840 return F_SETSIG;
4841#if TARGET_ABI_BITS == 32
4842 case TARGET_F_GETLK64:
4843 return F_GETLK64;
4844 case TARGET_F_SETLK64:
4845 return F_SETLK64;
4846 case TARGET_F_SETLKW64:
4847 return F_SETLKW64;
4848#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004849 case TARGET_F_SETLEASE:
4850 return F_SETLEASE;
4851 case TARGET_F_GETLEASE:
4852 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004853#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004854 case TARGET_F_DUPFD_CLOEXEC:
4855 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004856#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004857 case TARGET_F_NOTIFY:
4858 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004859#ifdef F_GETOWN_EX
4860 case TARGET_F_GETOWN_EX:
4861 return F_GETOWN_EX;
4862#endif
4863#ifdef F_SETOWN_EX
4864 case TARGET_F_SETOWN_EX:
4865 return F_SETOWN_EX;
4866#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004867 default:
4868 return -TARGET_EINVAL;
4869 }
4870 return -TARGET_EINVAL;
4871}
4872
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004873#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4874static const bitmask_transtbl flock_tbl[] = {
4875 TRANSTBL_CONVERT(F_RDLCK),
4876 TRANSTBL_CONVERT(F_WRLCK),
4877 TRANSTBL_CONVERT(F_UNLCK),
4878 TRANSTBL_CONVERT(F_EXLCK),
4879 TRANSTBL_CONVERT(F_SHLCK),
4880 { 0, 0, 0, 0 }
4881};
4882
blueswir1992f48a2007-10-14 16:27:31 +00004883static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004884{
4885 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004886 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004887 struct flock64 fl64;
4888 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004889#ifdef F_GETOWN_EX
4890 struct f_owner_ex fox;
4891 struct target_f_owner_ex *target_fox;
4892#endif
blueswir1992f48a2007-10-14 16:27:31 +00004893 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004894 int host_cmd = target_to_host_fcntl_cmd(cmd);
4895
4896 if (host_cmd == -TARGET_EINVAL)
4897 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004898
bellard7775e9e2003-05-14 22:46:48 +00004899 switch(cmd) {
4900 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004901 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4902 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004903 fl.l_type =
4904 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004905 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004906 fl.l_start = tswapal(target_fl->l_start);
4907 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004908 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004909 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004910 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004911 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004912 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4913 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004914 target_fl->l_type =
4915 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004916 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004917 target_fl->l_start = tswapal(fl.l_start);
4918 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004919 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004920 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004921 }
4922 break;
ths3b46e622007-09-17 08:09:54 +00004923
bellard7775e9e2003-05-14 22:46:48 +00004924 case TARGET_F_SETLK:
4925 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004926 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4927 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004928 fl.l_type =
4929 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004930 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004931 fl.l_start = tswapal(target_fl->l_start);
4932 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004933 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004934 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004935 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004936 break;
ths3b46e622007-09-17 08:09:54 +00004937
bellard7775e9e2003-05-14 22:46:48 +00004938 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004939 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4940 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004941 fl64.l_type =
4942 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004943 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004944 fl64.l_start = tswap64(target_fl64->l_start);
4945 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004946 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004947 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004948 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004949 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004950 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4951 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004952 target_fl64->l_type =
4953 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004954 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004955 target_fl64->l_start = tswap64(fl64.l_start);
4956 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004957 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004958 unlock_user_struct(target_fl64, arg, 1);
4959 }
bellard9ee1fa22007-11-11 15:11:19 +00004960 break;
bellard7775e9e2003-05-14 22:46:48 +00004961 case TARGET_F_SETLK64:
4962 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004963 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4964 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004965 fl64.l_type =
4966 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004967 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004968 fl64.l_start = tswap64(target_fl64->l_start);
4969 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004970 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004971 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004972 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004973 break;
4974
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004975 case TARGET_F_GETFL:
4976 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004977 if (ret >= 0) {
4978 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4979 }
bellardffa65c32004-01-04 23:57:22 +00004980 break;
4981
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004982 case TARGET_F_SETFL:
4983 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4984 break;
4985
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004986#ifdef F_GETOWN_EX
4987 case TARGET_F_GETOWN_EX:
4988 ret = get_errno(fcntl(fd, host_cmd, &fox));
4989 if (ret >= 0) {
4990 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4991 return -TARGET_EFAULT;
4992 target_fox->type = tswap32(fox.type);
4993 target_fox->pid = tswap32(fox.pid);
4994 unlock_user_struct(target_fox, arg, 1);
4995 }
4996 break;
4997#endif
4998
4999#ifdef F_SETOWN_EX
5000 case TARGET_F_SETOWN_EX:
5001 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5002 return -TARGET_EFAULT;
5003 fox.type = tswap32(target_fox->type);
5004 fox.pid = tswap32(target_fox->pid);
5005 unlock_user_struct(target_fox, arg, 0);
5006 ret = get_errno(fcntl(fd, host_cmd, &fox));
5007 break;
5008#endif
5009
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005010 case TARGET_F_SETOWN:
5011 case TARGET_F_GETOWN:
5012 case TARGET_F_SETSIG:
5013 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005014 case TARGET_F_SETLEASE:
5015 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005016 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005017 break;
5018
bellard7775e9e2003-05-14 22:46:48 +00005019 default:
bellard9ee1fa22007-11-11 15:11:19 +00005020 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005021 break;
5022 }
5023 return ret;
5024}
5025
bellard67867302003-11-23 17:05:30 +00005026#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005027
bellard67867302003-11-23 17:05:30 +00005028static inline int high2lowuid(int uid)
5029{
5030 if (uid > 65535)
5031 return 65534;
5032 else
5033 return uid;
5034}
5035
5036static inline int high2lowgid(int gid)
5037{
5038 if (gid > 65535)
5039 return 65534;
5040 else
5041 return gid;
5042}
5043
5044static inline int low2highuid(int uid)
5045{
5046 if ((int16_t)uid == -1)
5047 return -1;
5048 else
5049 return uid;
5050}
5051
5052static inline int low2highgid(int gid)
5053{
5054 if ((int16_t)gid == -1)
5055 return -1;
5056 else
5057 return gid;
5058}
Riku Voipio0c866a72011-04-18 15:23:06 +03005059static inline int tswapid(int id)
5060{
5061 return tswap16(id);
5062}
Peter Maydell76ca3102014-03-02 19:36:41 +00005063
5064#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5065
Riku Voipio0c866a72011-04-18 15:23:06 +03005066#else /* !USE_UID16 */
5067static inline int high2lowuid(int uid)
5068{
5069 return uid;
5070}
5071static inline int high2lowgid(int gid)
5072{
5073 return gid;
5074}
5075static inline int low2highuid(int uid)
5076{
5077 return uid;
5078}
5079static inline int low2highgid(int gid)
5080{
5081 return gid;
5082}
5083static inline int tswapid(int id)
5084{
5085 return tswap32(id);
5086}
Peter Maydell76ca3102014-03-02 19:36:41 +00005087
5088#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5089
bellard67867302003-11-23 17:05:30 +00005090#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005091
bellard31e31b82003-02-18 22:55:36 +00005092void syscall_init(void)
5093{
bellard2ab83ea2003-06-15 19:56:46 +00005094 IOCTLEntry *ie;
5095 const argtype *arg_type;
5096 int size;
thsb92c47c2007-11-01 00:07:38 +00005097 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005098
Alexander Graf8be656b2015-05-06 23:47:32 +02005099 thunk_init(STRUCT_MAX);
5100
Blue Swirl001faf32009-05-13 17:53:17 +00005101#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005102#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005103#include "syscall_types.h"
5104#undef STRUCT
5105#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005106
Peter Maydelldd6e9572012-07-23 08:07:22 +00005107 /* Build target_to_host_errno_table[] table from
5108 * host_to_target_errno_table[]. */
5109 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5110 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5111 }
5112
bellard2ab83ea2003-06-15 19:56:46 +00005113 /* we patch the ioctl size if necessary. We rely on the fact that
5114 no ioctl has all the bits at '1' in the size field */
5115 ie = ioctl_entries;
5116 while (ie->target_cmd != 0) {
5117 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5118 TARGET_IOC_SIZEMASK) {
5119 arg_type = ie->arg_type;
5120 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005121 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005122 ie->target_cmd);
5123 exit(1);
5124 }
5125 arg_type++;
5126 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005127 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005128 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5129 (size << TARGET_IOC_SIZESHIFT);
5130 }
thsb92c47c2007-11-01 00:07:38 +00005131
bellard2ab83ea2003-06-15 19:56:46 +00005132 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005133#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5134 (defined(__x86_64__) && defined(TARGET_X86_64))
5135 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5136 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5137 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005138 }
5139#endif
5140 ie++;
5141 }
bellard31e31b82003-02-18 22:55:36 +00005142}
bellardc573ff62004-01-04 15:51:36 +00005143
blueswir1992f48a2007-10-14 16:27:31 +00005144#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005145static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5146{
thsaf325d32008-06-10 15:29:15 +00005147#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005148 return ((uint64_t)word0 << 32) | word1;
5149#else
5150 return ((uint64_t)word1 << 32) | word0;
5151#endif
5152}
blueswir1992f48a2007-10-14 16:27:31 +00005153#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005154static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5155{
5156 return word0;
5157}
blueswir1992f48a2007-10-14 16:27:31 +00005158#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005159
5160#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005161static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5162 abi_long arg2,
5163 abi_long arg3,
5164 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005165{
Riku Voipio48e515d2011-07-12 15:40:51 +03005166 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005167 arg2 = arg3;
5168 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005169 }
pbrookce4defa2006-02-09 16:49:55 +00005170 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5171}
5172#endif
5173
5174#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005175static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5176 abi_long arg2,
5177 abi_long arg3,
5178 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005179{
Riku Voipio48e515d2011-07-12 15:40:51 +03005180 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005181 arg2 = arg3;
5182 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005183 }
pbrookce4defa2006-02-09 16:49:55 +00005184 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5185}
5186#endif
5187
bellard579a97f2007-11-11 14:26:47 +00005188static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5189 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005190{
5191 struct target_timespec *target_ts;
5192
bellard579a97f2007-11-11 14:26:47 +00005193 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5194 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005195 host_ts->tv_sec = tswapal(target_ts->tv_sec);
5196 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005197 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005198 return 0;
pbrook53a59602006-03-25 19:31:22 +00005199}
5200
bellard579a97f2007-11-11 14:26:47 +00005201static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5202 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005203{
5204 struct target_timespec *target_ts;
5205
bellard579a97f2007-11-11 14:26:47 +00005206 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5207 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005208 target_ts->tv_sec = tswapal(host_ts->tv_sec);
5209 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005210 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005211 return 0;
pbrook53a59602006-03-25 19:31:22 +00005212}
5213
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005214static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5215 abi_ulong target_addr)
5216{
5217 struct target_itimerspec *target_itspec;
5218
5219 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5220 return -TARGET_EFAULT;
5221 }
5222
5223 host_itspec->it_interval.tv_sec =
5224 tswapal(target_itspec->it_interval.tv_sec);
5225 host_itspec->it_interval.tv_nsec =
5226 tswapal(target_itspec->it_interval.tv_nsec);
5227 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5228 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5229
5230 unlock_user_struct(target_itspec, target_addr, 1);
5231 return 0;
5232}
5233
5234static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5235 struct itimerspec *host_its)
5236{
5237 struct target_itimerspec *target_itspec;
5238
5239 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5240 return -TARGET_EFAULT;
5241 }
5242
5243 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5244 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5245
5246 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5247 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5248
5249 unlock_user_struct(target_itspec, target_addr, 0);
5250 return 0;
5251}
5252
Peter Maydellc0659762014-08-09 15:42:32 +01005253static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5254 abi_ulong target_addr)
5255{
5256 struct target_sigevent *target_sevp;
5257
5258 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5259 return -TARGET_EFAULT;
5260 }
5261
5262 /* This union is awkward on 64 bit systems because it has a 32 bit
5263 * integer and a pointer in it; we follow the conversion approach
5264 * used for handling sigval types in signal.c so the guest should get
5265 * the correct value back even if we did a 64 bit byteswap and it's
5266 * using the 32 bit integer.
5267 */
5268 host_sevp->sigev_value.sival_ptr =
5269 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5270 host_sevp->sigev_signo =
5271 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5272 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5273 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5274
5275 unlock_user_struct(target_sevp, target_addr, 1);
5276 return 0;
5277}
5278
Tom Musta6f6a4032014-08-12 13:53:42 -05005279#if defined(TARGET_NR_mlockall)
5280static inline int target_to_host_mlockall_arg(int arg)
5281{
5282 int result = 0;
5283
5284 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5285 result |= MCL_CURRENT;
5286 }
5287 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5288 result |= MCL_FUTURE;
5289 }
5290 return result;
5291}
5292#endif
5293
balrog6a24a772008-09-20 02:23:36 +00005294static inline abi_long host_to_target_stat64(void *cpu_env,
5295 abi_ulong target_addr,
5296 struct stat *host_st)
5297{
Alexander Graf09701192013-09-03 20:12:15 +01005298#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005299 if (((CPUARMState *)cpu_env)->eabi) {
5300 struct target_eabi_stat64 *target_st;
5301
5302 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5303 return -TARGET_EFAULT;
5304 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5305 __put_user(host_st->st_dev, &target_st->st_dev);
5306 __put_user(host_st->st_ino, &target_st->st_ino);
5307#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5308 __put_user(host_st->st_ino, &target_st->__st_ino);
5309#endif
5310 __put_user(host_st->st_mode, &target_st->st_mode);
5311 __put_user(host_st->st_nlink, &target_st->st_nlink);
5312 __put_user(host_st->st_uid, &target_st->st_uid);
5313 __put_user(host_st->st_gid, &target_st->st_gid);
5314 __put_user(host_st->st_rdev, &target_st->st_rdev);
5315 __put_user(host_st->st_size, &target_st->st_size);
5316 __put_user(host_st->st_blksize, &target_st->st_blksize);
5317 __put_user(host_st->st_blocks, &target_st->st_blocks);
5318 __put_user(host_st->st_atime, &target_st->target_st_atime);
5319 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5320 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5321 unlock_user_struct(target_st, target_addr, 1);
5322 } else
5323#endif
5324 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005325#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005326 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005327#else
5328 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005329#endif
balrog6a24a772008-09-20 02:23:36 +00005330
5331 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5332 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005333 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005334 __put_user(host_st->st_dev, &target_st->st_dev);
5335 __put_user(host_st->st_ino, &target_st->st_ino);
5336#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5337 __put_user(host_st->st_ino, &target_st->__st_ino);
5338#endif
5339 __put_user(host_st->st_mode, &target_st->st_mode);
5340 __put_user(host_st->st_nlink, &target_st->st_nlink);
5341 __put_user(host_st->st_uid, &target_st->st_uid);
5342 __put_user(host_st->st_gid, &target_st->st_gid);
5343 __put_user(host_st->st_rdev, &target_st->st_rdev);
5344 /* XXX: better use of kernel struct */
5345 __put_user(host_st->st_size, &target_st->st_size);
5346 __put_user(host_st->st_blksize, &target_st->st_blksize);
5347 __put_user(host_st->st_blocks, &target_st->st_blocks);
5348 __put_user(host_st->st_atime, &target_st->target_st_atime);
5349 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5350 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5351 unlock_user_struct(target_st, target_addr, 1);
5352 }
5353
5354 return 0;
5355}
balrog6a24a772008-09-20 02:23:36 +00005356
pbrookbd0c5662008-05-29 14:34:11 +00005357/* ??? Using host futex calls even when target atomic operations
5358 are not really atomic probably breaks things. However implementing
5359 futexes locally would make futexes shared between multiple processes
5360 tricky. However they're probably useless because guest atomic
5361 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005362static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5363 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005364{
5365 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005366 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005367
5368 /* ??? We assume FUTEX_* constants are the same on both host
5369 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005370#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005371 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005372#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005373 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005374#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005375 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005376 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005377 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005378 if (timeout) {
5379 pts = &ts;
5380 target_to_host_timespec(pts, timeout);
5381 } else {
5382 pts = NULL;
5383 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005384 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005385 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005386 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005387 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005388 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005389 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005390 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005391 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005392 case FUTEX_WAKE_OP:
5393 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5394 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5395 But the prototype takes a `struct timespec *'; insert casts
5396 to satisfy the compiler. We do not need to tswap TIMEOUT
5397 since it's not compared to guest memory. */
5398 pts = (struct timespec *)(uintptr_t) timeout;
5399 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5400 g2h(uaddr2),
5401 (base_op == FUTEX_CMP_REQUEUE
5402 ? tswap32(val3)
5403 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005404 default:
5405 return -TARGET_ENOSYS;
5406 }
5407}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005408#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5409static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
5410 abi_long handle, abi_long mount_id,
5411 abi_long flags)
5412{
5413 struct file_handle *target_fh;
5414 struct file_handle *fh;
5415 int mid = 0;
5416 abi_long ret;
5417 char *name;
5418 unsigned int size, total_size;
5419
5420 if (get_user_s32(size, handle)) {
5421 return -TARGET_EFAULT;
5422 }
5423
5424 name = lock_user_string(pathname);
5425 if (!name) {
5426 return -TARGET_EFAULT;
5427 }
5428
5429 total_size = sizeof(struct file_handle) + size;
5430 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
5431 if (!target_fh) {
5432 unlock_user(name, pathname, 0);
5433 return -TARGET_EFAULT;
5434 }
5435
5436 fh = g_malloc0(total_size);
5437 fh->handle_bytes = size;
5438
5439 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
5440 unlock_user(name, pathname, 0);
5441
5442 /* man name_to_handle_at(2):
5443 * Other than the use of the handle_bytes field, the caller should treat
5444 * the file_handle structure as an opaque data type
5445 */
5446
5447 memcpy(target_fh, fh, total_size);
5448 target_fh->handle_bytes = tswap32(fh->handle_bytes);
5449 target_fh->handle_type = tswap32(fh->handle_type);
5450 g_free(fh);
5451 unlock_user(target_fh, handle, total_size);
5452
5453 if (put_user_s32(mid, mount_id)) {
5454 return -TARGET_EFAULT;
5455 }
5456
5457 return ret;
5458
5459}
5460#endif
5461
5462#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5463static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
5464 abi_long flags)
5465{
5466 struct file_handle *target_fh;
5467 struct file_handle *fh;
5468 unsigned int size, total_size;
5469 abi_long ret;
5470
5471 if (get_user_s32(size, handle)) {
5472 return -TARGET_EFAULT;
5473 }
5474
5475 total_size = sizeof(struct file_handle) + size;
5476 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
5477 if (!target_fh) {
5478 return -TARGET_EFAULT;
5479 }
5480
Thomas Huthe9d49d52015-10-09 17:56:38 +02005481 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005482 fh->handle_bytes = size;
5483 fh->handle_type = tswap32(target_fh->handle_type);
5484
5485 ret = get_errno(open_by_handle_at(mount_fd, fh,
5486 target_to_host_bitmask(flags, fcntl_flags_tbl)));
5487
5488 g_free(fh);
5489
5490 unlock_user(target_fh, handle, total_size);
5491
5492 return ret;
5493}
5494#endif
pbrookbd0c5662008-05-29 14:34:11 +00005495
Laurent Viviere36800c2015-10-02 14:48:09 +02005496#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
5497
5498/* signalfd siginfo conversion */
5499
5500static void
5501host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
5502 const struct signalfd_siginfo *info)
5503{
5504 int sig = host_to_target_signal(info->ssi_signo);
5505
5506 /* linux/signalfd.h defines a ssi_addr_lsb
5507 * not defined in sys/signalfd.h but used by some kernels
5508 */
5509
5510#ifdef BUS_MCEERR_AO
5511 if (tinfo->ssi_signo == SIGBUS &&
5512 (tinfo->ssi_code == BUS_MCEERR_AR ||
5513 tinfo->ssi_code == BUS_MCEERR_AO)) {
5514 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
5515 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
5516 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
5517 }
5518#endif
5519
5520 tinfo->ssi_signo = tswap32(sig);
5521 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
5522 tinfo->ssi_code = tswap32(info->ssi_code);
5523 tinfo->ssi_pid = tswap32(info->ssi_pid);
5524 tinfo->ssi_uid = tswap32(info->ssi_uid);
5525 tinfo->ssi_fd = tswap32(info->ssi_fd);
5526 tinfo->ssi_tid = tswap32(info->ssi_tid);
5527 tinfo->ssi_band = tswap32(info->ssi_band);
5528 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
5529 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
5530 tinfo->ssi_status = tswap32(info->ssi_status);
5531 tinfo->ssi_int = tswap32(info->ssi_int);
5532 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
5533 tinfo->ssi_utime = tswap64(info->ssi_utime);
5534 tinfo->ssi_stime = tswap64(info->ssi_stime);
5535 tinfo->ssi_addr = tswap64(info->ssi_addr);
5536}
5537
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005538static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02005539{
5540 int i;
5541
5542 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
5543 host_to_target_signalfd_siginfo(buf + i, buf + i);
5544 }
5545
5546 return len;
5547}
5548
5549static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005550 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02005551};
5552
5553static abi_long do_signalfd4(int fd, abi_long mask, int flags)
5554{
5555 int host_flags;
5556 target_sigset_t *target_mask;
5557 sigset_t host_mask;
5558 abi_long ret;
5559
5560 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
5561 return -TARGET_EINVAL;
5562 }
5563 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
5564 return -TARGET_EFAULT;
5565 }
5566
5567 target_to_host_sigset(&host_mask, target_mask);
5568
5569 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
5570
5571 ret = get_errno(signalfd(fd, &host_mask, host_flags));
5572 if (ret >= 0) {
5573 fd_trans_register(ret, &target_signalfd_trans);
5574 }
5575
5576 unlock_user_struct(target_mask, mask, 0);
5577
5578 return ret;
5579}
5580#endif
5581
pbrook1d9d8b52009-04-16 15:17:02 +00005582/* Map host to target signal numbers for the wait family of syscalls.
5583 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005584int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005585{
5586 if (WIFSIGNALED(status)) {
5587 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5588 }
5589 if (WIFSTOPPED(status)) {
5590 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5591 | (status & 0xff);
5592 }
5593 return status;
5594}
5595
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005596static int open_self_cmdline(void *cpu_env, int fd)
5597{
5598 int fd_orig = -1;
5599 bool word_skipped = false;
5600
5601 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5602 if (fd_orig < 0) {
5603 return fd_orig;
5604 }
5605
5606 while (true) {
5607 ssize_t nb_read;
5608 char buf[128];
5609 char *cp_buf = buf;
5610
5611 nb_read = read(fd_orig, buf, sizeof(buf));
5612 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005613 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005614 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005615 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005616 return -1;
5617 } else if (nb_read == 0) {
5618 break;
5619 }
5620
5621 if (!word_skipped) {
5622 /* Skip the first string, which is the path to qemu-*-static
5623 instead of the actual command. */
5624 cp_buf = memchr(buf, 0, sizeof(buf));
5625 if (cp_buf) {
5626 /* Null byte found, skip one string */
5627 cp_buf++;
5628 nb_read -= cp_buf - buf;
5629 word_skipped = true;
5630 }
5631 }
5632
5633 if (word_skipped) {
5634 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005635 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08005636 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005637 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005638 return -1;
5639 }
5640 }
5641 }
5642
5643 return close(fd_orig);
5644}
5645
Alexander Graf36c08d42011-11-02 20:23:24 +01005646static int open_self_maps(void *cpu_env, int fd)
5647{
Andreas Färber0429a972013-08-26 18:14:44 +02005648 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5649 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005650 FILE *fp;
5651 char *line = NULL;
5652 size_t len = 0;
5653 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005654
Alexander Graf1a49ef22012-05-01 16:30:28 +01005655 fp = fopen("/proc/self/maps", "r");
5656 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005657 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005658 }
5659
5660 while ((read = getline(&line, &len, fp)) != -1) {
5661 int fields, dev_maj, dev_min, inode;
5662 uint64_t min, max, offset;
5663 char flag_r, flag_w, flag_x, flag_p;
5664 char path[512] = "";
5665 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5666 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5667 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5668
5669 if ((fields < 10) || (fields > 11)) {
5670 continue;
5671 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005672 if (h2g_valid(min)) {
5673 int flags = page_get_flags(h2g(min));
5674 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5675 if (page_check_range(h2g(min), max - min, flags) == -1) {
5676 continue;
5677 }
5678 if (h2g(min) == ts->info->stack_limit) {
5679 pstrcpy(path, sizeof(path), " [stack]");
5680 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005681 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005682 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005683 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005684 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005685 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005686 }
5687 }
5688
5689 free(line);
5690 fclose(fp);
5691
Alexander Graf36c08d42011-11-02 20:23:24 +01005692 return 0;
5693}
5694
Alexander Graf480b8e72011-11-02 20:23:25 +01005695static int open_self_stat(void *cpu_env, int fd)
5696{
Andreas Färber0429a972013-08-26 18:14:44 +02005697 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5698 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005699 abi_ulong start_stack = ts->info->start_stack;
5700 int i;
5701
5702 for (i = 0; i < 44; i++) {
5703 char buf[128];
5704 int len;
5705 uint64_t val = 0;
5706
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005707 if (i == 0) {
5708 /* pid */
5709 val = getpid();
5710 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5711 } else if (i == 1) {
5712 /* app name */
5713 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5714 } else if (i == 27) {
5715 /* stack bottom */
5716 val = start_stack;
5717 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5718 } else {
5719 /* for the rest, there is MasterCard */
5720 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005721 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005722
Alexander Graf480b8e72011-11-02 20:23:25 +01005723 len = strlen(buf);
5724 if (write(fd, buf, len) != len) {
5725 return -1;
5726 }
5727 }
5728
5729 return 0;
5730}
5731
Alexander Graf257450e2011-11-02 20:23:26 +01005732static int open_self_auxv(void *cpu_env, int fd)
5733{
Andreas Färber0429a972013-08-26 18:14:44 +02005734 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5735 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005736 abi_ulong auxv = ts->info->saved_auxv;
5737 abi_ulong len = ts->info->auxv_len;
5738 char *ptr;
5739
5740 /*
5741 * Auxiliary vector is stored in target process stack.
5742 * read in whole auxv vector and copy it to file
5743 */
5744 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5745 if (ptr != NULL) {
5746 while (len > 0) {
5747 ssize_t r;
5748 r = write(fd, ptr, len);
5749 if (r <= 0) {
5750 break;
5751 }
5752 len -= r;
5753 ptr += r;
5754 }
5755 lseek(fd, 0, SEEK_SET);
5756 unlock_user(ptr, auxv, len);
5757 }
5758
5759 return 0;
5760}
5761
Andreas Schwab463d8e72013-07-02 14:04:12 +01005762static int is_proc_myself(const char *filename, const char *entry)
5763{
5764 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5765 filename += strlen("/proc/");
5766 if (!strncmp(filename, "self/", strlen("self/"))) {
5767 filename += strlen("self/");
5768 } else if (*filename >= '1' && *filename <= '9') {
5769 char myself[80];
5770 snprintf(myself, sizeof(myself), "%d/", getpid());
5771 if (!strncmp(filename, myself, strlen(myself))) {
5772 filename += strlen(myself);
5773 } else {
5774 return 0;
5775 }
5776 } else {
5777 return 0;
5778 }
5779 if (!strcmp(filename, entry)) {
5780 return 1;
5781 }
5782 }
5783 return 0;
5784}
5785
Laurent Vivierde6b9932013-08-30 01:46:40 +02005786#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5787static int is_proc(const char *filename, const char *entry)
5788{
5789 return strcmp(filename, entry) == 0;
5790}
5791
5792static int open_net_route(void *cpu_env, int fd)
5793{
5794 FILE *fp;
5795 char *line = NULL;
5796 size_t len = 0;
5797 ssize_t read;
5798
5799 fp = fopen("/proc/net/route", "r");
5800 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005801 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02005802 }
5803
5804 /* read header */
5805
5806 read = getline(&line, &len, fp);
5807 dprintf(fd, "%s", line);
5808
5809 /* read routes */
5810
5811 while ((read = getline(&line, &len, fp)) != -1) {
5812 char iface[16];
5813 uint32_t dest, gw, mask;
5814 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5815 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5816 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5817 &mask, &mtu, &window, &irtt);
5818 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5819 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5820 metric, tswap32(mask), mtu, window, irtt);
5821 }
5822
5823 free(line);
5824 fclose(fp);
5825
5826 return 0;
5827}
5828#endif
5829
Riku Voipio0b2effd2014-08-06 10:36:37 +03005830static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005831{
5832 struct fake_open {
5833 const char *filename;
5834 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005835 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005836 };
5837 const struct fake_open *fake_open;
5838 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005839 { "maps", open_self_maps, is_proc_myself },
5840 { "stat", open_self_stat, is_proc_myself },
5841 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005842 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005843#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5844 { "/proc/net/route", open_net_route, is_proc },
5845#endif
5846 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005847 };
5848
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005849 if (is_proc_myself(pathname, "exe")) {
5850 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01005851 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005852 }
5853
Alexander Graf3be14d02011-11-02 20:23:23 +01005854 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005855 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005856 break;
5857 }
5858 }
5859
5860 if (fake_open->filename) {
5861 const char *tmpdir;
5862 char filename[PATH_MAX];
5863 int fd, r;
5864
5865 /* create temporary file to map stat to */
5866 tmpdir = getenv("TMPDIR");
5867 if (!tmpdir)
5868 tmpdir = "/tmp";
5869 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5870 fd = mkstemp(filename);
5871 if (fd < 0) {
5872 return fd;
5873 }
5874 unlink(filename);
5875
5876 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005877 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01005878 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005879 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01005880 return r;
5881 }
5882 lseek(fd, 0, SEEK_SET);
5883
5884 return fd;
5885 }
5886
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01005887 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01005888}
5889
Alexander Grafaecc8862014-11-10 21:33:03 +01005890#define TIMER_MAGIC 0x0caf0000
5891#define TIMER_MAGIC_MASK 0xffff0000
5892
5893/* Convert QEMU provided timer ID back to internal 16bit index format */
5894static target_timer_t get_timer_id(abi_long arg)
5895{
5896 target_timer_t timerid = arg;
5897
5898 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
5899 return -TARGET_EINVAL;
5900 }
5901
5902 timerid &= 0xffff;
5903
5904 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
5905 return -TARGET_EINVAL;
5906 }
5907
5908 return timerid;
5909}
5910
ths0da46a62007-10-20 20:23:07 +00005911/* do_syscall() should always have a single exit point at the end so
5912 that actions, such as logging of syscall results, can be performed.
5913 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005914abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5915 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005916 abi_long arg5, abi_long arg6, abi_long arg7,
5917 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005918{
Andreas Färber182735e2013-05-29 22:29:20 +02005919 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005920 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005921 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005922 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005923 void *p;
ths3b46e622007-09-17 08:09:54 +00005924
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01005925#if defined(DEBUG_ERESTARTSYS)
5926 /* Debug-only code for exercising the syscall-restart code paths
5927 * in the per-architecture cpu main loops: restart every syscall
5928 * the guest makes once before letting it through.
5929 */
5930 {
5931 static int flag;
5932
5933 flag = !flag;
5934 if (flag) {
5935 return -TARGET_ERESTARTSYS;
5936 }
5937 }
5938#endif
5939
bellard72f03902003-02-18 23:33:18 +00005940#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005941 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005942#endif
thsb92c47c2007-11-01 00:07:38 +00005943 if(do_strace)
5944 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5945
bellard31e31b82003-02-18 22:55:36 +00005946 switch(num) {
5947 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005948 /* In old applications this may be used to implement _exit(2).
5949 However in threaded applictions it is used for thread termination,
5950 and _exit_group is used for application termination.
5951 Do thread termination if we have more then one thread. */
5952 /* FIXME: This probably breaks if a signal arrives. We should probably
5953 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005954 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005955 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005956
Andreas Färber9b056fc2013-06-24 23:53:10 +02005957 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005958 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005959 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005960 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005961 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005962 if (ts->child_tidptr) {
5963 put_user_u32(0, ts->child_tidptr);
5964 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5965 NULL, NULL, 0);
5966 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005967 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005968 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005969 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04005970 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005971 pthread_exit(NULL);
5972 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005973#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005974 _mcleanup();
5975#endif
bellarde9009672005-04-26 20:42:36 +00005976 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005977 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005978 ret = 0; /* avoid warning */
5979 break;
5980 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005981 if (arg3 == 0)
5982 ret = 0;
5983 else {
5984 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5985 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01005986 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005987 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005988 fd_trans_host_to_target_data(arg1)) {
5989 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02005990 }
aurel3238d840e2009-01-30 19:48:17 +00005991 unlock_user(p, arg2, ret);
5992 }
bellard31e31b82003-02-18 22:55:36 +00005993 break;
5994 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005995 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5996 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01005997 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00005998 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005999 break;
Chen Gang704eff62015-08-21 05:37:33 +08006000#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006001 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006002 if (!(p = lock_user_string(arg1)))
6003 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006004 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6005 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6006 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006007 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006008 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006009 break;
Chen Gang704eff62015-08-21 05:37:33 +08006010#endif
ths82424832007-09-24 09:21:55 +00006011 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006012 if (!(p = lock_user_string(arg2)))
6013 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006014 ret = get_errno(do_openat(cpu_env, arg1, p,
6015 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6016 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006017 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006018 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006019 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006020#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6021 case TARGET_NR_name_to_handle_at:
6022 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6023 break;
6024#endif
6025#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6026 case TARGET_NR_open_by_handle_at:
6027 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006028 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006029 break;
6030#endif
bellard31e31b82003-02-18 22:55:36 +00006031 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006032 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006033 ret = get_errno(close(arg1));
6034 break;
6035 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006036 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006037 break;
Chen Gang704eff62015-08-21 05:37:33 +08006038#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006039 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006040 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006041 break;
Chen Gang704eff62015-08-21 05:37:33 +08006042#endif
thse5febef2007-04-01 18:31:35 +00006043#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006044 case TARGET_NR_waitpid:
6045 {
pbrook53a59602006-03-25 19:31:22 +00006046 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006047 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006048 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006049 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006050 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006051 }
6052 break;
thse5febef2007-04-01 18:31:35 +00006053#endif
pbrookf0cbb612008-05-30 18:20:05 +00006054#ifdef TARGET_NR_waitid
6055 case TARGET_NR_waitid:
6056 {
6057 siginfo_t info;
6058 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006059 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006060 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006061 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006062 goto efault;
6063 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006064 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006065 }
6066 }
6067 break;
6068#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006069#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006070 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006071 if (!(p = lock_user_string(arg1)))
6072 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006073 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006074 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006075 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006076 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006077#endif
Chen Gang704eff62015-08-21 05:37:33 +08006078#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006079 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006080 {
6081 void * p2;
6082 p = lock_user_string(arg1);
6083 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006084 if (!p || !p2)
6085 ret = -TARGET_EFAULT;
6086 else
6087 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006088 unlock_user(p2, arg2, 0);
6089 unlock_user(p, arg1, 0);
6090 }
bellard31e31b82003-02-18 22:55:36 +00006091 break;
Chen Gang704eff62015-08-21 05:37:33 +08006092#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006093#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006094 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006095 {
6096 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006097 if (!arg2 || !arg4)
6098 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006099 p = lock_user_string(arg2);
6100 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006101 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006102 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006103 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006104 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006105 unlock_user(p, arg2, 0);
6106 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006107 }
6108 break;
6109#endif
Chen Gang704eff62015-08-21 05:37:33 +08006110#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006111 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006112 if (!(p = lock_user_string(arg1)))
6113 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006114 ret = get_errno(unlink(p));
6115 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006116 break;
Chen Gang704eff62015-08-21 05:37:33 +08006117#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006118#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006119 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006120 if (!(p = lock_user_string(arg2)))
6121 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006122 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006123 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006124 break;
balrogb7d35e62007-12-12 00:40:24 +00006125#endif
bellard31e31b82003-02-18 22:55:36 +00006126 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006127 {
6128 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006129 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006130 abi_ulong gp;
6131 abi_ulong guest_argp;
6132 abi_ulong guest_envp;
6133 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006134 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006135 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006136
bellardf7341ff2003-03-30 21:00:25 +00006137 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006138 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006139 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006140 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006141 goto efault;
ths03aa1972007-12-02 06:28:08 +00006142 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006143 break;
bellard7854b052003-03-29 17:22:23 +00006144 argc++;
bellard2f619692007-11-16 10:46:05 +00006145 }
bellardf7341ff2003-03-30 21:00:25 +00006146 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006147 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006148 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006149 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006150 goto efault;
ths03aa1972007-12-02 06:28:08 +00006151 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006152 break;
bellard7854b052003-03-29 17:22:23 +00006153 envc++;
bellard2f619692007-11-16 10:46:05 +00006154 }
bellard7854b052003-03-29 17:22:23 +00006155
bellardf7341ff2003-03-30 21:00:25 +00006156 argp = alloca((argc + 1) * sizeof(void *));
6157 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006158
pbrookda94d262008-05-30 18:24:00 +00006159 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006160 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006161 if (get_user_ual(addr, gp))
6162 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006163 if (!addr)
6164 break;
bellard2f619692007-11-16 10:46:05 +00006165 if (!(*q = lock_user_string(addr)))
6166 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006167 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006168 }
bellardf7341ff2003-03-30 21:00:25 +00006169 *q = NULL;
6170
pbrookda94d262008-05-30 18:24:00 +00006171 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006172 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006173 if (get_user_ual(addr, gp))
6174 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006175 if (!addr)
6176 break;
bellard2f619692007-11-16 10:46:05 +00006177 if (!(*q = lock_user_string(addr)))
6178 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006179 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006180 }
bellardf7341ff2003-03-30 21:00:25 +00006181 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006182
bellard2f619692007-11-16 10:46:05 +00006183 if (!(p = lock_user_string(arg1)))
6184 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01006185 /* Although execve() is not an interruptible syscall it is
6186 * a special case where we must use the safe_syscall wrapper:
6187 * if we allow a signal to happen before we make the host
6188 * syscall then we will 'lose' it, because at the point of
6189 * execve the process leaves QEMU's control. So we use the
6190 * safe syscall wrapper to ensure that we either take the
6191 * signal as a guest signal, or else it does not happen
6192 * before the execve completes and makes it the other
6193 * program's problem.
6194 */
6195 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00006196 unlock_user(p, arg1, 0);
6197
bellard2f619692007-11-16 10:46:05 +00006198 goto execve_end;
6199
6200 execve_efault:
6201 ret = -TARGET_EFAULT;
6202
6203 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006204 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006205 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006206 if (get_user_ual(addr, gp)
6207 || !addr)
6208 break;
pbrook53a59602006-03-25 19:31:22 +00006209 unlock_user(*q, addr, 0);
6210 }
6211 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006212 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006213 if (get_user_ual(addr, gp)
6214 || !addr)
6215 break;
pbrook53a59602006-03-25 19:31:22 +00006216 unlock_user(*q, addr, 0);
6217 }
bellard7854b052003-03-29 17:22:23 +00006218 }
bellard31e31b82003-02-18 22:55:36 +00006219 break;
6220 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006221 if (!(p = lock_user_string(arg1)))
6222 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006223 ret = get_errno(chdir(p));
6224 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006225 break;
bellarda315a142005-01-30 22:59:18 +00006226#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006227 case TARGET_NR_time:
6228 {
pbrook53a59602006-03-25 19:31:22 +00006229 time_t host_time;
6230 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006231 if (!is_error(ret)
6232 && arg1
6233 && put_user_sal(host_time, arg1))
6234 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006235 }
6236 break;
bellarda315a142005-01-30 22:59:18 +00006237#endif
Chen Gang704eff62015-08-21 05:37:33 +08006238#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006239 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006240 if (!(p = lock_user_string(arg1)))
6241 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006242 ret = get_errno(mknod(p, arg2, arg3));
6243 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006244 break;
Chen Gang704eff62015-08-21 05:37:33 +08006245#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006246#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006247 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006248 if (!(p = lock_user_string(arg2)))
6249 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006250 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00006251 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00006252 break;
6253#endif
Chen Gang704eff62015-08-21 05:37:33 +08006254#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00006255 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00006256 if (!(p = lock_user_string(arg1)))
6257 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006258 ret = get_errno(chmod(p, arg2));
6259 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006260 break;
Chen Gang704eff62015-08-21 05:37:33 +08006261#endif
bellardebc05482003-09-30 21:08:41 +00006262#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00006263 case TARGET_NR_break:
6264 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006265#endif
6266#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00006267 case TARGET_NR_oldstat:
6268 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006269#endif
bellard31e31b82003-02-18 22:55:36 +00006270 case TARGET_NR_lseek:
6271 ret = get_errno(lseek(arg1, arg2, arg3));
6272 break;
Richard Henderson92317332010-05-03 10:07:53 -07006273#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
6274 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00006275 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07006276 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00006277 ret = get_errno(getpid());
6278 break;
Richard Henderson92317332010-05-03 10:07:53 -07006279#endif
6280#ifdef TARGET_NR_getpid
6281 case TARGET_NR_getpid:
6282 ret = get_errno(getpid());
6283 break;
6284#endif
bellard31e31b82003-02-18 22:55:36 +00006285 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01006286 {
6287 /* need to look at the data field */
6288 void *p2, *p3;
6289
6290 if (arg1) {
6291 p = lock_user_string(arg1);
6292 if (!p) {
6293 goto efault;
6294 }
6295 } else {
6296 p = NULL;
6297 }
6298
6299 p2 = lock_user_string(arg2);
6300 if (!p2) {
6301 if (arg1) {
6302 unlock_user(p, arg1, 0);
6303 }
6304 goto efault;
6305 }
6306
6307 if (arg3) {
6308 p3 = lock_user_string(arg3);
6309 if (!p3) {
6310 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006311 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01006312 }
6313 unlock_user(p2, arg2, 0);
6314 goto efault;
6315 }
6316 } else {
6317 p3 = NULL;
6318 }
6319
6320 /* FIXME - arg5 should be locked, but it isn't clear how to
6321 * do that since it's not guaranteed to be a NULL-terminated
6322 * string.
6323 */
6324 if (!arg5) {
6325 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
6326 } else {
6327 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
6328 }
6329 ret = get_errno(ret);
6330
6331 if (arg1) {
6332 unlock_user(p, arg1, 0);
6333 }
6334 unlock_user(p2, arg2, 0);
6335 if (arg3) {
6336 unlock_user(p3, arg3, 0);
6337 }
6338 }
6339 break;
thse5febef2007-04-01 18:31:35 +00006340#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00006341 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00006342 if (!(p = lock_user_string(arg1)))
6343 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006344 ret = get_errno(umount(p));
6345 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006346 break;
thse5febef2007-04-01 18:31:35 +00006347#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006348#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006349 case TARGET_NR_stime:
6350 {
pbrook53a59602006-03-25 19:31:22 +00006351 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00006352 if (get_user_sal(host_time, arg1))
6353 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006354 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00006355 }
6356 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006357#endif
bellard31e31b82003-02-18 22:55:36 +00006358 case TARGET_NR_ptrace:
6359 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00006360#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006361 case TARGET_NR_alarm:
6362 ret = alarm(arg1);
6363 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006364#endif
bellardebc05482003-09-30 21:08:41 +00006365#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00006366 case TARGET_NR_oldfstat:
6367 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006368#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006369#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006370 case TARGET_NR_pause:
6371 ret = get_errno(pause());
6372 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006373#endif
thse5febef2007-04-01 18:31:35 +00006374#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00006375 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00006376 {
pbrook53a59602006-03-25 19:31:22 +00006377 struct utimbuf tbuf, *host_tbuf;
6378 struct target_utimbuf *target_tbuf;
6379 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006380 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
6381 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006382 tbuf.actime = tswapal(target_tbuf->actime);
6383 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00006384 unlock_user_struct(target_tbuf, arg2, 0);
6385 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00006386 } else {
pbrook53a59602006-03-25 19:31:22 +00006387 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00006388 }
bellard579a97f2007-11-11 14:26:47 +00006389 if (!(p = lock_user_string(arg1)))
6390 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006391 ret = get_errno(utime(p, host_tbuf));
6392 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00006393 }
6394 break;
thse5febef2007-04-01 18:31:35 +00006395#endif
Chen Gang704eff62015-08-21 05:37:33 +08006396#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00006397 case TARGET_NR_utimes:
6398 {
bellard978a66f2004-12-06 22:58:05 +00006399 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00006400 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00006401 if (copy_from_user_timeval(&tv[0], arg2)
6402 || copy_from_user_timeval(&tv[1],
6403 arg2 + sizeof(struct target_timeval)))
6404 goto efault;
bellard978a66f2004-12-06 22:58:05 +00006405 tvp = tv;
6406 } else {
6407 tvp = NULL;
6408 }
bellard579a97f2007-11-11 14:26:47 +00006409 if (!(p = lock_user_string(arg1)))
6410 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006411 ret = get_errno(utimes(p, tvp));
6412 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00006413 }
6414 break;
Chen Gang704eff62015-08-21 05:37:33 +08006415#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006416#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00006417 case TARGET_NR_futimesat:
6418 {
6419 struct timeval *tvp, tv[2];
6420 if (arg3) {
6421 if (copy_from_user_timeval(&tv[0], arg3)
6422 || copy_from_user_timeval(&tv[1],
6423 arg3 + sizeof(struct target_timeval)))
6424 goto efault;
6425 tvp = tv;
6426 } else {
6427 tvp = NULL;
6428 }
6429 if (!(p = lock_user_string(arg2)))
6430 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006431 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00006432 unlock_user(p, arg2, 0);
6433 }
6434 break;
6435#endif
bellardebc05482003-09-30 21:08:41 +00006436#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00006437 case TARGET_NR_stty:
6438 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006439#endif
6440#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00006441 case TARGET_NR_gtty:
6442 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006443#endif
Chen Gang704eff62015-08-21 05:37:33 +08006444#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00006445 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00006446 if (!(p = lock_user_string(arg1)))
6447 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02006448 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00006449 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006450 break;
Chen Gang704eff62015-08-21 05:37:33 +08006451#endif
ths92a34c12007-09-24 09:27:49 +00006452#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
6453 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00006454 if (!(p = lock_user_string(arg2)))
6455 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006456 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006457 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00006458 break;
6459#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006460#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006461 case TARGET_NR_nice:
6462 ret = get_errno(nice(arg1));
6463 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006464#endif
bellardebc05482003-09-30 21:08:41 +00006465#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00006466 case TARGET_NR_ftime:
6467 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006468#endif
bellard31e31b82003-02-18 22:55:36 +00006469 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00006470 sync();
6471 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00006472 break;
6473 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00006474 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00006475 break;
Chen Gang704eff62015-08-21 05:37:33 +08006476#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00006477 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00006478 {
6479 void *p2;
6480 p = lock_user_string(arg1);
6481 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006482 if (!p || !p2)
6483 ret = -TARGET_EFAULT;
6484 else
6485 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006486 unlock_user(p2, arg2, 0);
6487 unlock_user(p, arg1, 0);
6488 }
bellard31e31b82003-02-18 22:55:36 +00006489 break;
Chen Gang704eff62015-08-21 05:37:33 +08006490#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006491#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006492 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006493 {
bellard579a97f2007-11-11 14:26:47 +00006494 void *p2;
ths722183f2007-09-24 09:24:37 +00006495 p = lock_user_string(arg2);
6496 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006497 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006498 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006499 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006500 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006501 unlock_user(p2, arg4, 0);
6502 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006503 }
6504 break;
6505#endif
Chen Gang704eff62015-08-21 05:37:33 +08006506#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00006507 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006508 if (!(p = lock_user_string(arg1)))
6509 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006510 ret = get_errno(mkdir(p, arg2));
6511 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006512 break;
Chen Gang704eff62015-08-21 05:37:33 +08006513#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006514#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006515 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006516 if (!(p = lock_user_string(arg2)))
6517 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006518 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006519 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006520 break;
6521#endif
Chen Gang704eff62015-08-21 05:37:33 +08006522#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00006523 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006524 if (!(p = lock_user_string(arg1)))
6525 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006526 ret = get_errno(rmdir(p));
6527 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006528 break;
Chen Gang704eff62015-08-21 05:37:33 +08006529#endif
bellard31e31b82003-02-18 22:55:36 +00006530 case TARGET_NR_dup:
6531 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02006532 if (ret >= 0) {
6533 fd_trans_dup(arg1, ret);
6534 }
bellard31e31b82003-02-18 22:55:36 +00006535 break;
Chen Gang704eff62015-08-21 05:37:33 +08006536#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00006537 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006538 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006539 break;
Chen Gang704eff62015-08-21 05:37:33 +08006540#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03006541#ifdef TARGET_NR_pipe2
6542 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006543 ret = do_pipe(cpu_env, arg1,
6544 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006545 break;
6546#endif
bellard31e31b82003-02-18 22:55:36 +00006547 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006548 {
pbrook53a59602006-03-25 19:31:22 +00006549 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006550 struct tms tms;
6551 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006552 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006553 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6554 if (!tmsp)
6555 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006556 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6557 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6558 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6559 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006560 }
bellardc596ed12003-07-13 17:32:31 +00006561 if (!is_error(ret))
6562 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006563 }
6564 break;
bellardebc05482003-09-30 21:08:41 +00006565#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006566 case TARGET_NR_prof:
6567 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006568#endif
thse5febef2007-04-01 18:31:35 +00006569#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006570 case TARGET_NR_signal:
6571 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006572#endif
bellard31e31b82003-02-18 22:55:36 +00006573 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006574 if (arg1 == 0) {
6575 ret = get_errno(acct(NULL));
6576 } else {
6577 if (!(p = lock_user_string(arg1)))
6578 goto efault;
6579 ret = get_errno(acct(path(p)));
6580 unlock_user(p, arg1, 0);
6581 }
pbrook24836682006-04-16 14:14:53 +00006582 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006583#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006584 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006585 if (!(p = lock_user_string(arg1)))
6586 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006587 ret = get_errno(umount2(p, arg2));
6588 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006589 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006590#endif
bellardebc05482003-09-30 21:08:41 +00006591#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006592 case TARGET_NR_lock:
6593 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006594#endif
bellard31e31b82003-02-18 22:55:36 +00006595 case TARGET_NR_ioctl:
6596 ret = do_ioctl(arg1, arg2, arg3);
6597 break;
6598 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006599 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006600 break;
bellardebc05482003-09-30 21:08:41 +00006601#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006602 case TARGET_NR_mpx:
6603 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006604#endif
bellard31e31b82003-02-18 22:55:36 +00006605 case TARGET_NR_setpgid:
6606 ret = get_errno(setpgid(arg1, arg2));
6607 break;
bellardebc05482003-09-30 21:08:41 +00006608#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006609 case TARGET_NR_ulimit:
6610 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006611#endif
6612#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006613 case TARGET_NR_oldolduname:
6614 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006615#endif
bellard31e31b82003-02-18 22:55:36 +00006616 case TARGET_NR_umask:
6617 ret = get_errno(umask(arg1));
6618 break;
6619 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006620 if (!(p = lock_user_string(arg1)))
6621 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006622 ret = get_errno(chroot(p));
6623 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006624 break;
Chen Gang704eff62015-08-21 05:37:33 +08006625#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00006626 case TARGET_NR_ustat:
6627 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08006628#endif
6629#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00006630 case TARGET_NR_dup2:
6631 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006632 if (ret >= 0) {
6633 fd_trans_dup(arg1, arg2);
6634 }
bellard31e31b82003-02-18 22:55:36 +00006635 break;
Chen Gang704eff62015-08-21 05:37:33 +08006636#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03006637#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6638 case TARGET_NR_dup3:
6639 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006640 if (ret >= 0) {
6641 fd_trans_dup(arg1, arg2);
6642 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03006643 break;
6644#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006645#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006646 case TARGET_NR_getppid:
6647 ret = get_errno(getppid());
6648 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006649#endif
Chen Gang704eff62015-08-21 05:37:33 +08006650#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00006651 case TARGET_NR_getpgrp:
6652 ret = get_errno(getpgrp());
6653 break;
Chen Gang704eff62015-08-21 05:37:33 +08006654#endif
bellard31e31b82003-02-18 22:55:36 +00006655 case TARGET_NR_setsid:
6656 ret = get_errno(setsid());
6657 break;
thse5febef2007-04-01 18:31:35 +00006658#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006659 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006660 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006661#if defined(TARGET_ALPHA)
6662 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006663 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006664 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006665 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6666 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006667 act._sa_handler = old_act->_sa_handler;
6668 target_siginitset(&act.sa_mask, old_act->sa_mask);
6669 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006670 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006671 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006672 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006673 }
6674 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006675 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006676 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6677 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006678 old_act->_sa_handler = oact._sa_handler;
6679 old_act->sa_mask = oact.sa_mask.sig[0];
6680 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006681 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006682 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006683#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006684 struct target_sigaction act, oact, *pact, *old_act;
6685
6686 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006687 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6688 goto efault;
bellard106ec872006-06-27 21:08:10 +00006689 act._sa_handler = old_act->_sa_handler;
6690 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6691 act.sa_flags = old_act->sa_flags;
6692 unlock_user_struct(old_act, arg2, 0);
6693 pact = &act;
6694 } else {
6695 pact = NULL;
6696 }
6697
6698 ret = get_errno(do_sigaction(arg1, pact, &oact));
6699
6700 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006701 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6702 goto efault;
bellard106ec872006-06-27 21:08:10 +00006703 old_act->_sa_handler = oact._sa_handler;
6704 old_act->sa_flags = oact.sa_flags;
6705 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6706 old_act->sa_mask.sig[1] = 0;
6707 old_act->sa_mask.sig[2] = 0;
6708 old_act->sa_mask.sig[3] = 0;
6709 unlock_user_struct(old_act, arg3, 1);
6710 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006711#else
6712 struct target_old_sigaction *old_act;
6713 struct target_sigaction act, oact, *pact;
6714 if (arg2) {
6715 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6716 goto efault;
6717 act._sa_handler = old_act->_sa_handler;
6718 target_siginitset(&act.sa_mask, old_act->sa_mask);
6719 act.sa_flags = old_act->sa_flags;
6720 act.sa_restorer = old_act->sa_restorer;
6721 unlock_user_struct(old_act, arg2, 0);
6722 pact = &act;
6723 } else {
6724 pact = NULL;
6725 }
6726 ret = get_errno(do_sigaction(arg1, pact, &oact));
6727 if (!is_error(ret) && arg3) {
6728 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6729 goto efault;
6730 old_act->_sa_handler = oact._sa_handler;
6731 old_act->sa_mask = oact.sa_mask.sig[0];
6732 old_act->sa_flags = oact.sa_flags;
6733 old_act->sa_restorer = oact.sa_restorer;
6734 unlock_user_struct(old_act, arg3, 1);
6735 }
ths388bb212007-05-13 13:58:00 +00006736#endif
bellard31e31b82003-02-18 22:55:36 +00006737 }
6738 break;
thse5febef2007-04-01 18:31:35 +00006739#endif
bellard66fb9762003-03-23 01:06:05 +00006740 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006741 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006742#if defined(TARGET_ALPHA)
6743 struct target_sigaction act, oact, *pact = 0;
6744 struct target_rt_sigaction *rt_act;
6745 /* ??? arg4 == sizeof(sigset_t). */
6746 if (arg2) {
6747 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6748 goto efault;
6749 act._sa_handler = rt_act->_sa_handler;
6750 act.sa_mask = rt_act->sa_mask;
6751 act.sa_flags = rt_act->sa_flags;
6752 act.sa_restorer = arg5;
6753 unlock_user_struct(rt_act, arg2, 0);
6754 pact = &act;
6755 }
6756 ret = get_errno(do_sigaction(arg1, pact, &oact));
6757 if (!is_error(ret) && arg3) {
6758 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6759 goto efault;
6760 rt_act->_sa_handler = oact._sa_handler;
6761 rt_act->sa_mask = oact.sa_mask;
6762 rt_act->sa_flags = oact.sa_flags;
6763 unlock_user_struct(rt_act, arg3, 1);
6764 }
6765#else
pbrook53a59602006-03-25 19:31:22 +00006766 struct target_sigaction *act;
6767 struct target_sigaction *oact;
6768
bellard579a97f2007-11-11 14:26:47 +00006769 if (arg2) {
6770 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6771 goto efault;
6772 } else
pbrook53a59602006-03-25 19:31:22 +00006773 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006774 if (arg3) {
6775 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6776 ret = -TARGET_EFAULT;
6777 goto rt_sigaction_fail;
6778 }
6779 } else
pbrook53a59602006-03-25 19:31:22 +00006780 oact = NULL;
6781 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006782 rt_sigaction_fail:
6783 if (act)
pbrook53a59602006-03-25 19:31:22 +00006784 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006785 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006786 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006787#endif
pbrook53a59602006-03-25 19:31:22 +00006788 }
bellard66fb9762003-03-23 01:06:05 +00006789 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006790#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006791 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006792 {
6793 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006794 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006795 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006796 host_to_target_old_sigset(&target_set, &cur_set);
6797 ret = target_set;
6798 }
6799 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006800#endif
6801#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006802 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006803 {
6804 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006805 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006806 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006807 target_to_host_old_sigset(&set, &target_set);
6808 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006809 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006810 host_to_target_old_sigset(&target_set, &oset);
6811 ret = target_set;
6812 }
6813 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006814#endif
thse5febef2007-04-01 18:31:35 +00006815#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006816 case TARGET_NR_sigprocmask:
6817 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006818#if defined(TARGET_ALPHA)
6819 sigset_t set, oldset;
6820 abi_ulong mask;
6821 int how;
6822
6823 switch (arg1) {
6824 case TARGET_SIG_BLOCK:
6825 how = SIG_BLOCK;
6826 break;
6827 case TARGET_SIG_UNBLOCK:
6828 how = SIG_UNBLOCK;
6829 break;
6830 case TARGET_SIG_SETMASK:
6831 how = SIG_SETMASK;
6832 break;
6833 default:
6834 ret = -TARGET_EINVAL;
6835 goto fail;
6836 }
6837 mask = arg2;
6838 target_to_host_old_sigset(&set, &mask);
6839
Alex Barcelo1c275922014-03-14 14:36:55 +00006840 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006841 if (!is_error(ret)) {
6842 host_to_target_old_sigset(&mask, &oldset);
6843 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006844 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006845 }
6846#else
bellard66fb9762003-03-23 01:06:05 +00006847 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006848 int how;
ths3b46e622007-09-17 08:09:54 +00006849
pbrook53a59602006-03-25 19:31:22 +00006850 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006851 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006852 case TARGET_SIG_BLOCK:
6853 how = SIG_BLOCK;
6854 break;
6855 case TARGET_SIG_UNBLOCK:
6856 how = SIG_UNBLOCK;
6857 break;
6858 case TARGET_SIG_SETMASK:
6859 how = SIG_SETMASK;
6860 break;
6861 default:
ths0da46a62007-10-20 20:23:07 +00006862 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006863 goto fail;
6864 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006865 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006866 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006867 target_to_host_old_sigset(&set, p);
6868 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006869 set_ptr = &set;
6870 } else {
6871 how = 0;
6872 set_ptr = NULL;
6873 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006874 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006875 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006876 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006877 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006878 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006879 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006880 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006881#endif
bellard66fb9762003-03-23 01:06:05 +00006882 }
6883 break;
thse5febef2007-04-01 18:31:35 +00006884#endif
bellard66fb9762003-03-23 01:06:05 +00006885 case TARGET_NR_rt_sigprocmask:
6886 {
6887 int how = arg1;
6888 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006889
pbrook53a59602006-03-25 19:31:22 +00006890 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006891 switch(how) {
6892 case TARGET_SIG_BLOCK:
6893 how = SIG_BLOCK;
6894 break;
6895 case TARGET_SIG_UNBLOCK:
6896 how = SIG_UNBLOCK;
6897 break;
6898 case TARGET_SIG_SETMASK:
6899 how = SIG_SETMASK;
6900 break;
6901 default:
ths0da46a62007-10-20 20:23:07 +00006902 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006903 goto fail;
6904 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006905 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006906 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006907 target_to_host_sigset(&set, p);
6908 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006909 set_ptr = &set;
6910 } else {
6911 how = 0;
6912 set_ptr = NULL;
6913 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006914 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006915 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006916 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006917 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006918 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006919 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006920 }
6921 }
6922 break;
thse5febef2007-04-01 18:31:35 +00006923#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006924 case TARGET_NR_sigpending:
6925 {
6926 sigset_t set;
6927 ret = get_errno(sigpending(&set));
6928 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006929 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006930 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006931 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006932 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006933 }
6934 }
6935 break;
thse5febef2007-04-01 18:31:35 +00006936#endif
bellard66fb9762003-03-23 01:06:05 +00006937 case TARGET_NR_rt_sigpending:
6938 {
6939 sigset_t set;
6940 ret = get_errno(sigpending(&set));
6941 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006942 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006943 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006944 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006945 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006946 }
6947 }
6948 break;
thse5febef2007-04-01 18:31:35 +00006949#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006950 case TARGET_NR_sigsuspend:
6951 {
6952 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006953#if defined(TARGET_ALPHA)
6954 abi_ulong mask = arg1;
6955 target_to_host_old_sigset(&set, &mask);
6956#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006957 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006958 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006959 target_to_host_old_sigset(&set, p);
6960 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006961#endif
bellard66fb9762003-03-23 01:06:05 +00006962 ret = get_errno(sigsuspend(&set));
6963 }
6964 break;
thse5febef2007-04-01 18:31:35 +00006965#endif
bellard66fb9762003-03-23 01:06:05 +00006966 case TARGET_NR_rt_sigsuspend:
6967 {
6968 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006969 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006970 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006971 target_to_host_sigset(&set, p);
6972 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006973 ret = get_errno(sigsuspend(&set));
6974 }
6975 break;
6976 case TARGET_NR_rt_sigtimedwait:
6977 {
bellard66fb9762003-03-23 01:06:05 +00006978 sigset_t set;
6979 struct timespec uts, *puts;
6980 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006981
Anthony Liguoric227f092009-10-01 16:12:16 -05006982 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006983 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006984 target_to_host_sigset(&set, p);
6985 unlock_user(p, arg1, 0);
6986 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006987 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006988 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006989 } else {
6990 puts = NULL;
6991 }
6992 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006993 if (!is_error(ret)) {
6994 if (arg2) {
6995 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6996 0);
6997 if (!p) {
6998 goto efault;
6999 }
7000 host_to_target_siginfo(p, &uinfo);
7001 unlock_user(p, arg2, sizeof(target_siginfo_t));
7002 }
7003 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007004 }
7005 }
7006 break;
7007 case TARGET_NR_rt_sigqueueinfo:
7008 {
7009 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05007010 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007011 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007012 target_to_host_siginfo(&uinfo, p);
7013 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007014 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7015 }
7016 break;
thse5febef2007-04-01 18:31:35 +00007017#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007018 case TARGET_NR_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007019 ret = do_sigreturn(cpu_env);
7020 break;
thse5febef2007-04-01 18:31:35 +00007021#endif
bellard66fb9762003-03-23 01:06:05 +00007022 case TARGET_NR_rt_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007023 ret = do_rt_sigreturn(cpu_env);
7024 break;
bellard31e31b82003-02-18 22:55:36 +00007025 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007026 if (!(p = lock_user_string(arg1)))
7027 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007028 ret = get_errno(sethostname(p, arg2));
7029 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007030 break;
7031 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007032 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007033 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007034 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007035 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007036 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7037 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007038 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7039 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007040 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007041 ret = get_errno(setrlimit(resource, &rlim));
7042 }
7043 break;
bellard31e31b82003-02-18 22:55:36 +00007044 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007045 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007046 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007047 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007048 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007049
bellard9de5e442003-03-23 16:49:39 +00007050 ret = get_errno(getrlimit(resource, &rlim));
7051 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007052 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7053 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007054 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7055 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007056 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007057 }
7058 }
7059 break;
bellard31e31b82003-02-18 22:55:36 +00007060 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007061 {
7062 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007063 ret = get_errno(getrusage(arg1, &rusage));
7064 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007065 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007066 }
7067 }
7068 break;
bellard31e31b82003-02-18 22:55:36 +00007069 case TARGET_NR_gettimeofday:
7070 {
bellard31e31b82003-02-18 22:55:36 +00007071 struct timeval tv;
7072 ret = get_errno(gettimeofday(&tv, NULL));
7073 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007074 if (copy_to_user_timeval(arg1, &tv))
7075 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007076 }
7077 }
7078 break;
7079 case TARGET_NR_settimeofday:
7080 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007081 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007082 struct timezone tz, *ptz = NULL;
7083
Paul Burtonb67d8032014-06-22 11:25:41 +01007084 if (arg1) {
7085 if (copy_from_user_timeval(&tv, arg1)) {
7086 goto efault;
7087 }
7088 ptv = &tv;
7089 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007090
7091 if (arg2) {
7092 if (copy_from_user_timezone(&tz, arg2)) {
7093 goto efault;
7094 }
7095 ptz = &tz;
7096 }
7097
Paul Burtonb67d8032014-06-22 11:25:41 +01007098 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007099 }
7100 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007101#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007102 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007103#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7104 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7105#else
bellardf2674e32003-07-09 12:26:09 +00007106 {
pbrook53a59602006-03-25 19:31:22 +00007107 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007108 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007109 long nsel;
7110
bellard579a97f2007-11-11 14:26:47 +00007111 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7112 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007113 nsel = tswapal(sel->n);
7114 inp = tswapal(sel->inp);
7115 outp = tswapal(sel->outp);
7116 exp = tswapal(sel->exp);
7117 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007118 unlock_user_struct(sel, arg1, 0);
7119 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007120 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007121#endif
bellardf2674e32003-07-09 12:26:09 +00007122 break;
bellard048f6b42005-11-26 18:47:20 +00007123#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007124#ifdef TARGET_NR_pselect6
7125 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007126 {
7127 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7128 fd_set rfds, wfds, efds;
7129 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7130 struct timespec ts, *ts_ptr;
7131
7132 /*
7133 * The 6th arg is actually two args smashed together,
7134 * so we cannot use the C library.
7135 */
7136 sigset_t set;
7137 struct {
7138 sigset_t *set;
7139 size_t size;
7140 } sig, *sig_ptr;
7141
7142 abi_ulong arg_sigset, arg_sigsize, *arg7;
7143 target_sigset_t *target_sigset;
7144
7145 n = arg1;
7146 rfd_addr = arg2;
7147 wfd_addr = arg3;
7148 efd_addr = arg4;
7149 ts_addr = arg5;
7150
7151 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7152 if (ret) {
7153 goto fail;
7154 }
7155 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7156 if (ret) {
7157 goto fail;
7158 }
7159 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7160 if (ret) {
7161 goto fail;
7162 }
7163
7164 /*
7165 * This takes a timespec, and not a timeval, so we cannot
7166 * use the do_select() helper ...
7167 */
7168 if (ts_addr) {
7169 if (target_to_host_timespec(&ts, ts_addr)) {
7170 goto efault;
7171 }
7172 ts_ptr = &ts;
7173 } else {
7174 ts_ptr = NULL;
7175 }
7176
7177 /* Extract the two packed args for the sigset */
7178 if (arg6) {
7179 sig_ptr = &sig;
7180 sig.size = _NSIG / 8;
7181
7182 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7183 if (!arg7) {
7184 goto efault;
7185 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007186 arg_sigset = tswapal(arg7[0]);
7187 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007188 unlock_user(arg7, arg6, 0);
7189
7190 if (arg_sigset) {
7191 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007192 if (arg_sigsize != sizeof(*target_sigset)) {
7193 /* Like the kernel, we enforce correct size sigsets */
7194 ret = -TARGET_EINVAL;
7195 goto fail;
7196 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007197 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7198 sizeof(*target_sigset), 1);
7199 if (!target_sigset) {
7200 goto efault;
7201 }
7202 target_to_host_sigset(&set, target_sigset);
7203 unlock_user(target_sigset, arg_sigset, 0);
7204 } else {
7205 sig.set = NULL;
7206 }
7207 } else {
7208 sig_ptr = NULL;
7209 }
7210
Peter Maydell6df9d382016-05-12 18:47:51 +01007211 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7212 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04007213
7214 if (!is_error(ret)) {
7215 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7216 goto efault;
7217 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7218 goto efault;
7219 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7220 goto efault;
7221
7222 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
7223 goto efault;
7224 }
7225 }
7226 break;
Riku Voipio9e423822010-05-07 12:28:05 +00007227#endif
Chen Gang704eff62015-08-21 05:37:33 +08007228#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00007229 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00007230 {
7231 void *p2;
7232 p = lock_user_string(arg1);
7233 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007234 if (!p || !p2)
7235 ret = -TARGET_EFAULT;
7236 else
7237 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007238 unlock_user(p2, arg2, 0);
7239 unlock_user(p, arg1, 0);
7240 }
bellard31e31b82003-02-18 22:55:36 +00007241 break;
Chen Gang704eff62015-08-21 05:37:33 +08007242#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007243#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00007244 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00007245 {
bellard579a97f2007-11-11 14:26:47 +00007246 void *p2;
thsf0b62432007-09-24 09:25:40 +00007247 p = lock_user_string(arg1);
7248 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00007249 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007250 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00007251 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007252 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00007253 unlock_user(p2, arg3, 0);
7254 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00007255 }
7256 break;
7257#endif
bellardebc05482003-09-30 21:08:41 +00007258#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00007259 case TARGET_NR_oldlstat:
7260 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007261#endif
Chen Gang704eff62015-08-21 05:37:33 +08007262#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00007263 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00007264 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01007265 void *p2;
pbrook53a59602006-03-25 19:31:22 +00007266 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00007267 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007268 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00007269 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09007270 } else if (!arg3) {
7271 /* Short circuit this for the magic exe check. */
7272 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01007273 } else if (is_proc_myself((const char *)p, "exe")) {
7274 char real[PATH_MAX], *temp;
7275 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09007276 /* Return value is # of bytes that we wrote to the buffer. */
7277 if (temp == NULL) {
7278 ret = get_errno(-1);
7279 } else {
7280 /* Don't worry about sign mismatch as earlier mapping
7281 * logic would have thrown a bad address error. */
7282 ret = MIN(strlen(real), arg3);
7283 /* We cannot NUL terminate the string. */
7284 memcpy(p2, real, ret);
7285 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01007286 } else {
7287 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00007288 }
pbrook53a59602006-03-25 19:31:22 +00007289 unlock_user(p2, arg2, ret);
7290 unlock_user(p, arg1, 0);
7291 }
bellard31e31b82003-02-18 22:55:36 +00007292 break;
Chen Gang704eff62015-08-21 05:37:33 +08007293#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007294#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00007295 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00007296 {
bellard579a97f2007-11-11 14:26:47 +00007297 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00007298 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007299 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007300 if (!p || !p2) {
7301 ret = -TARGET_EFAULT;
7302 } else if (is_proc_myself((const char *)p, "exe")) {
7303 char real[PATH_MAX], *temp;
7304 temp = realpath(exec_path, real);
7305 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
7306 snprintf((char *)p2, arg4, "%s", real);
7307 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01007308 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01007309 }
bellard579a97f2007-11-11 14:26:47 +00007310 unlock_user(p2, arg3, ret);
7311 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00007312 }
7313 break;
7314#endif
thse5febef2007-04-01 18:31:35 +00007315#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00007316 case TARGET_NR_uselib:
7317 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007318#endif
7319#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00007320 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00007321 if (!(p = lock_user_string(arg1)))
7322 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007323 ret = get_errno(swapon(p, arg2));
7324 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007325 break;
thse5febef2007-04-01 18:31:35 +00007326#endif
bellard31e31b82003-02-18 22:55:36 +00007327 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00007328 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
7329 /* arg4 must be ignored in all other cases */
7330 p = lock_user_string(arg4);
7331 if (!p) {
7332 goto efault;
7333 }
7334 ret = get_errno(reboot(arg1, arg2, arg3, p));
7335 unlock_user(p, arg4, 0);
7336 } else {
7337 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
7338 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02007339 break;
thse5febef2007-04-01 18:31:35 +00007340#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00007341 case TARGET_NR_readdir:
7342 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007343#endif
7344#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00007345 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01007346#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7347 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007348 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
7349 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00007350 {
blueswir1992f48a2007-10-14 16:27:31 +00007351 abi_ulong *v;
7352 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00007353 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
7354 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007355 v1 = tswapal(v[0]);
7356 v2 = tswapal(v[1]);
7357 v3 = tswapal(v[2]);
7358 v4 = tswapal(v[3]);
7359 v5 = tswapal(v[4]);
7360 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00007361 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00007362 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00007363 target_to_host_bitmask(v4, mmap_flags_tbl),
7364 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00007365 }
bellard31e31b82003-02-18 22:55:36 +00007366#else
ths5fafdf22007-09-16 21:08:06 +00007367 ret = get_errno(target_mmap(arg1, arg2, arg3,
7368 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00007369 arg5,
7370 arg6));
bellard31e31b82003-02-18 22:55:36 +00007371#endif
bellard6fb883e2003-07-09 17:12:39 +00007372 break;
thse5febef2007-04-01 18:31:35 +00007373#endif
bellarda315a142005-01-30 22:59:18 +00007374#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00007375 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00007376#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00007377#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00007378#endif
ths5fafdf22007-09-16 21:08:06 +00007379 ret = get_errno(target_mmap(arg1, arg2, arg3,
7380 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00007381 arg5,
bellardc573ff62004-01-04 15:51:36 +00007382 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00007383 break;
bellarda315a142005-01-30 22:59:18 +00007384#endif
bellard31e31b82003-02-18 22:55:36 +00007385 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00007386 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007387 break;
bellard9de5e442003-03-23 16:49:39 +00007388 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01007389 {
Andreas Färber0429a972013-08-26 18:14:44 +02007390 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01007391 /* Special hack to detect libc making the stack executable. */
7392 if ((arg3 & PROT_GROWSDOWN)
7393 && arg1 >= ts->info->stack_limit
7394 && arg1 <= ts->info->start_stack) {
7395 arg3 &= ~PROT_GROWSDOWN;
7396 arg2 = arg2 + arg1 - ts->info->stack_limit;
7397 arg1 = ts->info->stack_limit;
7398 }
7399 }
bellard54936002003-05-13 00:25:15 +00007400 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007401 break;
thse5febef2007-04-01 18:31:35 +00007402#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00007403 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00007404 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00007405 break;
thse5febef2007-04-01 18:31:35 +00007406#endif
pbrook53a59602006-03-25 19:31:22 +00007407 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00007408#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00007409 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00007410 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007411 break;
thse5febef2007-04-01 18:31:35 +00007412#endif
7413#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00007414 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00007415 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007416 break;
thse5febef2007-04-01 18:31:35 +00007417#endif
7418#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00007419 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00007420 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007421 break;
thse5febef2007-04-01 18:31:35 +00007422#endif
7423#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00007424 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05007425 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00007426 break;
thse5febef2007-04-01 18:31:35 +00007427#endif
7428#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00007429 case TARGET_NR_munlockall:
7430 ret = get_errno(munlockall());
7431 break;
thse5febef2007-04-01 18:31:35 +00007432#endif
bellard31e31b82003-02-18 22:55:36 +00007433 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00007434 if (!(p = lock_user_string(arg1)))
7435 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007436 ret = get_errno(truncate(p, arg2));
7437 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007438 break;
7439 case TARGET_NR_ftruncate:
7440 ret = get_errno(ftruncate(arg1, arg2));
7441 break;
7442 case TARGET_NR_fchmod:
7443 ret = get_errno(fchmod(arg1, arg2));
7444 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007445#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00007446 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00007447 if (!(p = lock_user_string(arg2)))
7448 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007449 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007450 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00007451 break;
7452#endif
bellard31e31b82003-02-18 22:55:36 +00007453 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07007454 /* Note that negative values are valid for getpriority, so we must
7455 differentiate based on errno settings. */
7456 errno = 0;
7457 ret = getpriority(arg1, arg2);
7458 if (ret == -1 && errno != 0) {
7459 ret = -host_to_target_errno(errno);
7460 break;
7461 }
7462#ifdef TARGET_ALPHA
7463 /* Return value is the unbiased priority. Signal no error. */
7464 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
7465#else
7466 /* Return value is a biased priority to avoid negative numbers. */
7467 ret = 20 - ret;
7468#endif
bellard31e31b82003-02-18 22:55:36 +00007469 break;
7470 case TARGET_NR_setpriority:
7471 ret = get_errno(setpriority(arg1, arg2, arg3));
7472 break;
bellardebc05482003-09-30 21:08:41 +00007473#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00007474 case TARGET_NR_profil:
7475 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007476#endif
bellard31e31b82003-02-18 22:55:36 +00007477 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00007478 if (!(p = lock_user_string(arg1)))
7479 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007480 ret = get_errno(statfs(path(p), &stfs));
7481 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007482 convert_statfs:
7483 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007484 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007485
bellard579a97f2007-11-11 14:26:47 +00007486 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
7487 goto efault;
7488 __put_user(stfs.f_type, &target_stfs->f_type);
7489 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7490 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7491 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7492 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7493 __put_user(stfs.f_files, &target_stfs->f_files);
7494 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7495 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7496 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7497 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007498 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7499 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00007500 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007501 }
7502 break;
7503 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00007504 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00007505 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00007506#ifdef TARGET_NR_statfs64
7507 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00007508 if (!(p = lock_user_string(arg1)))
7509 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007510 ret = get_errno(statfs(path(p), &stfs));
7511 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00007512 convert_statfs64:
7513 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007514 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007515
bellard579a97f2007-11-11 14:26:47 +00007516 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7517 goto efault;
7518 __put_user(stfs.f_type, &target_stfs->f_type);
7519 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7520 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7521 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7522 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7523 __put_user(stfs.f_files, &target_stfs->f_files);
7524 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7525 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7526 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7527 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007528 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7529 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007530 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007531 }
7532 break;
7533 case TARGET_NR_fstatfs64:
7534 ret = get_errno(fstatfs(arg1, &stfs));
7535 goto convert_statfs64;
7536#endif
bellardebc05482003-09-30 21:08:41 +00007537#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007538 case TARGET_NR_ioperm:
7539 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007540#endif
thse5febef2007-04-01 18:31:35 +00007541#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007542 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007543 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007544 break;
thse5febef2007-04-01 18:31:35 +00007545#endif
bellard3532fa72006-06-24 15:06:03 +00007546#ifdef TARGET_NR_accept
7547 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007548 ret = do_accept4(arg1, arg2, arg3, 0);
7549 break;
7550#endif
7551#ifdef TARGET_NR_accept4
7552 case TARGET_NR_accept4:
7553#ifdef CONFIG_ACCEPT4
7554 ret = do_accept4(arg1, arg2, arg3, arg4);
7555#else
7556 goto unimplemented;
7557#endif
bellard3532fa72006-06-24 15:06:03 +00007558 break;
7559#endif
7560#ifdef TARGET_NR_bind
7561 case TARGET_NR_bind:
7562 ret = do_bind(arg1, arg2, arg3);
7563 break;
7564#endif
7565#ifdef TARGET_NR_connect
7566 case TARGET_NR_connect:
7567 ret = do_connect(arg1, arg2, arg3);
7568 break;
7569#endif
7570#ifdef TARGET_NR_getpeername
7571 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007572 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007573 break;
7574#endif
7575#ifdef TARGET_NR_getsockname
7576 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007577 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007578 break;
7579#endif
7580#ifdef TARGET_NR_getsockopt
7581 case TARGET_NR_getsockopt:
7582 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7583 break;
7584#endif
7585#ifdef TARGET_NR_listen
7586 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007587 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007588 break;
7589#endif
7590#ifdef TARGET_NR_recv
7591 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007592 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007593 break;
7594#endif
7595#ifdef TARGET_NR_recvfrom
7596 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007597 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007598 break;
7599#endif
7600#ifdef TARGET_NR_recvmsg
7601 case TARGET_NR_recvmsg:
7602 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7603 break;
7604#endif
7605#ifdef TARGET_NR_send
7606 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007607 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007608 break;
7609#endif
7610#ifdef TARGET_NR_sendmsg
7611 case TARGET_NR_sendmsg:
7612 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7613 break;
7614#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007615#ifdef TARGET_NR_sendmmsg
7616 case TARGET_NR_sendmmsg:
7617 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7618 break;
7619 case TARGET_NR_recvmmsg:
7620 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7621 break;
7622#endif
bellard3532fa72006-06-24 15:06:03 +00007623#ifdef TARGET_NR_sendto
7624 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007625 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007626 break;
7627#endif
7628#ifdef TARGET_NR_shutdown
7629 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007630 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007631 break;
7632#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01007633#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
7634 case TARGET_NR_getrandom:
7635 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
7636 if (!p) {
7637 goto efault;
7638 }
7639 ret = get_errno(getrandom(p, arg2, arg3));
7640 unlock_user(p, arg1, ret);
7641 break;
7642#endif
bellard3532fa72006-06-24 15:06:03 +00007643#ifdef TARGET_NR_socket
7644 case TARGET_NR_socket:
7645 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007646 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00007647 break;
7648#endif
7649#ifdef TARGET_NR_socketpair
7650 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007651 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007652 break;
7653#endif
7654#ifdef TARGET_NR_setsockopt
7655 case TARGET_NR_setsockopt:
7656 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7657 break;
7658#endif
ths7494b0f2007-02-11 18:26:53 +00007659
bellard31e31b82003-02-18 22:55:36 +00007660 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007661 if (!(p = lock_user_string(arg2)))
7662 goto efault;
thse5574482007-02-11 20:03:13 +00007663 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7664 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007665 break;
7666
bellard31e31b82003-02-18 22:55:36 +00007667 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007668 {
bellard66fb9762003-03-23 01:06:05 +00007669 struct itimerval value, ovalue, *pvalue;
7670
pbrook53a59602006-03-25 19:31:22 +00007671 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007672 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007673 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7674 || copy_from_user_timeval(&pvalue->it_value,
7675 arg2 + sizeof(struct target_timeval)))
7676 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007677 } else {
7678 pvalue = NULL;
7679 }
7680 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007681 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007682 if (copy_to_user_timeval(arg3,
7683 &ovalue.it_interval)
7684 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7685 &ovalue.it_value))
7686 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007687 }
7688 }
7689 break;
bellard31e31b82003-02-18 22:55:36 +00007690 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007691 {
bellard66fb9762003-03-23 01:06:05 +00007692 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007693
bellard66fb9762003-03-23 01:06:05 +00007694 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007695 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007696 if (copy_to_user_timeval(arg2,
7697 &value.it_interval)
7698 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7699 &value.it_value))
7700 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007701 }
7702 }
7703 break;
Chen Gang704eff62015-08-21 05:37:33 +08007704#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00007705 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007706 if (!(p = lock_user_string(arg1)))
7707 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007708 ret = get_errno(stat(path(p), &st));
7709 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007710 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007711#endif
7712#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00007713 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007714 if (!(p = lock_user_string(arg1)))
7715 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007716 ret = get_errno(lstat(path(p), &st));
7717 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007718 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007719#endif
bellard31e31b82003-02-18 22:55:36 +00007720 case TARGET_NR_fstat:
7721 {
7722 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08007723#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00007724 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08007725#endif
bellard31e31b82003-02-18 22:55:36 +00007726 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007727 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007728
bellard579a97f2007-11-11 14:26:47 +00007729 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7730 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007731 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007732 __put_user(st.st_dev, &target_st->st_dev);
7733 __put_user(st.st_ino, &target_st->st_ino);
7734 __put_user(st.st_mode, &target_st->st_mode);
7735 __put_user(st.st_uid, &target_st->st_uid);
7736 __put_user(st.st_gid, &target_st->st_gid);
7737 __put_user(st.st_nlink, &target_st->st_nlink);
7738 __put_user(st.st_rdev, &target_st->st_rdev);
7739 __put_user(st.st_size, &target_st->st_size);
7740 __put_user(st.st_blksize, &target_st->st_blksize);
7741 __put_user(st.st_blocks, &target_st->st_blocks);
7742 __put_user(st.st_atime, &target_st->target_st_atime);
7743 __put_user(st.st_mtime, &target_st->target_st_mtime);
7744 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007745 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007746 }
7747 }
7748 break;
bellardebc05482003-09-30 21:08:41 +00007749#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007750 case TARGET_NR_olduname:
7751 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007752#endif
7753#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007754 case TARGET_NR_iopl:
7755 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007756#endif
bellard31e31b82003-02-18 22:55:36 +00007757 case TARGET_NR_vhangup:
7758 ret = get_errno(vhangup());
7759 break;
bellardebc05482003-09-30 21:08:41 +00007760#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007761 case TARGET_NR_idle:
7762 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007763#endif
bellard42ad6ae2005-01-03 22:48:11 +00007764#ifdef TARGET_NR_syscall
7765 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007766 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7767 arg6, arg7, arg8, 0);
7768 break;
bellard42ad6ae2005-01-03 22:48:11 +00007769#endif
bellard31e31b82003-02-18 22:55:36 +00007770 case TARGET_NR_wait4:
7771 {
7772 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007773 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007774 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007775 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007776 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007777 if (target_rusage)
7778 rusage_ptr = &rusage;
7779 else
7780 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007781 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00007782 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007783 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007784 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007785 if (put_user_s32(status, status_ptr))
7786 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007787 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007788 if (target_rusage) {
7789 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7790 if (rusage_err) {
7791 ret = rusage_err;
7792 }
7793 }
bellard31e31b82003-02-18 22:55:36 +00007794 }
7795 }
7796 break;
thse5febef2007-04-01 18:31:35 +00007797#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007798 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007799 if (!(p = lock_user_string(arg1)))
7800 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007801 ret = get_errno(swapoff(p));
7802 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007803 break;
thse5febef2007-04-01 18:31:35 +00007804#endif
bellard31e31b82003-02-18 22:55:36 +00007805 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007806 {
pbrook53a59602006-03-25 19:31:22 +00007807 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007808 struct sysinfo value;
7809 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007810 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007811 {
bellard579a97f2007-11-11 14:26:47 +00007812 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7813 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007814 __put_user(value.uptime, &target_value->uptime);
7815 __put_user(value.loads[0], &target_value->loads[0]);
7816 __put_user(value.loads[1], &target_value->loads[1]);
7817 __put_user(value.loads[2], &target_value->loads[2]);
7818 __put_user(value.totalram, &target_value->totalram);
7819 __put_user(value.freeram, &target_value->freeram);
7820 __put_user(value.sharedram, &target_value->sharedram);
7821 __put_user(value.bufferram, &target_value->bufferram);
7822 __put_user(value.totalswap, &target_value->totalswap);
7823 __put_user(value.freeswap, &target_value->freeswap);
7824 __put_user(value.procs, &target_value->procs);
7825 __put_user(value.totalhigh, &target_value->totalhigh);
7826 __put_user(value.freehigh, &target_value->freehigh);
7827 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007828 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007829 }
7830 }
7831 break;
thse5febef2007-04-01 18:31:35 +00007832#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007833 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007834 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7835 break;
thse5febef2007-04-01 18:31:35 +00007836#endif
aurel32e5289082009-04-18 16:16:12 +00007837#ifdef TARGET_NR_semget
7838 case TARGET_NR_semget:
7839 ret = get_errno(semget(arg1, arg2, arg3));
7840 break;
7841#endif
7842#ifdef TARGET_NR_semop
7843 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007844 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007845 break;
7846#endif
7847#ifdef TARGET_NR_semctl
7848 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01007849 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00007850 break;
7851#endif
aurel32eeb438c2008-10-13 21:08:55 +00007852#ifdef TARGET_NR_msgctl
7853 case TARGET_NR_msgctl:
7854 ret = do_msgctl(arg1, arg2, arg3);
7855 break;
7856#endif
7857#ifdef TARGET_NR_msgget
7858 case TARGET_NR_msgget:
7859 ret = get_errno(msgget(arg1, arg2));
7860 break;
7861#endif
7862#ifdef TARGET_NR_msgrcv
7863 case TARGET_NR_msgrcv:
7864 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7865 break;
7866#endif
7867#ifdef TARGET_NR_msgsnd
7868 case TARGET_NR_msgsnd:
7869 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7870 break;
7871#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007872#ifdef TARGET_NR_shmget
7873 case TARGET_NR_shmget:
7874 ret = get_errno(shmget(arg1, arg2, arg3));
7875 break;
7876#endif
7877#ifdef TARGET_NR_shmctl
7878 case TARGET_NR_shmctl:
7879 ret = do_shmctl(arg1, arg2, arg3);
7880 break;
7881#endif
7882#ifdef TARGET_NR_shmat
7883 case TARGET_NR_shmat:
7884 ret = do_shmat(arg1, arg2, arg3);
7885 break;
7886#endif
7887#ifdef TARGET_NR_shmdt
7888 case TARGET_NR_shmdt:
7889 ret = do_shmdt(arg1);
7890 break;
7891#endif
bellard31e31b82003-02-18 22:55:36 +00007892 case TARGET_NR_fsync:
7893 ret = get_errno(fsync(arg1));
7894 break;
bellard31e31b82003-02-18 22:55:36 +00007895 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007896 /* Linux manages to have three different orderings for its
7897 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7898 * match the kernel's CONFIG_CLONE_* settings.
7899 * Microblaze is further special in that it uses a sixth
7900 * implicit argument to clone for the TLS pointer.
7901 */
7902#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007903 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007904#elif defined(TARGET_CLONE_BACKWARDS)
7905 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7906#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007907 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007908#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007909 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007910#endif
bellard1b6b0292003-03-22 17:31:38 +00007911 break;
bellardec86b0f2003-04-11 00:15:04 +00007912#ifdef __NR_exit_group
7913 /* new thread calls */
7914 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007915#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007916 _mcleanup();
7917#endif
bellarde9009672005-04-26 20:42:36 +00007918 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007919 ret = get_errno(exit_group(arg1));
7920 break;
7921#endif
bellard31e31b82003-02-18 22:55:36 +00007922 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007923 if (!(p = lock_user_string(arg1)))
7924 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007925 ret = get_errno(setdomainname(p, arg2));
7926 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007927 break;
7928 case TARGET_NR_uname:
7929 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007930 {
7931 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007932
bellard579a97f2007-11-11 14:26:47 +00007933 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7934 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007935 ret = get_errno(sys_uname(buf));
7936 if (!is_error(ret)) {
7937 /* Overrite the native machine name with whatever is being
7938 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007939 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007940 /* Allow the user to override the reported release. */
7941 if (qemu_uname_release && *qemu_uname_release)
7942 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007943 }
pbrook53a59602006-03-25 19:31:22 +00007944 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007945 }
bellard31e31b82003-02-18 22:55:36 +00007946 break;
bellard6dbad632003-03-16 18:05:05 +00007947#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007948 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007949 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007950 break;
j_mayer84409dd2007-04-06 08:56:50 +00007951#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007952 case TARGET_NR_vm86old:
7953 goto unimplemented;
7954 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007955 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007956 break;
7957#endif
j_mayer84409dd2007-04-06 08:56:50 +00007958#endif
bellard31e31b82003-02-18 22:55:36 +00007959 case TARGET_NR_adjtimex:
7960 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007961#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007962 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007963#endif
bellard31e31b82003-02-18 22:55:36 +00007964 case TARGET_NR_init_module:
7965 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007966#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007967 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007968#endif
bellard31e31b82003-02-18 22:55:36 +00007969 goto unimplemented;
7970 case TARGET_NR_quotactl:
7971 goto unimplemented;
7972 case TARGET_NR_getpgid:
7973 ret = get_errno(getpgid(arg1));
7974 break;
7975 case TARGET_NR_fchdir:
7976 ret = get_errno(fchdir(arg1));
7977 break;
j_mayer84409dd2007-04-06 08:56:50 +00007978#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007979 case TARGET_NR_bdflush:
7980 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007981#endif
thse5febef2007-04-01 18:31:35 +00007982#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007983 case TARGET_NR_sysfs:
7984 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007985#endif
bellard31e31b82003-02-18 22:55:36 +00007986 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007987 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007988 break;
thse5febef2007-04-01 18:31:35 +00007989#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007990 case TARGET_NR_afs_syscall:
7991 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007992#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007993#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007994 case TARGET_NR__llseek:
7995 {
7996 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007997#if !defined(__NR_llseek)
7998 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7999 if (res == -1) {
8000 ret = get_errno(res);
8001 } else {
8002 ret = 0;
8003 }
8004#else
bellard31e31b82003-02-18 22:55:36 +00008005 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008006#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008007 if ((ret == 0) && put_user_s64(res, arg4)) {
8008 goto efault;
8009 }
bellard31e31b82003-02-18 22:55:36 +00008010 }
8011 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008012#endif
Chen Gang704eff62015-08-21 05:37:33 +08008013#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008014 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008015#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008016#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008017 {
pbrook53a59602006-03-25 19:31:22 +00008018 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008019 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008020 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008021
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308022 dirp = g_try_malloc(count);
8023 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008024 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008025 goto fail;
8026 }
ths3b46e622007-09-17 08:09:54 +00008027
bellard4add45b2003-06-05 01:52:59 +00008028 ret = get_errno(sys_getdents(arg1, dirp, count));
8029 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008030 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008031 struct target_dirent *tde;
8032 int len = ret;
8033 int reclen, treclen;
8034 int count1, tnamelen;
8035
8036 count1 = 0;
8037 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008038 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8039 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008040 tde = target_dirp;
8041 while (len > 0) {
8042 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008043 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8044 assert(tnamelen >= 0);
8045 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8046 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008047 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008048 tde->d_ino = tswapal(de->d_ino);
8049 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008050 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008051 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008052 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008053 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008054 count1 += treclen;
8055 }
8056 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008057 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008058 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308059 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008060 }
8061#else
bellard31e31b82003-02-18 22:55:36 +00008062 {
aurel326556a832008-10-13 21:08:17 +00008063 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008064 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008065
bellard579a97f2007-11-11 14:26:47 +00008066 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8067 goto efault;
bellard72f03902003-02-18 23:33:18 +00008068 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008069 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008070 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008071 int len = ret;
8072 int reclen;
8073 de = dirp;
8074 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008075 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008076 if (reclen > len)
8077 break;
bellard8083a3e2003-03-24 23:12:16 +00008078 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008079 tswapls(&de->d_ino);
8080 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008081 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008082 len -= reclen;
8083 }
8084 }
pbrook53a59602006-03-25 19:31:22 +00008085 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008086 }
bellard4add45b2003-06-05 01:52:59 +00008087#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008088#else
8089 /* Implement getdents in terms of getdents64 */
8090 {
8091 struct linux_dirent64 *dirp;
8092 abi_long count = arg3;
8093
8094 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8095 if (!dirp) {
8096 goto efault;
8097 }
8098 ret = get_errno(sys_getdents64(arg1, dirp, count));
8099 if (!is_error(ret)) {
8100 /* Convert the dirent64 structs to target dirent. We do this
8101 * in-place, since we can guarantee that a target_dirent is no
8102 * larger than a dirent64; however this means we have to be
8103 * careful to read everything before writing in the new format.
8104 */
8105 struct linux_dirent64 *de;
8106 struct target_dirent *tde;
8107 int len = ret;
8108 int tlen = 0;
8109
8110 de = dirp;
8111 tde = (struct target_dirent *)dirp;
8112 while (len > 0) {
8113 int namelen, treclen;
8114 int reclen = de->d_reclen;
8115 uint64_t ino = de->d_ino;
8116 int64_t off = de->d_off;
8117 uint8_t type = de->d_type;
8118
8119 namelen = strlen(de->d_name);
8120 treclen = offsetof(struct target_dirent, d_name)
8121 + namelen + 2;
8122 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8123
8124 memmove(tde->d_name, de->d_name, namelen + 1);
8125 tde->d_ino = tswapal(ino);
8126 tde->d_off = tswapal(off);
8127 tde->d_reclen = tswap16(treclen);
8128 /* The target_dirent type is in what was formerly a padding
8129 * byte at the end of the structure:
8130 */
8131 *(((char *)tde) + treclen - 1) = type;
8132
8133 de = (struct linux_dirent64 *)((char *)de + reclen);
8134 tde = (struct target_dirent *)((char *)tde + treclen);
8135 len -= reclen;
8136 tlen += treclen;
8137 }
8138 ret = tlen;
8139 }
8140 unlock_user(dirp, arg2, ret);
8141 }
8142#endif
bellard31e31b82003-02-18 22:55:36 +00008143 break;
Chen Gang704eff62015-08-21 05:37:33 +08008144#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008145#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008146 case TARGET_NR_getdents64:
8147 {
aurel326556a832008-10-13 21:08:17 +00008148 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008149 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008150 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8151 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008152 ret = get_errno(sys_getdents64(arg1, dirp, count));
8153 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008154 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008155 int len = ret;
8156 int reclen;
8157 de = dirp;
8158 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008159 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008160 if (reclen > len)
8161 break;
bellard8083a3e2003-03-24 23:12:16 +00008162 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008163 tswap64s((uint64_t *)&de->d_ino);
8164 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008165 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008166 len -= reclen;
8167 }
8168 }
pbrook53a59602006-03-25 19:31:22 +00008169 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008170 }
8171 break;
bellarda541f292004-04-12 20:39:29 +00008172#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008173#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008174 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008175 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008176 break;
thse5febef2007-04-01 18:31:35 +00008177#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008178#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8179# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008180 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008181# endif
8182# ifdef TARGET_NR_ppoll
8183 case TARGET_NR_ppoll:
8184# endif
bellard9de5e442003-03-23 16:49:39 +00008185 {
pbrook53a59602006-03-25 19:31:22 +00008186 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008187 unsigned int nfds = arg2;
8188 int timeout = arg3;
8189 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008190 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008191
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008192 pfd = NULL;
8193 target_pfd = NULL;
8194 if (nfds) {
8195 target_pfd = lock_user(VERIFY_WRITE, arg1,
8196 sizeof(struct target_pollfd) * nfds, 1);
8197 if (!target_pfd) {
8198 goto efault;
8199 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008200
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008201 pfd = alloca(sizeof(struct pollfd) * nfds);
8202 for (i = 0; i < nfds; i++) {
8203 pfd[i].fd = tswap32(target_pfd[i].fd);
8204 pfd[i].events = tswap16(target_pfd[i].events);
8205 }
bellard9de5e442003-03-23 16:49:39 +00008206 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008207
8208# ifdef TARGET_NR_ppoll
8209 if (num == TARGET_NR_ppoll) {
8210 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8211 target_sigset_t *target_set;
8212 sigset_t _set, *set = &_set;
8213
8214 if (arg3) {
8215 if (target_to_host_timespec(timeout_ts, arg3)) {
8216 unlock_user(target_pfd, arg1, 0);
8217 goto efault;
8218 }
8219 } else {
8220 timeout_ts = NULL;
8221 }
8222
8223 if (arg4) {
8224 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
8225 if (!target_set) {
8226 unlock_user(target_pfd, arg1, 0);
8227 goto efault;
8228 }
8229 target_to_host_sigset(set, target_set);
8230 } else {
8231 set = NULL;
8232 }
8233
8234 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
8235
8236 if (!is_error(ret) && arg3) {
8237 host_to_target_timespec(arg3, timeout_ts);
8238 }
8239 if (arg4) {
8240 unlock_user(target_set, arg4, 0);
8241 }
8242 } else
8243# endif
8244 ret = get_errno(poll(pfd, nfds, timeout));
8245
bellard9de5e442003-03-23 16:49:39 +00008246 if (!is_error(ret)) {
8247 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00008248 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00008249 }
8250 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00008251 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00008252 }
8253 break;
thse5febef2007-04-01 18:31:35 +00008254#endif
bellard31e31b82003-02-18 22:55:36 +00008255 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00008256 /* NOTE: the flock constant seems to be the same for every
8257 Linux platform */
8258 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008259 break;
8260 case TARGET_NR_readv:
8261 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008262 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
8263 if (vec != NULL) {
8264 ret = get_errno(readv(arg1, vec, arg3));
8265 unlock_iovec(vec, arg2, arg3, 1);
8266 } else {
8267 ret = -host_to_target_errno(errno);
8268 }
bellard31e31b82003-02-18 22:55:36 +00008269 }
8270 break;
8271 case TARGET_NR_writev:
8272 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008273 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8274 if (vec != NULL) {
8275 ret = get_errno(writev(arg1, vec, arg3));
8276 unlock_iovec(vec, arg2, arg3, 0);
8277 } else {
8278 ret = -host_to_target_errno(errno);
8279 }
bellard31e31b82003-02-18 22:55:36 +00008280 }
8281 break;
8282 case TARGET_NR_getsid:
8283 ret = get_errno(getsid(arg1));
8284 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008285#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00008286 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00008287 ret = get_errno(fdatasync(arg1));
8288 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008289#endif
Chen Gang704eff62015-08-21 05:37:33 +08008290#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00008291 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00008292 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00008293 return value. */
ths0da46a62007-10-20 20:23:07 +00008294 ret = -TARGET_ENOTDIR;
8295 break;
Chen Gang704eff62015-08-21 05:37:33 +08008296#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05008297 case TARGET_NR_sched_getaffinity:
8298 {
8299 unsigned int mask_size;
8300 unsigned long *mask;
8301
8302 /*
8303 * sched_getaffinity needs multiples of ulong, so need to take
8304 * care of mismatches between target ulong and host ulong sizes.
8305 */
8306 if (arg2 & (sizeof(abi_ulong) - 1)) {
8307 ret = -TARGET_EINVAL;
8308 break;
8309 }
8310 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8311
8312 mask = alloca(mask_size);
8313 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
8314
8315 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01008316 if (ret > arg2) {
8317 /* More data returned than the caller's buffer will fit.
8318 * This only happens if sizeof(abi_long) < sizeof(long)
8319 * and the caller passed us a buffer holding an odd number
8320 * of abi_longs. If the host kernel is actually using the
8321 * extra 4 bytes then fail EINVAL; otherwise we can just
8322 * ignore them and only copy the interesting part.
8323 */
8324 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
8325 if (numcpus > arg2 * 8) {
8326 ret = -TARGET_EINVAL;
8327 break;
8328 }
8329 ret = arg2;
8330 }
8331
Mike McCormackcd18f052011-04-18 14:43:36 +09008332 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05008333 goto efault;
8334 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05008335 }
8336 }
8337 break;
8338 case TARGET_NR_sched_setaffinity:
8339 {
8340 unsigned int mask_size;
8341 unsigned long *mask;
8342
8343 /*
8344 * sched_setaffinity needs multiples of ulong, so need to take
8345 * care of mismatches between target ulong and host ulong sizes.
8346 */
8347 if (arg2 & (sizeof(abi_ulong) - 1)) {
8348 ret = -TARGET_EINVAL;
8349 break;
8350 }
8351 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8352
8353 mask = alloca(mask_size);
8354 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
8355 goto efault;
8356 }
8357 memcpy(mask, p, arg2);
8358 unlock_user_struct(p, arg2, 0);
8359
8360 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
8361 }
8362 break;
bellard31e31b82003-02-18 22:55:36 +00008363 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00008364 {
pbrook53a59602006-03-25 19:31:22 +00008365 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008366 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00008367
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008368 if (arg2 == 0) {
8369 return -TARGET_EINVAL;
8370 }
bellard579a97f2007-11-11 14:26:47 +00008371 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
8372 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008373 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008374 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00008375 ret = get_errno(sched_setparam(arg1, &schp));
8376 }
8377 break;
bellard31e31b82003-02-18 22:55:36 +00008378 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00008379 {
pbrook53a59602006-03-25 19:31:22 +00008380 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008381 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008382
8383 if (arg2 == 0) {
8384 return -TARGET_EINVAL;
8385 }
bellard5cd43932003-03-29 16:54:36 +00008386 ret = get_errno(sched_getparam(arg1, &schp));
8387 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008388 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
8389 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008390 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008391 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00008392 }
8393 }
8394 break;
bellard31e31b82003-02-18 22:55:36 +00008395 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00008396 {
pbrook53a59602006-03-25 19:31:22 +00008397 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008398 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008399 if (arg3 == 0) {
8400 return -TARGET_EINVAL;
8401 }
bellard579a97f2007-11-11 14:26:47 +00008402 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
8403 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008404 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008405 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00008406 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
8407 }
8408 break;
bellard31e31b82003-02-18 22:55:36 +00008409 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00008410 ret = get_errno(sched_getscheduler(arg1));
8411 break;
bellard31e31b82003-02-18 22:55:36 +00008412 case TARGET_NR_sched_yield:
8413 ret = get_errno(sched_yield());
8414 break;
8415 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00008416 ret = get_errno(sched_get_priority_max(arg1));
8417 break;
bellard31e31b82003-02-18 22:55:36 +00008418 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00008419 ret = get_errno(sched_get_priority_min(arg1));
8420 break;
bellard31e31b82003-02-18 22:55:36 +00008421 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00008422 {
bellard5cd43932003-03-29 16:54:36 +00008423 struct timespec ts;
8424 ret = get_errno(sched_rr_get_interval(arg1, &ts));
8425 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05008426 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00008427 }
8428 }
8429 break;
bellard31e31b82003-02-18 22:55:36 +00008430 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00008431 {
bellard1b6b0292003-03-22 17:31:38 +00008432 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00008433 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00008434 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00008435 if (is_error(ret) && arg2) {
8436 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00008437 }
8438 }
8439 break;
thse5febef2007-04-01 18:31:35 +00008440#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00008441 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00008442 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008443#endif
8444#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00008445 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00008446 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008447#endif
bellard31e31b82003-02-18 22:55:36 +00008448 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00008449 switch (arg1) {
8450 case PR_GET_PDEATHSIG:
8451 {
8452 int deathsig;
8453 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
8454 if (!is_error(ret) && arg2
8455 && put_user_ual(deathsig, arg2)) {
8456 goto efault;
thse5574482007-02-11 20:03:13 +00008457 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00008458 break;
8459 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00008460#ifdef PR_GET_NAME
8461 case PR_GET_NAME:
8462 {
8463 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
8464 if (!name) {
8465 goto efault;
8466 }
8467 ret = get_errno(prctl(arg1, (unsigned long)name,
8468 arg3, arg4, arg5));
8469 unlock_user(name, arg2, 16);
8470 break;
8471 }
8472 case PR_SET_NAME:
8473 {
8474 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
8475 if (!name) {
8476 goto efault;
8477 }
8478 ret = get_errno(prctl(arg1, (unsigned long)name,
8479 arg3, arg4, arg5));
8480 unlock_user(name, arg2, 0);
8481 break;
8482 }
8483#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00008484 default:
8485 /* Most prctl options have no pointer arguments */
8486 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
8487 break;
8488 }
ths39b9aae2007-02-11 18:36:44 +00008489 break;
bellardd2fd1af2007-11-14 18:08:56 +00008490#ifdef TARGET_NR_arch_prctl
8491 case TARGET_NR_arch_prctl:
8492#if defined(TARGET_I386) && !defined(TARGET_ABI32)
8493 ret = do_arch_prctl(cpu_env, arg1, arg2);
8494 break;
8495#else
8496 goto unimplemented;
8497#endif
8498#endif
aurel32f2c7ba12008-03-28 22:32:06 +00008499#ifdef TARGET_NR_pread64
8500 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00008501 if (regpairs_aligned(cpu_env)) {
8502 arg4 = arg5;
8503 arg5 = arg6;
8504 }
aurel32f2c7ba12008-03-28 22:32:06 +00008505 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8506 goto efault;
8507 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
8508 unlock_user(p, arg2, ret);
8509 break;
8510 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00008511 if (regpairs_aligned(cpu_env)) {
8512 arg4 = arg5;
8513 arg5 = arg6;
8514 }
aurel32f2c7ba12008-03-28 22:32:06 +00008515 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8516 goto efault;
8517 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
8518 unlock_user(p, arg2, 0);
8519 break;
8520#endif
bellard31e31b82003-02-18 22:55:36 +00008521 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00008522 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
8523 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008524 ret = get_errno(sys_getcwd1(p, arg2));
8525 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00008526 break;
8527 case TARGET_NR_capget:
8528 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00008529 {
8530 struct target_user_cap_header *target_header;
8531 struct target_user_cap_data *target_data = NULL;
8532 struct __user_cap_header_struct header;
8533 struct __user_cap_data_struct data[2];
8534 struct __user_cap_data_struct *dataptr = NULL;
8535 int i, target_datalen;
8536 int data_items = 1;
8537
8538 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
8539 goto efault;
8540 }
8541 header.version = tswap32(target_header->version);
8542 header.pid = tswap32(target_header->pid);
8543
Peter Maydellec864872014-03-19 16:07:30 +00008544 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008545 /* Version 2 and up takes pointer to two user_data structs */
8546 data_items = 2;
8547 }
8548
8549 target_datalen = sizeof(*target_data) * data_items;
8550
8551 if (arg2) {
8552 if (num == TARGET_NR_capget) {
8553 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8554 } else {
8555 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8556 }
8557 if (!target_data) {
8558 unlock_user_struct(target_header, arg1, 0);
8559 goto efault;
8560 }
8561
8562 if (num == TARGET_NR_capset) {
8563 for (i = 0; i < data_items; i++) {
8564 data[i].effective = tswap32(target_data[i].effective);
8565 data[i].permitted = tswap32(target_data[i].permitted);
8566 data[i].inheritable = tswap32(target_data[i].inheritable);
8567 }
8568 }
8569
8570 dataptr = data;
8571 }
8572
8573 if (num == TARGET_NR_capget) {
8574 ret = get_errno(capget(&header, dataptr));
8575 } else {
8576 ret = get_errno(capset(&header, dataptr));
8577 }
8578
8579 /* The kernel always updates version for both capget and capset */
8580 target_header->version = tswap32(header.version);
8581 unlock_user_struct(target_header, arg1, 1);
8582
8583 if (arg2) {
8584 if (num == TARGET_NR_capget) {
8585 for (i = 0; i < data_items; i++) {
8586 target_data[i].effective = tswap32(data[i].effective);
8587 target_data[i].permitted = tswap32(data[i].permitted);
8588 target_data[i].inheritable = tswap32(data[i].inheritable);
8589 }
8590 unlock_user(target_data, arg2, target_datalen);
8591 } else {
8592 unlock_user(target_data, arg2, 0);
8593 }
8594 }
8595 break;
8596 }
bellard31e31b82003-02-18 22:55:36 +00008597 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01008598 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008599 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008600
8601#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008602 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008603 {
8604 off_t *offp = NULL;
8605 off_t off;
8606 if (arg3) {
8607 ret = get_user_sal(off, arg3);
8608 if (is_error(ret)) {
8609 break;
8610 }
8611 offp = &off;
8612 }
8613 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8614 if (!is_error(ret) && arg3) {
8615 abi_long ret2 = put_user_sal(off, arg3);
8616 if (is_error(ret2)) {
8617 ret = ret2;
8618 }
8619 }
8620 break;
8621 }
8622#ifdef TARGET_NR_sendfile64
8623 case TARGET_NR_sendfile64:
8624 {
8625 off_t *offp = NULL;
8626 off_t off;
8627 if (arg3) {
8628 ret = get_user_s64(off, arg3);
8629 if (is_error(ret)) {
8630 break;
8631 }
8632 offp = &off;
8633 }
8634 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8635 if (!is_error(ret) && arg3) {
8636 abi_long ret2 = put_user_s64(off, arg3);
8637 if (is_error(ret2)) {
8638 ret = ret2;
8639 }
8640 }
8641 break;
8642 }
8643#endif
8644#else
8645 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008646#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008647 case TARGET_NR_sendfile64:
8648#endif
bellard5cd43932003-03-29 16:54:36 +00008649 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008650#endif
8651
bellardebc05482003-09-30 21:08:41 +00008652#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008653 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008654 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008655#endif
8656#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008657 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008658 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008659#endif
bellard048f6b42005-11-26 18:47:20 +00008660#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008661 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008662 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8663 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008664 break;
bellard048f6b42005-11-26 18:47:20 +00008665#endif
bellardebc05482003-09-30 21:08:41 +00008666#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008667 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008668 {
8669 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008670 int resource = target_to_host_resource(arg1);
8671 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008672 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008673 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008674 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8675 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008676 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8677 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008678 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008679 }
8680 break;
8681 }
bellardebc05482003-09-30 21:08:41 +00008682#endif
bellarda315a142005-01-30 22:59:18 +00008683#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008684 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008685 if (!(p = lock_user_string(arg1)))
8686 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008687 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8688 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008689 break;
bellarda315a142005-01-30 22:59:18 +00008690#endif
8691#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008692 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008693 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008694 break;
bellarda315a142005-01-30 22:59:18 +00008695#endif
8696#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008697 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008698 if (!(p = lock_user_string(arg1)))
8699 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008700 ret = get_errno(stat(path(p), &st));
8701 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008702 if (!is_error(ret))
8703 ret = host_to_target_stat64(cpu_env, arg2, &st);
8704 break;
bellarda315a142005-01-30 22:59:18 +00008705#endif
8706#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008707 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008708 if (!(p = lock_user_string(arg1)))
8709 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008710 ret = get_errno(lstat(path(p), &st));
8711 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008712 if (!is_error(ret))
8713 ret = host_to_target_stat64(cpu_env, arg2, &st);
8714 break;
bellarda315a142005-01-30 22:59:18 +00008715#endif
8716#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008717 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008718 ret = get_errno(fstat(arg1, &st));
8719 if (!is_error(ret))
8720 ret = host_to_target_stat64(cpu_env, arg2, &st);
8721 break;
bellardec86b0f2003-04-11 00:15:04 +00008722#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008723#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008724#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008725 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008726#endif
8727#ifdef TARGET_NR_newfstatat
8728 case TARGET_NR_newfstatat:
8729#endif
balrog6a24a772008-09-20 02:23:36 +00008730 if (!(p = lock_user_string(arg2)))
8731 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008732 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008733 if (!is_error(ret))
8734 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008735 break;
bellarda315a142005-01-30 22:59:18 +00008736#endif
Chen Gang704eff62015-08-21 05:37:33 +08008737#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00008738 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008739 if (!(p = lock_user_string(arg1)))
8740 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008741 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8742 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008743 break;
Chen Gang704eff62015-08-21 05:37:33 +08008744#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03008745#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008746 case TARGET_NR_getuid:
8747 ret = get_errno(high2lowuid(getuid()));
8748 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008749#endif
8750#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008751 case TARGET_NR_getgid:
8752 ret = get_errno(high2lowgid(getgid()));
8753 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008754#endif
8755#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008756 case TARGET_NR_geteuid:
8757 ret = get_errno(high2lowuid(geteuid()));
8758 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008759#endif
8760#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008761 case TARGET_NR_getegid:
8762 ret = get_errno(high2lowgid(getegid()));
8763 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008764#endif
bellard67867302003-11-23 17:05:30 +00008765 case TARGET_NR_setreuid:
8766 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8767 break;
8768 case TARGET_NR_setregid:
8769 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8770 break;
8771 case TARGET_NR_getgroups:
8772 {
8773 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008774 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008775 gid_t *grouplist;
8776 int i;
8777
8778 grouplist = alloca(gidsetsize * sizeof(gid_t));
8779 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008780 if (gidsetsize == 0)
8781 break;
bellard67867302003-11-23 17:05:30 +00008782 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008783 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008784 if (!target_grouplist)
8785 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008786 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008787 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008788 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008789 }
8790 }
8791 break;
8792 case TARGET_NR_setgroups:
8793 {
8794 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008795 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008796 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008797 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008798 if (gidsetsize) {
8799 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008800 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008801 if (!target_grouplist) {
8802 ret = -TARGET_EFAULT;
8803 goto fail;
8804 }
8805 for (i = 0; i < gidsetsize; i++) {
8806 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8807 }
8808 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008809 }
bellard67867302003-11-23 17:05:30 +00008810 ret = get_errno(setgroups(gidsetsize, grouplist));
8811 }
8812 break;
8813 case TARGET_NR_fchown:
8814 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8815 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008816#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008817 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008818 if (!(p = lock_user_string(arg2)))
8819 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008820 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8821 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008822 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008823 break;
8824#endif
bellard67867302003-11-23 17:05:30 +00008825#ifdef TARGET_NR_setresuid
8826 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008827 ret = get_errno(setresuid(low2highuid(arg1),
8828 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008829 low2highuid(arg3)));
8830 break;
8831#endif
8832#ifdef TARGET_NR_getresuid
8833 case TARGET_NR_getresuid:
8834 {
pbrook53a59602006-03-25 19:31:22 +00008835 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008836 ret = get_errno(getresuid(&ruid, &euid, &suid));
8837 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008838 if (put_user_id(high2lowuid(ruid), arg1)
8839 || put_user_id(high2lowuid(euid), arg2)
8840 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008841 goto efault;
bellard67867302003-11-23 17:05:30 +00008842 }
8843 }
8844 break;
8845#endif
8846#ifdef TARGET_NR_getresgid
8847 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008848 ret = get_errno(setresgid(low2highgid(arg1),
8849 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008850 low2highgid(arg3)));
8851 break;
8852#endif
8853#ifdef TARGET_NR_getresgid
8854 case TARGET_NR_getresgid:
8855 {
pbrook53a59602006-03-25 19:31:22 +00008856 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008857 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8858 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008859 if (put_user_id(high2lowgid(rgid), arg1)
8860 || put_user_id(high2lowgid(egid), arg2)
8861 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008862 goto efault;
bellard67867302003-11-23 17:05:30 +00008863 }
8864 }
8865 break;
8866#endif
Chen Gang704eff62015-08-21 05:37:33 +08008867#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00008868 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008869 if (!(p = lock_user_string(arg1)))
8870 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008871 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8872 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008873 break;
Chen Gang704eff62015-08-21 05:37:33 +08008874#endif
bellard67867302003-11-23 17:05:30 +00008875 case TARGET_NR_setuid:
8876 ret = get_errno(setuid(low2highuid(arg1)));
8877 break;
8878 case TARGET_NR_setgid:
8879 ret = get_errno(setgid(low2highgid(arg1)));
8880 break;
8881 case TARGET_NR_setfsuid:
8882 ret = get_errno(setfsuid(arg1));
8883 break;
8884 case TARGET_NR_setfsgid:
8885 ret = get_errno(setfsgid(arg1));
8886 break;
bellard67867302003-11-23 17:05:30 +00008887
bellarda315a142005-01-30 22:59:18 +00008888#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008889 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008890 if (!(p = lock_user_string(arg1)))
8891 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008892 ret = get_errno(lchown(p, arg2, arg3));
8893 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008894 break;
bellarda315a142005-01-30 22:59:18 +00008895#endif
8896#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008897 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008898 ret = get_errno(getuid());
8899 break;
bellarda315a142005-01-30 22:59:18 +00008900#endif
aurel3264b4d282008-11-14 17:20:15 +00008901
8902#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8903 /* Alpha specific */
8904 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008905 {
8906 uid_t euid;
8907 euid=geteuid();
8908 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8909 }
aurel3264b4d282008-11-14 17:20:15 +00008910 ret = get_errno(getuid());
8911 break;
8912#endif
8913#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8914 /* Alpha specific */
8915 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008916 {
8917 uid_t egid;
8918 egid=getegid();
8919 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8920 }
aurel3264b4d282008-11-14 17:20:15 +00008921 ret = get_errno(getgid());
8922 break;
8923#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008924#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8925 /* Alpha specific */
8926 case TARGET_NR_osf_getsysinfo:
8927 ret = -TARGET_EOPNOTSUPP;
8928 switch (arg1) {
8929 case TARGET_GSI_IEEE_FP_CONTROL:
8930 {
8931 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8932
8933 /* Copied from linux ieee_fpcr_to_swcr. */
8934 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8935 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8936 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8937 | SWCR_TRAP_ENABLE_DZE
8938 | SWCR_TRAP_ENABLE_OVF);
8939 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8940 | SWCR_TRAP_ENABLE_INE);
8941 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8942 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8943
8944 if (put_user_u64 (swcr, arg2))
8945 goto efault;
8946 ret = 0;
8947 }
8948 break;
8949
8950 /* case GSI_IEEE_STATE_AT_SIGNAL:
8951 -- Not implemented in linux kernel.
8952 case GSI_UACPROC:
8953 -- Retrieves current unaligned access state; not much used.
8954 case GSI_PROC_TYPE:
8955 -- Retrieves implver information; surely not used.
8956 case GSI_GET_HWRPB:
8957 -- Grabs a copy of the HWRPB; surely not used.
8958 */
8959 }
8960 break;
8961#endif
8962#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8963 /* Alpha specific */
8964 case TARGET_NR_osf_setsysinfo:
8965 ret = -TARGET_EOPNOTSUPP;
8966 switch (arg1) {
8967 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008968 {
8969 uint64_t swcr, fpcr, orig_fpcr;
8970
Richard Henderson6e06d512012-06-01 09:08:21 -07008971 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008972 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008973 }
8974 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008975 fpcr = orig_fpcr & FPCR_DYN_MASK;
8976
8977 /* Copied from linux ieee_swcr_to_fpcr. */
8978 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8979 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8980 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8981 | SWCR_TRAP_ENABLE_DZE
8982 | SWCR_TRAP_ENABLE_OVF)) << 48;
8983 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8984 | SWCR_TRAP_ENABLE_INE)) << 57;
8985 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8986 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8987
Richard Henderson6e06d512012-06-01 09:08:21 -07008988 cpu_alpha_store_fpcr(cpu_env, fpcr);
8989 ret = 0;
8990 }
8991 break;
8992
8993 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8994 {
8995 uint64_t exc, fpcr, orig_fpcr;
8996 int si_code;
8997
8998 if (get_user_u64(exc, arg2)) {
8999 goto efault;
9000 }
9001
9002 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9003
9004 /* We only add to the exception status here. */
9005 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9006
9007 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009008 ret = 0;
9009
Richard Henderson6e06d512012-06-01 09:08:21 -07009010 /* Old exceptions are not signaled. */
9011 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009012
Richard Henderson6e06d512012-06-01 09:08:21 -07009013 /* If any exceptions set by this call,
9014 and are unmasked, send a signal. */
9015 si_code = 0;
9016 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9017 si_code = TARGET_FPE_FLTRES;
9018 }
9019 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9020 si_code = TARGET_FPE_FLTUND;
9021 }
9022 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9023 si_code = TARGET_FPE_FLTOVF;
9024 }
9025 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9026 si_code = TARGET_FPE_FLTDIV;
9027 }
9028 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9029 si_code = TARGET_FPE_FLTINV;
9030 }
9031 if (si_code != 0) {
9032 target_siginfo_t info;
9033 info.si_signo = SIGFPE;
9034 info.si_errno = 0;
9035 info.si_code = si_code;
9036 info._sifields._sigfault._addr
9037 = ((CPUArchState *)cpu_env)->pc;
9038 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009039 }
9040 }
9041 break;
9042
9043 /* case SSI_NVPAIRS:
9044 -- Used with SSIN_UACPROC to enable unaligned accesses.
9045 case SSI_IEEE_STATE_AT_SIGNAL:
9046 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9047 -- Not implemented in linux kernel
9048 */
9049 }
9050 break;
9051#endif
9052#ifdef TARGET_NR_osf_sigprocmask
9053 /* Alpha specific. */
9054 case TARGET_NR_osf_sigprocmask:
9055 {
9056 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009057 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009058 sigset_t set, oldset;
9059
9060 switch(arg1) {
9061 case TARGET_SIG_BLOCK:
9062 how = SIG_BLOCK;
9063 break;
9064 case TARGET_SIG_UNBLOCK:
9065 how = SIG_UNBLOCK;
9066 break;
9067 case TARGET_SIG_SETMASK:
9068 how = SIG_SETMASK;
9069 break;
9070 default:
9071 ret = -TARGET_EINVAL;
9072 goto fail;
9073 }
9074 mask = arg2;
9075 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00009076 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009077 host_to_target_old_sigset(&mask, &oldset);
9078 ret = mask;
9079 }
9080 break;
9081#endif
aurel3264b4d282008-11-14 17:20:15 +00009082
bellarda315a142005-01-30 22:59:18 +00009083#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009084 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009085 ret = get_errno(getgid());
9086 break;
bellarda315a142005-01-30 22:59:18 +00009087#endif
9088#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009089 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009090 ret = get_errno(geteuid());
9091 break;
bellarda315a142005-01-30 22:59:18 +00009092#endif
9093#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009094 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009095 ret = get_errno(getegid());
9096 break;
bellarda315a142005-01-30 22:59:18 +00009097#endif
9098#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009099 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009100 ret = get_errno(setreuid(arg1, arg2));
9101 break;
bellarda315a142005-01-30 22:59:18 +00009102#endif
9103#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009104 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009105 ret = get_errno(setregid(arg1, arg2));
9106 break;
bellarda315a142005-01-30 22:59:18 +00009107#endif
9108#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009109 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009110 {
9111 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009112 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009113 gid_t *grouplist;
9114 int i;
9115
9116 grouplist = alloca(gidsetsize * sizeof(gid_t));
9117 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009118 if (gidsetsize == 0)
9119 break;
bellard99c475a2005-01-31 20:45:13 +00009120 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009121 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9122 if (!target_grouplist) {
9123 ret = -TARGET_EFAULT;
9124 goto fail;
9125 }
balroga2155fc2008-09-20 02:12:08 +00009126 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009127 target_grouplist[i] = tswap32(grouplist[i]);
9128 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009129 }
9130 }
9131 break;
bellarda315a142005-01-30 22:59:18 +00009132#endif
9133#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009134 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009135 {
9136 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009137 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009138 gid_t *grouplist;
9139 int i;
ths3b46e622007-09-17 08:09:54 +00009140
bellard99c475a2005-01-31 20:45:13 +00009141 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009142 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9143 if (!target_grouplist) {
9144 ret = -TARGET_EFAULT;
9145 goto fail;
9146 }
bellard99c475a2005-01-31 20:45:13 +00009147 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009148 grouplist[i] = tswap32(target_grouplist[i]);
9149 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009150 ret = get_errno(setgroups(gidsetsize, grouplist));
9151 }
9152 break;
bellarda315a142005-01-30 22:59:18 +00009153#endif
9154#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009155 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009156 ret = get_errno(fchown(arg1, arg2, arg3));
9157 break;
bellarda315a142005-01-30 22:59:18 +00009158#endif
9159#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009160 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009161 ret = get_errno(setresuid(arg1, arg2, arg3));
9162 break;
bellarda315a142005-01-30 22:59:18 +00009163#endif
9164#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009165 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009166 {
pbrook53a59602006-03-25 19:31:22 +00009167 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009168 ret = get_errno(getresuid(&ruid, &euid, &suid));
9169 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009170 if (put_user_u32(ruid, arg1)
9171 || put_user_u32(euid, arg2)
9172 || put_user_u32(suid, arg3))
9173 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009174 }
9175 }
9176 break;
bellarda315a142005-01-30 22:59:18 +00009177#endif
9178#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009179 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009180 ret = get_errno(setresgid(arg1, arg2, arg3));
9181 break;
bellarda315a142005-01-30 22:59:18 +00009182#endif
9183#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009184 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009185 {
pbrook53a59602006-03-25 19:31:22 +00009186 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009187 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9188 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009189 if (put_user_u32(rgid, arg1)
9190 || put_user_u32(egid, arg2)
9191 || put_user_u32(sgid, arg3))
9192 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009193 }
9194 }
9195 break;
bellarda315a142005-01-30 22:59:18 +00009196#endif
9197#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009198 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009199 if (!(p = lock_user_string(arg1)))
9200 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009201 ret = get_errno(chown(p, arg2, arg3));
9202 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009203 break;
bellarda315a142005-01-30 22:59:18 +00009204#endif
9205#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009206 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00009207 ret = get_errno(setuid(arg1));
9208 break;
bellarda315a142005-01-30 22:59:18 +00009209#endif
9210#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009211 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00009212 ret = get_errno(setgid(arg1));
9213 break;
bellarda315a142005-01-30 22:59:18 +00009214#endif
9215#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009216 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009217 ret = get_errno(setfsuid(arg1));
9218 break;
bellarda315a142005-01-30 22:59:18 +00009219#endif
9220#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00009221 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00009222 ret = get_errno(setfsgid(arg1));
9223 break;
bellarda315a142005-01-30 22:59:18 +00009224#endif
bellard67867302003-11-23 17:05:30 +00009225
bellard31e31b82003-02-18 22:55:36 +00009226 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00009227 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00009228#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00009229 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00009230 {
9231 void *a;
9232 ret = -TARGET_EFAULT;
9233 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
9234 goto efault;
9235 if (!(p = lock_user_string(arg3)))
9236 goto mincore_fail;
9237 ret = get_errno(mincore(a, arg2, p));
9238 unlock_user(p, arg3, ret);
9239 mincore_fail:
9240 unlock_user(a, arg1, 0);
9241 }
9242 break;
bellardffa65c32004-01-04 23:57:22 +00009243#endif
aurel32408321b2008-10-01 21:46:32 +00009244#ifdef TARGET_NR_arm_fadvise64_64
9245 case TARGET_NR_arm_fadvise64_64:
9246 {
9247 /*
9248 * arm_fadvise64_64 looks like fadvise64_64 but
9249 * with different argument order
9250 */
9251 abi_long temp;
9252 temp = arg3;
9253 arg3 = arg4;
9254 arg4 = temp;
9255 }
9256#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009257#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00009258#ifdef TARGET_NR_fadvise64_64
9259 case TARGET_NR_fadvise64_64:
9260#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009261#ifdef TARGET_NR_fadvise64
9262 case TARGET_NR_fadvise64:
9263#endif
9264#ifdef TARGET_S390X
9265 switch (arg4) {
9266 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
9267 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
9268 case 6: arg4 = POSIX_FADV_DONTNEED; break;
9269 case 7: arg4 = POSIX_FADV_NOREUSE; break;
9270 default: break;
9271 }
9272#endif
9273 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00009274 break;
9275#endif
bellardffa65c32004-01-04 23:57:22 +00009276#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00009277 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00009278 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08009279 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00009280 This will break MADV_DONTNEED.
9281 This is a hint, so ignoring and returning success is ok. */
9282 ret = get_errno(0);
9283 break;
bellardffa65c32004-01-04 23:57:22 +00009284#endif
blueswir1992f48a2007-10-14 16:27:31 +00009285#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00009286 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00009287 {
thsb1e341e2007-03-20 21:50:52 +00009288 int cmd;
bellard77e46722003-04-29 20:39:06 +00009289 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00009290 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00009291#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00009292 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00009293#endif
bellard77e46722003-04-29 20:39:06 +00009294
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009295 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00009296 if (cmd == -TARGET_EINVAL) {
9297 ret = cmd;
9298 break;
9299 }
thsb1e341e2007-03-20 21:50:52 +00009300
bellard60cd49d2003-03-16 22:53:56 +00009301 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00009302 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00009303#ifdef TARGET_ARM
9304 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009305 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9306 goto efault;
ths58134272007-03-31 18:59:32 +00009307 fl.l_type = tswap16(target_efl->l_type);
9308 fl.l_whence = tswap16(target_efl->l_whence);
9309 fl.l_start = tswap64(target_efl->l_start);
9310 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009311 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00009312 unlock_user_struct(target_efl, arg3, 0);
9313 } else
9314#endif
9315 {
bellard9ee1fa22007-11-11 15:11:19 +00009316 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9317 goto efault;
ths58134272007-03-31 18:59:32 +00009318 fl.l_type = tswap16(target_fl->l_type);
9319 fl.l_whence = tswap16(target_fl->l_whence);
9320 fl.l_start = tswap64(target_fl->l_start);
9321 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009322 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00009323 unlock_user_struct(target_fl, arg3, 0);
9324 }
thsb1e341e2007-03-20 21:50:52 +00009325 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009326 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00009327#ifdef TARGET_ARM
9328 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009329 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
9330 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009331 target_efl->l_type = tswap16(fl.l_type);
9332 target_efl->l_whence = tswap16(fl.l_whence);
9333 target_efl->l_start = tswap64(fl.l_start);
9334 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009335 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009336 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009337 } else
9338#endif
9339 {
bellard9ee1fa22007-11-11 15:11:19 +00009340 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
9341 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009342 target_fl->l_type = tswap16(fl.l_type);
9343 target_fl->l_whence = tswap16(fl.l_whence);
9344 target_fl->l_start = tswap64(fl.l_start);
9345 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009346 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009347 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009348 }
bellard77e46722003-04-29 20:39:06 +00009349 }
9350 break;
9351
thsb1e341e2007-03-20 21:50:52 +00009352 case TARGET_F_SETLK64:
9353 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00009354#ifdef TARGET_ARM
9355 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009356 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9357 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009358 fl.l_type = tswap16(target_efl->l_type);
9359 fl.l_whence = tswap16(target_efl->l_whence);
9360 fl.l_start = tswap64(target_efl->l_start);
9361 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009362 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009363 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009364 } else
9365#endif
9366 {
bellard9ee1fa22007-11-11 15:11:19 +00009367 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9368 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009369 fl.l_type = tswap16(target_fl->l_type);
9370 fl.l_whence = tswap16(target_fl->l_whence);
9371 fl.l_start = tswap64(target_fl->l_start);
9372 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009373 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009374 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009375 }
thsb1e341e2007-03-20 21:50:52 +00009376 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009377 break;
bellard60cd49d2003-03-16 22:53:56 +00009378 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009379 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00009380 break;
9381 }
bellard77e46722003-04-29 20:39:06 +00009382 break;
9383 }
bellard60cd49d2003-03-16 22:53:56 +00009384#endif
ths7d600c82006-12-08 01:32:58 +00009385#ifdef TARGET_NR_cacheflush
9386 case TARGET_NR_cacheflush:
9387 /* self-modifying code is handled automatically, so nothing needed */
9388 ret = 0;
9389 break;
9390#endif
bellardebc05482003-09-30 21:08:41 +00009391#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00009392 case TARGET_NR_security:
9393 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009394#endif
bellardc573ff62004-01-04 15:51:36 +00009395#ifdef TARGET_NR_getpagesize
9396 case TARGET_NR_getpagesize:
9397 ret = TARGET_PAGE_SIZE;
9398 break;
9399#endif
bellard31e31b82003-02-18 22:55:36 +00009400 case TARGET_NR_gettid:
9401 ret = get_errno(gettid());
9402 break;
thse5febef2007-04-01 18:31:35 +00009403#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00009404 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00009405#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03009406 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00009407 arg2 = arg3;
9408 arg3 = arg4;
9409 arg4 = arg5;
9410 }
aurel322054ac92008-10-13 21:08:07 +00009411 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
9412#else
9413 ret = get_errno(readahead(arg1, arg2, arg3));
9414#endif
9415 break;
thse5febef2007-04-01 18:31:35 +00009416#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009417#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00009418#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00009419 case TARGET_NR_listxattr:
9420 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00009421 {
9422 void *p, *b = 0;
9423 if (arg2) {
9424 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9425 if (!b) {
9426 ret = -TARGET_EFAULT;
9427 break;
9428 }
9429 }
9430 p = lock_user_string(arg1);
9431 if (p) {
9432 if (num == TARGET_NR_listxattr) {
9433 ret = get_errno(listxattr(p, b, arg3));
9434 } else {
9435 ret = get_errno(llistxattr(p, b, arg3));
9436 }
9437 } else {
9438 ret = -TARGET_EFAULT;
9439 }
9440 unlock_user(p, arg1, 0);
9441 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03009442 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00009443 }
9444 case TARGET_NR_flistxattr:
9445 {
9446 void *b = 0;
9447 if (arg2) {
9448 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9449 if (!b) {
9450 ret = -TARGET_EFAULT;
9451 break;
9452 }
9453 }
9454 ret = get_errno(flistxattr(arg1, b, arg3));
9455 unlock_user(b, arg2, arg3);
9456 break;
9457 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009458 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009459 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009460 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009461 void *p, *n, *v = 0;
9462 if (arg3) {
9463 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9464 if (!v) {
9465 ret = -TARGET_EFAULT;
9466 break;
9467 }
9468 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009469 p = lock_user_string(arg1);
9470 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009471 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009472 if (num == TARGET_NR_setxattr) {
9473 ret = get_errno(setxattr(p, n, v, arg4, arg5));
9474 } else {
9475 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
9476 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009477 } else {
9478 ret = -TARGET_EFAULT;
9479 }
9480 unlock_user(p, arg1, 0);
9481 unlock_user(n, arg2, 0);
9482 unlock_user(v, arg3, 0);
9483 }
9484 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009485 case TARGET_NR_fsetxattr:
9486 {
9487 void *n, *v = 0;
9488 if (arg3) {
9489 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9490 if (!v) {
9491 ret = -TARGET_EFAULT;
9492 break;
9493 }
9494 }
9495 n = lock_user_string(arg2);
9496 if (n) {
9497 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
9498 } else {
9499 ret = -TARGET_EFAULT;
9500 }
9501 unlock_user(n, arg2, 0);
9502 unlock_user(v, arg3, 0);
9503 }
9504 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009505 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009506 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009507 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009508 void *p, *n, *v = 0;
9509 if (arg3) {
9510 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9511 if (!v) {
9512 ret = -TARGET_EFAULT;
9513 break;
9514 }
9515 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009516 p = lock_user_string(arg1);
9517 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009518 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009519 if (num == TARGET_NR_getxattr) {
9520 ret = get_errno(getxattr(p, n, v, arg4));
9521 } else {
9522 ret = get_errno(lgetxattr(p, n, v, arg4));
9523 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009524 } else {
9525 ret = -TARGET_EFAULT;
9526 }
9527 unlock_user(p, arg1, 0);
9528 unlock_user(n, arg2, 0);
9529 unlock_user(v, arg3, arg4);
9530 }
9531 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009532 case TARGET_NR_fgetxattr:
9533 {
9534 void *n, *v = 0;
9535 if (arg3) {
9536 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9537 if (!v) {
9538 ret = -TARGET_EFAULT;
9539 break;
9540 }
9541 }
9542 n = lock_user_string(arg2);
9543 if (n) {
9544 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9545 } else {
9546 ret = -TARGET_EFAULT;
9547 }
9548 unlock_user(n, arg2, 0);
9549 unlock_user(v, arg3, arg4);
9550 }
9551 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009552 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009553 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009554 {
9555 void *p, *n;
9556 p = lock_user_string(arg1);
9557 n = lock_user_string(arg2);
9558 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009559 if (num == TARGET_NR_removexattr) {
9560 ret = get_errno(removexattr(p, n));
9561 } else {
9562 ret = get_errno(lremovexattr(p, n));
9563 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009564 } else {
9565 ret = -TARGET_EFAULT;
9566 }
9567 unlock_user(p, arg1, 0);
9568 unlock_user(n, arg2, 0);
9569 }
9570 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009571 case TARGET_NR_fremovexattr:
9572 {
9573 void *n;
9574 n = lock_user_string(arg2);
9575 if (n) {
9576 ret = get_errno(fremovexattr(arg1, n));
9577 } else {
9578 ret = -TARGET_EFAULT;
9579 }
9580 unlock_user(n, arg2, 0);
9581 }
9582 break;
bellardebc05482003-09-30 21:08:41 +00009583#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009584#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009585#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009586 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009587#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009588 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009589 ret = 0;
9590 break;
edgar_iglef967792009-01-07 14:19:38 +00009591#elif defined(TARGET_CRIS)
9592 if (arg1 & 0xff)
9593 ret = -TARGET_EINVAL;
9594 else {
9595 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9596 ret = 0;
9597 }
9598 break;
bellard8d18e892007-11-14 15:18:40 +00009599#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9600 ret = do_set_thread_area(cpu_env, arg1);
9601 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009602#elif defined(TARGET_M68K)
9603 {
Andreas Färber0429a972013-08-26 18:14:44 +02009604 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009605 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009606 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009607 break;
9608 }
ths6f5b89a2007-03-02 20:48:00 +00009609#else
9610 goto unimplemented_nowarn;
9611#endif
9612#endif
9613#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009614 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009615#if defined(TARGET_I386) && defined(TARGET_ABI32)
9616 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009617 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009618#elif defined(TARGET_M68K)
9619 {
Andreas Färber0429a972013-08-26 18:14:44 +02009620 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009621 ret = ts->tp_value;
9622 break;
9623 }
bellard8d18e892007-11-14 15:18:40 +00009624#else
bellard5cd43932003-03-29 16:54:36 +00009625 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009626#endif
bellard8d18e892007-11-14 15:18:40 +00009627#endif
bellard48dc41e2006-06-21 18:15:50 +00009628#ifdef TARGET_NR_getdomainname
9629 case TARGET_NR_getdomainname:
9630 goto unimplemented_nowarn;
9631#endif
ths6f5b89a2007-03-02 20:48:00 +00009632
thsb5906f92007-03-19 13:32:45 +00009633#ifdef TARGET_NR_clock_gettime
9634 case TARGET_NR_clock_gettime:
9635 {
9636 struct timespec ts;
9637 ret = get_errno(clock_gettime(arg1, &ts));
9638 if (!is_error(ret)) {
9639 host_to_target_timespec(arg2, &ts);
9640 }
9641 break;
9642 }
9643#endif
9644#ifdef TARGET_NR_clock_getres
9645 case TARGET_NR_clock_getres:
9646 {
9647 struct timespec ts;
9648 ret = get_errno(clock_getres(arg1, &ts));
9649 if (!is_error(ret)) {
9650 host_to_target_timespec(arg2, &ts);
9651 }
9652 break;
9653 }
9654#endif
pbrook63d76512008-05-29 13:43:29 +00009655#ifdef TARGET_NR_clock_nanosleep
9656 case TARGET_NR_clock_nanosleep:
9657 {
9658 struct timespec ts;
9659 target_to_host_timespec(&ts, arg3);
9660 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9661 if (arg4)
9662 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009663
9664#if defined(TARGET_PPC)
9665 /* clock_nanosleep is odd in that it returns positive errno values.
9666 * On PPC, CR0 bit 3 should be set in such a situation. */
9667 if (ret) {
9668 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9669 }
9670#endif
pbrook63d76512008-05-29 13:43:29 +00009671 break;
9672 }
9673#endif
thsb5906f92007-03-19 13:32:45 +00009674
ths6f5b89a2007-03-02 20:48:00 +00009675#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9676 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009677 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9678 break;
ths6f5b89a2007-03-02 20:48:00 +00009679#endif
9680
ths3ae43202007-09-16 21:39:48 +00009681#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009682 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009683 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009684 break;
9685#endif
9686
ths3ae43202007-09-16 21:39:48 +00009687#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009688 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009689 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9690 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009691 break;
9692#endif
9693
ths4f2b1fe2007-06-21 21:57:12 +00009694#ifdef TARGET_NR_set_robust_list
9695 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009696 case TARGET_NR_get_robust_list:
9697 /* The ABI for supporting robust futexes has userspace pass
9698 * the kernel a pointer to a linked list which is updated by
9699 * userspace after the syscall; the list is walked by the kernel
9700 * when the thread exits. Since the linked list in QEMU guest
9701 * memory isn't a valid linked list for the host and we have
9702 * no way to reliably intercept the thread-death event, we can't
9703 * support these. Silently return ENOSYS so that guest userspace
9704 * falls back to a non-robust futex implementation (which should
9705 * be OK except in the corner case of the guest crashing while
9706 * holding a mutex that is shared with another process via
9707 * shared memory).
9708 */
9709 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009710#endif
9711
Peter Maydell1acae9f2013-07-02 14:04:12 +01009712#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009713 case TARGET_NR_utimensat:
9714 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009715 struct timespec *tsp, ts[2];
9716 if (!arg3) {
9717 tsp = NULL;
9718 } else {
9719 target_to_host_timespec(ts, arg3);
9720 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9721 tsp = ts;
9722 }
ths9007f0e2007-09-25 17:50:37 +00009723 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009724 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009725 else {
bellard579a97f2007-11-11 14:26:47 +00009726 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009727 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009728 goto fail;
9729 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009730 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009731 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009732 }
9733 }
9734 break;
9735#endif
pbrookbd0c5662008-05-29 14:34:11 +00009736 case TARGET_NR_futex:
9737 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9738 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009739#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009740 case TARGET_NR_inotify_init:
9741 ret = get_errno(sys_inotify_init());
9742 break;
9743#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009744#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009745#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9746 case TARGET_NR_inotify_init1:
9747 ret = get_errno(sys_inotify_init1(arg1));
9748 break;
9749#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009750#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009751#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009752 case TARGET_NR_inotify_add_watch:
9753 p = lock_user_string(arg2);
9754 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9755 unlock_user(p, arg2, 0);
9756 break;
9757#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009758#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009759 case TARGET_NR_inotify_rm_watch:
9760 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9761 break;
9762#endif
ths9007f0e2007-09-25 17:50:37 +00009763
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009764#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009765 case TARGET_NR_mq_open:
9766 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009767 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009768
9769 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009770 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009771 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009772 attrp = &posix_mq_attr;
9773 } else {
9774 attrp = 0;
9775 }
9776 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009777 unlock_user (p, arg1, 0);
9778 }
9779 break;
9780
9781 case TARGET_NR_mq_unlink:
9782 p = lock_user_string(arg1 - 1);
9783 ret = get_errno(mq_unlink(p));
9784 unlock_user (p, arg1, 0);
9785 break;
9786
9787 case TARGET_NR_mq_timedsend:
9788 {
9789 struct timespec ts;
9790
9791 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9792 if (arg5 != 0) {
9793 target_to_host_timespec(&ts, arg5);
9794 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9795 host_to_target_timespec(arg5, &ts);
9796 }
9797 else
9798 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9799 unlock_user (p, arg2, arg3);
9800 }
9801 break;
9802
9803 case TARGET_NR_mq_timedreceive:
9804 {
9805 struct timespec ts;
9806 unsigned int prio;
9807
9808 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9809 if (arg5 != 0) {
9810 target_to_host_timespec(&ts, arg5);
9811 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9812 host_to_target_timespec(arg5, &ts);
9813 }
9814 else
9815 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9816 unlock_user (p, arg2, arg3);
9817 if (arg4 != 0)
9818 put_user_u32(prio, arg4);
9819 }
9820 break;
9821
9822 /* Not implemented for now... */
9823/* case TARGET_NR_mq_notify: */
9824/* break; */
9825
9826 case TARGET_NR_mq_getsetattr:
9827 {
9828 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9829 ret = 0;
9830 if (arg3 != 0) {
9831 ret = mq_getattr(arg1, &posix_mq_attr_out);
9832 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9833 }
9834 if (arg2 != 0) {
9835 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9836 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9837 }
9838
9839 }
9840 break;
9841#endif
9842
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309843#ifdef CONFIG_SPLICE
9844#ifdef TARGET_NR_tee
9845 case TARGET_NR_tee:
9846 {
9847 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9848 }
9849 break;
9850#endif
9851#ifdef TARGET_NR_splice
9852 case TARGET_NR_splice:
9853 {
9854 loff_t loff_in, loff_out;
9855 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +01009856 if (arg2) {
9857 if (get_user_u64(loff_in, arg2)) {
9858 goto efault;
9859 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309860 ploff_in = &loff_in;
9861 }
Andreas Schwab17644b32015-03-10 17:11:35 +01009862 if (arg4) {
9863 if (get_user_u64(loff_out, arg4)) {
9864 goto efault;
9865 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309866 ploff_out = &loff_out;
9867 }
9868 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +01009869 if (arg2) {
9870 if (put_user_u64(loff_in, arg2)) {
9871 goto efault;
9872 }
9873 }
9874 if (arg4) {
9875 if (put_user_u64(loff_out, arg4)) {
9876 goto efault;
9877 }
9878 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309879 }
9880 break;
9881#endif
9882#ifdef TARGET_NR_vmsplice
9883 case TARGET_NR_vmsplice:
9884 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009885 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9886 if (vec != NULL) {
9887 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9888 unlock_iovec(vec, arg2, arg3, 0);
9889 } else {
9890 ret = -host_to_target_errno(errno);
9891 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309892 }
9893 break;
9894#endif
9895#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009896#ifdef CONFIG_EVENTFD
9897#if defined(TARGET_NR_eventfd)
9898 case TARGET_NR_eventfd:
9899 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +02009900 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009901 break;
9902#endif
9903#if defined(TARGET_NR_eventfd2)
9904 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009905 {
9906 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9907 if (arg2 & TARGET_O_NONBLOCK) {
9908 host_flags |= O_NONBLOCK;
9909 }
9910 if (arg2 & TARGET_O_CLOEXEC) {
9911 host_flags |= O_CLOEXEC;
9912 }
9913 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02009914 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009915 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009916 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009917#endif
9918#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009919#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9920 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009921#if TARGET_ABI_BITS == 32
9922 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9923 target_offset64(arg5, arg6)));
9924#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009925 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009926#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009927 break;
9928#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009929#if defined(CONFIG_SYNC_FILE_RANGE)
9930#if defined(TARGET_NR_sync_file_range)
9931 case TARGET_NR_sync_file_range:
9932#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009933#if defined(TARGET_MIPS)
9934 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9935 target_offset64(arg5, arg6), arg7));
9936#else
Peter Maydellc727f472011-01-06 11:05:10 +00009937 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9938 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009939#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009940#else
9941 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9942#endif
9943 break;
9944#endif
9945#if defined(TARGET_NR_sync_file_range2)
9946 case TARGET_NR_sync_file_range2:
9947 /* This is like sync_file_range but the arguments are reordered */
9948#if TARGET_ABI_BITS == 32
9949 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9950 target_offset64(arg5, arg6), arg2));
9951#else
9952 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9953#endif
9954 break;
9955#endif
9956#endif
Laurent Viviere36800c2015-10-02 14:48:09 +02009957#if defined(TARGET_NR_signalfd4)
9958 case TARGET_NR_signalfd4:
9959 ret = do_signalfd4(arg1, arg2, arg4);
9960 break;
9961#endif
9962#if defined(TARGET_NR_signalfd)
9963 case TARGET_NR_signalfd:
9964 ret = do_signalfd4(arg1, arg2, 0);
9965 break;
9966#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009967#if defined(CONFIG_EPOLL)
9968#if defined(TARGET_NR_epoll_create)
9969 case TARGET_NR_epoll_create:
9970 ret = get_errno(epoll_create(arg1));
9971 break;
9972#endif
9973#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9974 case TARGET_NR_epoll_create1:
9975 ret = get_errno(epoll_create1(arg1));
9976 break;
9977#endif
9978#if defined(TARGET_NR_epoll_ctl)
9979 case TARGET_NR_epoll_ctl:
9980 {
9981 struct epoll_event ep;
9982 struct epoll_event *epp = 0;
9983 if (arg4) {
9984 struct target_epoll_event *target_ep;
9985 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9986 goto efault;
9987 }
9988 ep.events = tswap32(target_ep->events);
9989 /* The epoll_data_t union is just opaque data to the kernel,
9990 * so we transfer all 64 bits across and need not worry what
9991 * actual data type it is.
9992 */
9993 ep.data.u64 = tswap64(target_ep->data.u64);
9994 unlock_user_struct(target_ep, arg4, 0);
9995 epp = &ep;
9996 }
9997 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9998 break;
9999 }
10000#endif
10001
10002#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
10003#define IMPLEMENT_EPOLL_PWAIT
10004#endif
10005#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
10006#if defined(TARGET_NR_epoll_wait)
10007 case TARGET_NR_epoll_wait:
10008#endif
10009#if defined(IMPLEMENT_EPOLL_PWAIT)
10010 case TARGET_NR_epoll_pwait:
10011#endif
10012 {
10013 struct target_epoll_event *target_ep;
10014 struct epoll_event *ep;
10015 int epfd = arg1;
10016 int maxevents = arg3;
10017 int timeout = arg4;
10018
10019 target_ep = lock_user(VERIFY_WRITE, arg2,
10020 maxevents * sizeof(struct target_epoll_event), 1);
10021 if (!target_ep) {
10022 goto efault;
10023 }
10024
10025 ep = alloca(maxevents * sizeof(struct epoll_event));
10026
10027 switch (num) {
10028#if defined(IMPLEMENT_EPOLL_PWAIT)
10029 case TARGET_NR_epoll_pwait:
10030 {
10031 target_sigset_t *target_set;
10032 sigset_t _set, *set = &_set;
10033
10034 if (arg5) {
10035 target_set = lock_user(VERIFY_READ, arg5,
10036 sizeof(target_sigset_t), 1);
10037 if (!target_set) {
10038 unlock_user(target_ep, arg2, 0);
10039 goto efault;
10040 }
10041 target_to_host_sigset(set, target_set);
10042 unlock_user(target_set, arg5, 0);
10043 } else {
10044 set = NULL;
10045 }
10046
10047 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
10048 break;
10049 }
10050#endif
10051#if defined(TARGET_NR_epoll_wait)
10052 case TARGET_NR_epoll_wait:
10053 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
10054 break;
10055#endif
10056 default:
10057 ret = -TARGET_ENOSYS;
10058 }
10059 if (!is_error(ret)) {
10060 int i;
10061 for (i = 0; i < ret; i++) {
10062 target_ep[i].events = tswap32(ep[i].events);
10063 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10064 }
10065 }
10066 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10067 break;
10068 }
10069#endif
10070#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010071#ifdef TARGET_NR_prlimit64
10072 case TARGET_NR_prlimit64:
10073 {
10074 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10075 struct target_rlimit64 *target_rnew, *target_rold;
10076 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010077 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010078 if (arg3) {
10079 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10080 goto efault;
10081 }
10082 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10083 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10084 unlock_user_struct(target_rnew, arg3, 0);
10085 rnewp = &rnew;
10086 }
10087
Felix Janda95018012014-12-02 22:11:17 +010010088 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010089 if (!is_error(ret) && arg4) {
10090 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10091 goto efault;
10092 }
10093 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10094 target_rold->rlim_max = tswap64(rold.rlim_max);
10095 unlock_user_struct(target_rold, arg4, 1);
10096 }
10097 break;
10098 }
10099#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010100#ifdef TARGET_NR_gethostname
10101 case TARGET_NR_gethostname:
10102 {
10103 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10104 if (name) {
10105 ret = get_errno(gethostname(name, arg2));
10106 unlock_user(name, arg1, arg2);
10107 } else {
10108 ret = -TARGET_EFAULT;
10109 }
10110 break;
10111 }
10112#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010113#ifdef TARGET_NR_atomic_cmpxchg_32
10114 case TARGET_NR_atomic_cmpxchg_32:
10115 {
10116 /* should use start_exclusive from main.c */
10117 abi_ulong mem_value;
10118 if (get_user_u32(mem_value, arg6)) {
10119 target_siginfo_t info;
10120 info.si_signo = SIGSEGV;
10121 info.si_errno = 0;
10122 info.si_code = TARGET_SEGV_MAPERR;
10123 info._sifields._sigfault._addr = arg6;
10124 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10125 ret = 0xdeadbeef;
10126
10127 }
10128 if (mem_value == arg2)
10129 put_user_u32(arg1, arg6);
10130 ret = mem_value;
10131 break;
10132 }
10133#endif
10134#ifdef TARGET_NR_atomic_barrier
10135 case TARGET_NR_atomic_barrier:
10136 {
10137 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010138 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010139 break;
10140 }
10141#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010142
10143#ifdef TARGET_NR_timer_create
10144 case TARGET_NR_timer_create:
10145 {
10146 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10147
10148 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010149
10150 int clkid = arg1;
10151 int timer_index = next_free_host_timer();
10152
10153 if (timer_index < 0) {
10154 ret = -TARGET_EAGAIN;
10155 } else {
10156 timer_t *phtimer = g_posix_timers + timer_index;
10157
10158 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010159 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010160 ret = target_to_host_sigevent(phost_sevp, arg2);
10161 if (ret != 0) {
10162 break;
10163 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010164 }
10165
10166 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10167 if (ret) {
10168 phtimer = NULL;
10169 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010170 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010171 goto efault;
10172 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010173 }
10174 }
10175 break;
10176 }
10177#endif
10178
10179#ifdef TARGET_NR_timer_settime
10180 case TARGET_NR_timer_settime:
10181 {
10182 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
10183 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010184 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010185
Alexander Grafaecc8862014-11-10 21:33:03 +010010186 if (timerid < 0) {
10187 ret = timerid;
10188 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010189 ret = -TARGET_EINVAL;
10190 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010191 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010192 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
10193
10194 target_to_host_itimerspec(&hspec_new, arg3);
10195 ret = get_errno(
10196 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
10197 host_to_target_itimerspec(arg2, &hspec_old);
10198 }
10199 break;
10200 }
10201#endif
10202
10203#ifdef TARGET_NR_timer_gettime
10204 case TARGET_NR_timer_gettime:
10205 {
10206 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010207 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010208
Alexander Grafaecc8862014-11-10 21:33:03 +010010209 if (timerid < 0) {
10210 ret = timerid;
10211 } else if (!arg2) {
10212 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010213 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010214 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010215 struct itimerspec hspec;
10216 ret = get_errno(timer_gettime(htimer, &hspec));
10217
10218 if (host_to_target_itimerspec(arg2, &hspec)) {
10219 ret = -TARGET_EFAULT;
10220 }
10221 }
10222 break;
10223 }
10224#endif
10225
10226#ifdef TARGET_NR_timer_getoverrun
10227 case TARGET_NR_timer_getoverrun:
10228 {
10229 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010230 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010231
Alexander Grafaecc8862014-11-10 21:33:03 +010010232 if (timerid < 0) {
10233 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010234 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010235 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010236 ret = get_errno(timer_getoverrun(htimer));
10237 }
Laurent Viviere36800c2015-10-02 14:48:09 +020010238 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010239 break;
10240 }
10241#endif
10242
10243#ifdef TARGET_NR_timer_delete
10244 case TARGET_NR_timer_delete:
10245 {
10246 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010247 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010248
Alexander Grafaecc8862014-11-10 21:33:03 +010010249 if (timerid < 0) {
10250 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010251 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010252 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010253 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020010254 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010255 }
10256 break;
10257 }
10258#endif
10259
Riku Voipio51834342014-06-22 11:25:42 +010010260#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
10261 case TARGET_NR_timerfd_create:
10262 ret = get_errno(timerfd_create(arg1,
10263 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
10264 break;
10265#endif
10266
10267#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
10268 case TARGET_NR_timerfd_gettime:
10269 {
10270 struct itimerspec its_curr;
10271
10272 ret = get_errno(timerfd_gettime(arg1, &its_curr));
10273
10274 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
10275 goto efault;
10276 }
10277 }
10278 break;
10279#endif
10280
10281#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
10282 case TARGET_NR_timerfd_settime:
10283 {
10284 struct itimerspec its_new, its_old, *p_new;
10285
10286 if (arg3) {
10287 if (target_to_host_itimerspec(&its_new, arg3)) {
10288 goto efault;
10289 }
10290 p_new = &its_new;
10291 } else {
10292 p_new = NULL;
10293 }
10294
10295 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
10296
10297 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
10298 goto efault;
10299 }
10300 }
10301 break;
10302#endif
10303
Paul Burtonab31cda2014-06-22 11:25:43 +010010304#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
10305 case TARGET_NR_ioprio_get:
10306 ret = get_errno(ioprio_get(arg1, arg2));
10307 break;
10308#endif
10309
10310#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
10311 case TARGET_NR_ioprio_set:
10312 ret = get_errno(ioprio_set(arg1, arg2, arg3));
10313 break;
10314#endif
10315
Riku Voipio9af5c902014-08-12 15:58:57 +030010316#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
10317 case TARGET_NR_setns:
10318 ret = get_errno(setns(arg1, arg2));
10319 break;
10320#endif
10321#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
10322 case TARGET_NR_unshare:
10323 ret = get_errno(unshare(arg1));
10324 break;
10325#endif
10326
bellard31e31b82003-02-18 22:55:36 +000010327 default:
10328 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000010329 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000010330#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 +000010331 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000010332#endif
ths0da46a62007-10-20 20:23:07 +000010333 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000010334 break;
10335 }
bellard579a97f2007-11-11 14:26:47 +000010336fail:
bellardc573ff62004-01-04 15:51:36 +000010337#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000010338 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000010339#endif
thsb92c47c2007-11-01 00:07:38 +000010340 if(do_strace)
10341 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000010342 return ret;
bellard579a97f2007-11-11 14:26:47 +000010343efault:
10344 ret = -TARGET_EFAULT;
10345 goto fail;
bellard31e31b82003-02-18 22:55:36 +000010346}