blob: dea827fe04369ada9ab1e4c035b2ebacff4111f7 [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
Mike Frysinger055e0902011-06-03 17:01:49 -0400433#if defined(TARGET_NR_pselect6)
434#ifndef __NR_pselect6
435# define __NR_pselect6 -1
436#endif
437#define __NR_sys_pselect6 __NR_pselect6
438_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
439 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
440#endif
441
Peter Maydell163a05a2011-06-27 17:44:52 +0100442#if defined(TARGET_NR_prlimit64)
443#ifndef __NR_prlimit64
444# define __NR_prlimit64 -1
445#endif
446#define __NR_sys_prlimit64 __NR_prlimit64
447/* The glibc rlimit structure may not be that used by the underlying syscall */
448struct host_rlimit64 {
449 uint64_t rlim_cur;
450 uint64_t rlim_max;
451};
452_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
453 const struct host_rlimit64 *, new_limit,
454 struct host_rlimit64 *, old_limit)
455#endif
456
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100457
458#if defined(TARGET_NR_timer_create)
459/* Maxiumum of 32 active POSIX timers allowed at any one time. */
460static timer_t g_posix_timers[32] = { 0, } ;
461
462static inline int next_free_host_timer(void)
463{
464 int k ;
465 /* FIXME: Does finding the next free slot require a lock? */
466 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
467 if (g_posix_timers[k] == 0) {
468 g_posix_timers[k] = (timer_t) 1;
469 return k;
470 }
471 }
472 return -1;
473}
474#endif
475
Riku Voipio48e515d2011-07-12 15:40:51 +0300476/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000477#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300478static inline int regpairs_aligned(void *cpu_env) {
479 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
480}
481#elif defined(TARGET_MIPS)
482static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000483#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
484/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
485 * of registers which translates to the same as ARM/MIPS, because we start with
486 * r3 as arg1 */
487static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300488#else
489static inline int regpairs_aligned(void *cpu_env) { return 0; }
490#endif
491
thsb92c47c2007-11-01 00:07:38 +0000492#define ERRNO_TABLE_SIZE 1200
493
494/* target_to_host_errno_table[] is initialized from
495 * host_to_target_errno_table[] in syscall_init(). */
496static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
497};
498
ths637947f2007-06-01 12:09:19 +0000499/*
thsfe8f0962007-07-12 10:59:21 +0000500 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000501 * minus the errnos that are not actually generic to all archs.
502 */
thsb92c47c2007-11-01 00:07:38 +0000503static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800504 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000505 [EIDRM] = TARGET_EIDRM,
506 [ECHRNG] = TARGET_ECHRNG,
507 [EL2NSYNC] = TARGET_EL2NSYNC,
508 [EL3HLT] = TARGET_EL3HLT,
509 [EL3RST] = TARGET_EL3RST,
510 [ELNRNG] = TARGET_ELNRNG,
511 [EUNATCH] = TARGET_EUNATCH,
512 [ENOCSI] = TARGET_ENOCSI,
513 [EL2HLT] = TARGET_EL2HLT,
514 [EDEADLK] = TARGET_EDEADLK,
515 [ENOLCK] = TARGET_ENOLCK,
516 [EBADE] = TARGET_EBADE,
517 [EBADR] = TARGET_EBADR,
518 [EXFULL] = TARGET_EXFULL,
519 [ENOANO] = TARGET_ENOANO,
520 [EBADRQC] = TARGET_EBADRQC,
521 [EBADSLT] = TARGET_EBADSLT,
522 [EBFONT] = TARGET_EBFONT,
523 [ENOSTR] = TARGET_ENOSTR,
524 [ENODATA] = TARGET_ENODATA,
525 [ETIME] = TARGET_ETIME,
526 [ENOSR] = TARGET_ENOSR,
527 [ENONET] = TARGET_ENONET,
528 [ENOPKG] = TARGET_ENOPKG,
529 [EREMOTE] = TARGET_EREMOTE,
530 [ENOLINK] = TARGET_ENOLINK,
531 [EADV] = TARGET_EADV,
532 [ESRMNT] = TARGET_ESRMNT,
533 [ECOMM] = TARGET_ECOMM,
534 [EPROTO] = TARGET_EPROTO,
535 [EDOTDOT] = TARGET_EDOTDOT,
536 [EMULTIHOP] = TARGET_EMULTIHOP,
537 [EBADMSG] = TARGET_EBADMSG,
538 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
539 [EOVERFLOW] = TARGET_EOVERFLOW,
540 [ENOTUNIQ] = TARGET_ENOTUNIQ,
541 [EBADFD] = TARGET_EBADFD,
542 [EREMCHG] = TARGET_EREMCHG,
543 [ELIBACC] = TARGET_ELIBACC,
544 [ELIBBAD] = TARGET_ELIBBAD,
545 [ELIBSCN] = TARGET_ELIBSCN,
546 [ELIBMAX] = TARGET_ELIBMAX,
547 [ELIBEXEC] = TARGET_ELIBEXEC,
548 [EILSEQ] = TARGET_EILSEQ,
549 [ENOSYS] = TARGET_ENOSYS,
550 [ELOOP] = TARGET_ELOOP,
551 [ERESTART] = TARGET_ERESTART,
552 [ESTRPIPE] = TARGET_ESTRPIPE,
553 [ENOTEMPTY] = TARGET_ENOTEMPTY,
554 [EUSERS] = TARGET_EUSERS,
555 [ENOTSOCK] = TARGET_ENOTSOCK,
556 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
557 [EMSGSIZE] = TARGET_EMSGSIZE,
558 [EPROTOTYPE] = TARGET_EPROTOTYPE,
559 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
560 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
561 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
562 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
563 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
564 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
565 [EADDRINUSE] = TARGET_EADDRINUSE,
566 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
567 [ENETDOWN] = TARGET_ENETDOWN,
568 [ENETUNREACH] = TARGET_ENETUNREACH,
569 [ENETRESET] = TARGET_ENETRESET,
570 [ECONNABORTED] = TARGET_ECONNABORTED,
571 [ECONNRESET] = TARGET_ECONNRESET,
572 [ENOBUFS] = TARGET_ENOBUFS,
573 [EISCONN] = TARGET_EISCONN,
574 [ENOTCONN] = TARGET_ENOTCONN,
575 [EUCLEAN] = TARGET_EUCLEAN,
576 [ENOTNAM] = TARGET_ENOTNAM,
577 [ENAVAIL] = TARGET_ENAVAIL,
578 [EISNAM] = TARGET_EISNAM,
579 [EREMOTEIO] = TARGET_EREMOTEIO,
580 [ESHUTDOWN] = TARGET_ESHUTDOWN,
581 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
582 [ETIMEDOUT] = TARGET_ETIMEDOUT,
583 [ECONNREFUSED] = TARGET_ECONNREFUSED,
584 [EHOSTDOWN] = TARGET_EHOSTDOWN,
585 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
586 [EALREADY] = TARGET_EALREADY,
587 [EINPROGRESS] = TARGET_EINPROGRESS,
588 [ESTALE] = TARGET_ESTALE,
589 [ECANCELED] = TARGET_ECANCELED,
590 [ENOMEDIUM] = TARGET_ENOMEDIUM,
591 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000592#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000593 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000594#endif
595#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000596 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000597#endif
598#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000599 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000600#endif
601#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000602 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000603#endif
604#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000605 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000606#endif
607#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000608 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000609#endif
thsb92c47c2007-11-01 00:07:38 +0000610};
ths637947f2007-06-01 12:09:19 +0000611
612static inline int host_to_target_errno(int err)
613{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100614 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
615 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000616 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100617 }
ths637947f2007-06-01 12:09:19 +0000618 return err;
619}
620
thsb92c47c2007-11-01 00:07:38 +0000621static inline int target_to_host_errno(int err)
622{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100623 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
624 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000625 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100626 }
thsb92c47c2007-11-01 00:07:38 +0000627 return err;
628}
629
blueswir1992f48a2007-10-14 16:27:31 +0000630static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000631{
632 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000633 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000634 else
635 return ret;
636}
637
blueswir1992f48a2007-10-14 16:27:31 +0000638static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000639{
blueswir1992f48a2007-10-14 16:27:31 +0000640 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000641}
642
thsb92c47c2007-11-01 00:07:38 +0000643char *target_strerror(int err)
644{
Alexander Graf962b2892011-11-21 12:04:07 +0100645 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
646 return NULL;
647 }
thsb92c47c2007-11-01 00:07:38 +0000648 return strerror(target_to_host_errno(err));
649}
650
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100651#define safe_syscall0(type, name) \
652static type safe_##name(void) \
653{ \
654 return safe_syscall(__NR_##name); \
655}
656
657#define safe_syscall1(type, name, type1, arg1) \
658static type safe_##name(type1 arg1) \
659{ \
660 return safe_syscall(__NR_##name, arg1); \
661}
662
663#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
664static type safe_##name(type1 arg1, type2 arg2) \
665{ \
666 return safe_syscall(__NR_##name, arg1, arg2); \
667}
668
669#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
670static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
671{ \
672 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
673}
674
675#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
676 type4, arg4) \
677static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
678{ \
679 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
680}
681
682#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
683 type4, arg4, type5, arg5) \
684static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
685 type5 arg5) \
686{ \
687 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
688}
689
690#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
691 type4, arg4, type5, arg5, type6, arg6) \
692static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
693 type5 arg5, type6 arg6) \
694{ \
695 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
696}
697
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100698safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
699safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100700safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
701 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100702safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
703 struct rusage *, rusage)
704safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
705 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100706safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100707
Paul Burton8289d112014-06-22 11:25:33 +0100708static inline int host_to_target_sock_type(int host_type)
709{
710 int target_type;
711
712 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
713 case SOCK_DGRAM:
714 target_type = TARGET_SOCK_DGRAM;
715 break;
716 case SOCK_STREAM:
717 target_type = TARGET_SOCK_STREAM;
718 break;
719 default:
720 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
721 break;
722 }
723
724#if defined(SOCK_CLOEXEC)
725 if (host_type & SOCK_CLOEXEC) {
726 target_type |= TARGET_SOCK_CLOEXEC;
727 }
728#endif
729
730#if defined(SOCK_NONBLOCK)
731 if (host_type & SOCK_NONBLOCK) {
732 target_type |= TARGET_SOCK_NONBLOCK;
733 }
734#endif
735
736 return target_type;
737}
738
blueswir1992f48a2007-10-14 16:27:31 +0000739static abi_ulong target_brk;
740static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000741static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000742
blueswir1992f48a2007-10-14 16:27:31 +0000743void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000744{
blueswir14c1de732007-07-07 20:45:44 +0000745 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000746 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000747}
748
vincent4d1de872011-06-14 21:56:33 +0000749//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
750#define DEBUGF_BRK(message, args...)
751
ths0da46a62007-10-20 20:23:07 +0000752/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000753abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000754{
blueswir1992f48a2007-10-14 16:27:31 +0000755 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000756 int new_alloc_size;
757
Paul Brook3a0c6c42012-02-09 19:04:27 +0000758 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000759
vincent4d1de872011-06-14 21:56:33 +0000760 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000761 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000762 return target_brk;
763 }
764 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000765 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
766 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000767 return target_brk;
768 }
bellard31e31b82003-02-18 22:55:36 +0000769
vincent4d1de872011-06-14 21:56:33 +0000770 /* If the new brk is less than the highest page reserved to the
771 * target heap allocation, set it and we're almost done... */
772 if (new_brk <= brk_page) {
773 /* Heap contents are initialized to zero, as for anonymous
774 * mapped pages. */
775 if (new_brk > target_brk) {
776 memset(g2h(target_brk), 0, new_brk - target_brk);
777 }
bellard31e31b82003-02-18 22:55:36 +0000778 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000779 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000780 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000781 }
782
Peter Maydell00faf082011-04-18 16:34:24 +0100783 /* We need to allocate more memory after the brk... Note that
784 * we don't use MAP_FIXED because that will map over the top of
785 * any existing mapping (like the one with the host libc or qemu
786 * itself); instead we treat "mapped but at wrong address" as
787 * a failure and unmap again.
788 */
vincent4d1de872011-06-14 21:56:33 +0000789 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000790 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000791 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100792 MAP_ANON|MAP_PRIVATE, 0, 0));
793
794 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200795 /* Heap contents are initialized to zero, as for anonymous
796 * mapped pages. Technically the new pages are already
797 * initialized to zero since they *are* anonymous mapped
798 * pages, however we have to take care with the contents that
799 * come from the remaining part of the previous page: it may
800 * contains garbage data due to a previous heap usage (grown
801 * then shrunken). */
802 memset(g2h(target_brk), 0, brk_page - target_brk);
803
Peter Maydell00faf082011-04-18 16:34:24 +0100804 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000805 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000806 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
807 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100808 return target_brk;
809 } else if (mapped_addr != -1) {
810 /* Mapped but at wrong address, meaning there wasn't actually
811 * enough space for this brk.
812 */
813 target_munmap(mapped_addr, new_alloc_size);
814 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000815 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000816 }
817 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000818 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100819 }
balrog7ab240a2008-04-26 12:17:34 +0000820
Richard Henderson7dd46c02010-05-03 10:07:49 -0700821#if defined(TARGET_ALPHA)
822 /* We (partially) emulate OSF/1 on Alpha, which requires we
823 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100824 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700825#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100826 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000827 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000828}
829
ths26edcf42007-12-09 02:25:24 +0000830static inline abi_long copy_from_user_fdset(fd_set *fds,
831 abi_ulong target_fds_addr,
832 int n)
bellard31e31b82003-02-18 22:55:36 +0000833{
ths26edcf42007-12-09 02:25:24 +0000834 int i, nw, j, k;
835 abi_ulong b, *target_fds;
836
837 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
838 if (!(target_fds = lock_user(VERIFY_READ,
839 target_fds_addr,
840 sizeof(abi_ulong) * nw,
841 1)))
842 return -TARGET_EFAULT;
843
844 FD_ZERO(fds);
845 k = 0;
846 for (i = 0; i < nw; i++) {
847 /* grab the abi_ulong */
848 __get_user(b, &target_fds[i]);
849 for (j = 0; j < TARGET_ABI_BITS; j++) {
850 /* check the bit inside the abi_ulong */
851 if ((b >> j) & 1)
852 FD_SET(k, fds);
853 k++;
bellard31e31b82003-02-18 22:55:36 +0000854 }
bellard31e31b82003-02-18 22:55:36 +0000855 }
ths26edcf42007-12-09 02:25:24 +0000856
857 unlock_user(target_fds, target_fds_addr, 0);
858
859 return 0;
bellard31e31b82003-02-18 22:55:36 +0000860}
861
Mike Frysinger055e0902011-06-03 17:01:49 -0400862static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
863 abi_ulong target_fds_addr,
864 int n)
865{
866 if (target_fds_addr) {
867 if (copy_from_user_fdset(fds, target_fds_addr, n))
868 return -TARGET_EFAULT;
869 *fds_ptr = fds;
870 } else {
871 *fds_ptr = NULL;
872 }
873 return 0;
874}
875
ths26edcf42007-12-09 02:25:24 +0000876static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
877 const fd_set *fds,
878 int n)
bellard31e31b82003-02-18 22:55:36 +0000879{
bellard31e31b82003-02-18 22:55:36 +0000880 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000881 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000882 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000883
ths26edcf42007-12-09 02:25:24 +0000884 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
885 if (!(target_fds = lock_user(VERIFY_WRITE,
886 target_fds_addr,
887 sizeof(abi_ulong) * nw,
888 0)))
889 return -TARGET_EFAULT;
890
891 k = 0;
892 for (i = 0; i < nw; i++) {
893 v = 0;
894 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000895 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000896 k++;
bellard31e31b82003-02-18 22:55:36 +0000897 }
ths26edcf42007-12-09 02:25:24 +0000898 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000899 }
ths26edcf42007-12-09 02:25:24 +0000900
901 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
902
903 return 0;
bellard31e31b82003-02-18 22:55:36 +0000904}
905
bellardc596ed12003-07-13 17:32:31 +0000906#if defined(__alpha__)
907#define HOST_HZ 1024
908#else
909#define HOST_HZ 100
910#endif
911
blueswir1992f48a2007-10-14 16:27:31 +0000912static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000913{
914#if HOST_HZ == TARGET_HZ
915 return ticks;
916#else
917 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
918#endif
919}
920
bellard579a97f2007-11-11 14:26:47 +0000921static inline abi_long host_to_target_rusage(abi_ulong target_addr,
922 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000923{
pbrook53a59602006-03-25 19:31:22 +0000924 struct target_rusage *target_rusage;
925
bellard579a97f2007-11-11 14:26:47 +0000926 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
927 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200928 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
929 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
930 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
931 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
932 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
933 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
934 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
935 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
936 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
937 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
938 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
939 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
940 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
941 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
942 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
943 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
944 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
945 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000946 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000947
948 return 0;
bellardb4091862003-05-16 15:39:34 +0000949}
950
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200951static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900952{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200953 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300954 rlim_t result;
955
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200956 target_rlim_swap = tswapal(target_rlim);
957 if (target_rlim_swap == TARGET_RLIM_INFINITY)
958 return RLIM_INFINITY;
959
960 result = target_rlim_swap;
961 if (target_rlim_swap != (rlim_t)result)
962 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300963
964 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900965}
966
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200967static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900968{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200969 abi_ulong target_rlim_swap;
970 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300971
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200972 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300973 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900974 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300975 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200976 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300977
978 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900979}
980
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300981static inline int target_to_host_resource(int code)
982{
983 switch (code) {
984 case TARGET_RLIMIT_AS:
985 return RLIMIT_AS;
986 case TARGET_RLIMIT_CORE:
987 return RLIMIT_CORE;
988 case TARGET_RLIMIT_CPU:
989 return RLIMIT_CPU;
990 case TARGET_RLIMIT_DATA:
991 return RLIMIT_DATA;
992 case TARGET_RLIMIT_FSIZE:
993 return RLIMIT_FSIZE;
994 case TARGET_RLIMIT_LOCKS:
995 return RLIMIT_LOCKS;
996 case TARGET_RLIMIT_MEMLOCK:
997 return RLIMIT_MEMLOCK;
998 case TARGET_RLIMIT_MSGQUEUE:
999 return RLIMIT_MSGQUEUE;
1000 case TARGET_RLIMIT_NICE:
1001 return RLIMIT_NICE;
1002 case TARGET_RLIMIT_NOFILE:
1003 return RLIMIT_NOFILE;
1004 case TARGET_RLIMIT_NPROC:
1005 return RLIMIT_NPROC;
1006 case TARGET_RLIMIT_RSS:
1007 return RLIMIT_RSS;
1008 case TARGET_RLIMIT_RTPRIO:
1009 return RLIMIT_RTPRIO;
1010 case TARGET_RLIMIT_SIGPENDING:
1011 return RLIMIT_SIGPENDING;
1012 case TARGET_RLIMIT_STACK:
1013 return RLIMIT_STACK;
1014 default:
1015 return code;
1016 }
1017}
1018
ths788f5ec2007-12-09 02:37:05 +00001019static inline abi_long copy_from_user_timeval(struct timeval *tv,
1020 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001021{
pbrook53a59602006-03-25 19:31:22 +00001022 struct target_timeval *target_tv;
1023
ths788f5ec2007-12-09 02:37:05 +00001024 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001025 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001026
1027 __get_user(tv->tv_sec, &target_tv->tv_sec);
1028 __get_user(tv->tv_usec, &target_tv->tv_usec);
1029
1030 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001031
1032 return 0;
bellard31e31b82003-02-18 22:55:36 +00001033}
1034
ths788f5ec2007-12-09 02:37:05 +00001035static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1036 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001037{
pbrook53a59602006-03-25 19:31:22 +00001038 struct target_timeval *target_tv;
1039
ths788f5ec2007-12-09 02:37:05 +00001040 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001041 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001042
1043 __put_user(tv->tv_sec, &target_tv->tv_sec);
1044 __put_user(tv->tv_usec, &target_tv->tv_usec);
1045
1046 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001047
1048 return 0;
bellard31e31b82003-02-18 22:55:36 +00001049}
1050
Paul Burtonef4467e2014-06-22 11:25:40 +01001051static inline abi_long copy_from_user_timezone(struct timezone *tz,
1052 abi_ulong target_tz_addr)
1053{
1054 struct target_timezone *target_tz;
1055
1056 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1057 return -TARGET_EFAULT;
1058 }
1059
1060 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1061 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1062
1063 unlock_user_struct(target_tz, target_tz_addr, 0);
1064
1065 return 0;
1066}
1067
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001068#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1069#include <mqueue.h>
1070
aurel3224e10032009-04-15 16:11:43 +00001071static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1072 abi_ulong target_mq_attr_addr)
1073{
1074 struct target_mq_attr *target_mq_attr;
1075
1076 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1077 target_mq_attr_addr, 1))
1078 return -TARGET_EFAULT;
1079
1080 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1081 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1082 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1083 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1084
1085 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1086
1087 return 0;
1088}
1089
1090static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1091 const struct mq_attr *attr)
1092{
1093 struct target_mq_attr *target_mq_attr;
1094
1095 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1096 target_mq_attr_addr, 0))
1097 return -TARGET_EFAULT;
1098
1099 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1100 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1101 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1102 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1103
1104 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1105
1106 return 0;
1107}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001108#endif
bellard31e31b82003-02-18 22:55:36 +00001109
Mike Frysinger055e0902011-06-03 17:01:49 -04001110#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001111/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001112static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001113 abi_ulong rfd_addr, abi_ulong wfd_addr,
1114 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001115{
1116 fd_set rfds, wfds, efds;
1117 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1118 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001119 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001120
Mike Frysinger055e0902011-06-03 17:01:49 -04001121 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1122 if (ret) {
1123 return ret;
pbrook53a59602006-03-25 19:31:22 +00001124 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001125 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1126 if (ret) {
1127 return ret;
pbrook53a59602006-03-25 19:31:22 +00001128 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001129 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1130 if (ret) {
1131 return ret;
pbrook53a59602006-03-25 19:31:22 +00001132 }
ths3b46e622007-09-17 08:09:54 +00001133
ths26edcf42007-12-09 02:25:24 +00001134 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001135 if (copy_from_user_timeval(&tv, target_tv_addr))
1136 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001137 tv_ptr = &tv;
1138 } else {
1139 tv_ptr = NULL;
1140 }
ths26edcf42007-12-09 02:25:24 +00001141
bellard31e31b82003-02-18 22:55:36 +00001142 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001143
ths26edcf42007-12-09 02:25:24 +00001144 if (!is_error(ret)) {
1145 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1146 return -TARGET_EFAULT;
1147 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1148 return -TARGET_EFAULT;
1149 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1150 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001151
ths788f5ec2007-12-09 02:37:05 +00001152 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1153 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001154 }
bellard579a97f2007-11-11 14:26:47 +00001155
bellard31e31b82003-02-18 22:55:36 +00001156 return ret;
1157}
Mike Frysinger055e0902011-06-03 17:01:49 -04001158#endif
bellard31e31b82003-02-18 22:55:36 +00001159
Riku Voipio099d6b02009-05-05 12:10:04 +03001160static abi_long do_pipe2(int host_pipe[], int flags)
1161{
1162#ifdef CONFIG_PIPE2
1163 return pipe2(host_pipe, flags);
1164#else
1165 return -ENOSYS;
1166#endif
1167}
1168
Richard Hendersonfb41a662010-05-03 10:07:52 -07001169static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1170 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001171{
1172 int host_pipe[2];
1173 abi_long ret;
1174 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1175
1176 if (is_error(ret))
1177 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001178
1179 /* Several targets have special calling conventions for the original
1180 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1181 if (!is_pipe2) {
1182#if defined(TARGET_ALPHA)
1183 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1184 return host_pipe[0];
1185#elif defined(TARGET_MIPS)
1186 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1187 return host_pipe[0];
1188#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001189 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001190 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001191#elif defined(TARGET_SPARC)
1192 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1193 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001194#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001195 }
1196
Riku Voipio099d6b02009-05-05 12:10:04 +03001197 if (put_user_s32(host_pipe[0], pipedes)
1198 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1199 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001200 return get_errno(ret);
1201}
1202
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001203static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1204 abi_ulong target_addr,
1205 socklen_t len)
1206{
1207 struct target_ip_mreqn *target_smreqn;
1208
1209 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1210 if (!target_smreqn)
1211 return -TARGET_EFAULT;
1212 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1213 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1214 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001215 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001216 unlock_user(target_smreqn, target_addr, 0);
1217
1218 return 0;
1219}
1220
Laurent Vivier7b36f782015-10-28 21:40:44 +01001221static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001222 abi_ulong target_addr,
1223 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001224{
aurel32607175e2009-04-15 16:11:59 +00001225 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1226 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001227 struct target_sockaddr *target_saddr;
1228
Laurent Vivier7b36f782015-10-28 21:40:44 +01001229 if (fd_trans_target_to_host_addr(fd)) {
1230 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1231 }
1232
bellard579a97f2007-11-11 14:26:47 +00001233 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1234 if (!target_saddr)
1235 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001236
1237 sa_family = tswap16(target_saddr->sa_family);
1238
1239 /* Oops. The caller might send a incomplete sun_path; sun_path
1240 * must be terminated by \0 (see the manual page), but
1241 * unfortunately it is quite common to specify sockaddr_un
1242 * length as "strlen(x->sun_path)" while it should be
1243 * "strlen(...) + 1". We'll fix that here if needed.
1244 * Linux kernel has a similar feature.
1245 */
1246
1247 if (sa_family == AF_UNIX) {
1248 if (len < unix_maxlen && len > 0) {
1249 char *cp = (char*)target_saddr;
1250
1251 if ( cp[len-1] && !cp[len] )
1252 len++;
1253 }
1254 if (len > unix_maxlen)
1255 len = unix_maxlen;
1256 }
1257
pbrook53a59602006-03-25 19:31:22 +00001258 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001259 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001260 if (sa_family == AF_PACKET) {
1261 struct target_sockaddr_ll *lladdr;
1262
1263 lladdr = (struct target_sockaddr_ll *)addr;
1264 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1265 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1266 }
pbrook53a59602006-03-25 19:31:22 +00001267 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001268
1269 return 0;
bellard7854b052003-03-29 17:22:23 +00001270}
1271
bellard579a97f2007-11-11 14:26:47 +00001272static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1273 struct sockaddr *addr,
1274 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001275{
pbrook53a59602006-03-25 19:31:22 +00001276 struct target_sockaddr *target_saddr;
1277
bellard579a97f2007-11-11 14:26:47 +00001278 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1279 if (!target_saddr)
1280 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001281 memcpy(target_saddr, addr, len);
1282 target_saddr->sa_family = tswap16(addr->sa_family);
1283 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001284
1285 return 0;
bellard7854b052003-03-29 17:22:23 +00001286}
1287
bellard5a4a8982007-11-11 17:39:18 +00001288static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1289 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001290{
1291 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001292 abi_long msg_controllen;
1293 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001294 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001295 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001296
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001297 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001298 if (msg_controllen < sizeof (struct target_cmsghdr))
1299 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001300 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001301 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001302 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001303 if (!target_cmsg)
1304 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001305
1306 while (cmsg && target_cmsg) {
1307 void *data = CMSG_DATA(cmsg);
1308 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1309
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001310 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001311 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1312
1313 space += CMSG_SPACE(len);
1314 if (space > msgh->msg_controllen) {
1315 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001316 /* This is a QEMU bug, since we allocated the payload
1317 * area ourselves (unlike overflow in host-to-target
1318 * conversion, which is just the guest giving us a buffer
1319 * that's too small). It can't happen for the payload types
1320 * we currently support; if it becomes an issue in future
1321 * we would need to improve our allocation strategy to
1322 * something more intelligent than "twice the size of the
1323 * target buffer we're reading from".
1324 */
bellard31febb72005-12-18 20:03:27 +00001325 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001326 break;
1327 }
1328
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001329 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1330 cmsg->cmsg_level = SOL_SOCKET;
1331 } else {
1332 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1333 }
bellard7854b052003-03-29 17:22:23 +00001334 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1335 cmsg->cmsg_len = CMSG_LEN(len);
1336
Alex Suykov30b8b682014-12-23 07:52:58 +02001337 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001338 int *fd = (int *)data;
1339 int *target_fd = (int *)target_data;
1340 int i, numfds = len / sizeof(int);
1341
Peter Maydell876e23c2015-05-26 19:46:32 +01001342 for (i = 0; i < numfds; i++) {
1343 __get_user(fd[i], target_fd + i);
1344 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001345 } else if (cmsg->cmsg_level == SOL_SOCKET
1346 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1347 struct ucred *cred = (struct ucred *)data;
1348 struct target_ucred *target_cred =
1349 (struct target_ucred *)target_data;
1350
Peter Maydell876e23c2015-05-26 19:46:32 +01001351 __get_user(cred->pid, &target_cred->pid);
1352 __get_user(cred->uid, &target_cred->uid);
1353 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001354 } else {
1355 gemu_log("Unsupported ancillary data: %d/%d\n",
1356 cmsg->cmsg_level, cmsg->cmsg_type);
1357 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001358 }
1359
1360 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001361 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1362 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001363 }
bellard5a4a8982007-11-11 17:39:18 +00001364 unlock_user(target_cmsg, target_cmsg_addr, 0);
1365 the_end:
bellard7854b052003-03-29 17:22:23 +00001366 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001367 return 0;
bellard7854b052003-03-29 17:22:23 +00001368}
1369
bellard5a4a8982007-11-11 17:39:18 +00001370static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1371 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001372{
1373 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001374 abi_long msg_controllen;
1375 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001376 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001377 socklen_t space = 0;
1378
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001379 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001380 if (msg_controllen < sizeof (struct target_cmsghdr))
1381 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001382 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001383 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001384 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001385 if (!target_cmsg)
1386 return -TARGET_EFAULT;
1387
bellard7854b052003-03-29 17:22:23 +00001388 while (cmsg && target_cmsg) {
1389 void *data = CMSG_DATA(cmsg);
1390 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1391
1392 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001393 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001394
Peter Maydellc2aeb252015-05-26 19:46:31 +01001395 /* We never copy a half-header but may copy half-data;
1396 * this is Linux's behaviour in put_cmsg(). Note that
1397 * truncation here is a guest problem (which we report
1398 * to the guest via the CTRUNC bit), unlike truncation
1399 * in target_to_host_cmsg, which is a QEMU bug.
1400 */
1401 if (msg_controllen < sizeof(struct cmsghdr)) {
1402 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001403 break;
1404 }
1405
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001406 if (cmsg->cmsg_level == SOL_SOCKET) {
1407 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1408 } else {
1409 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1410 }
bellard7854b052003-03-29 17:22:23 +00001411 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001412
Peter Maydellc2aeb252015-05-26 19:46:31 +01001413 tgt_len = TARGET_CMSG_LEN(len);
1414
1415 /* Payload types which need a different size of payload on
1416 * the target must adjust tgt_len here.
1417 */
1418 switch (cmsg->cmsg_level) {
1419 case SOL_SOCKET:
1420 switch (cmsg->cmsg_type) {
1421 case SO_TIMESTAMP:
1422 tgt_len = sizeof(struct target_timeval);
1423 break;
1424 default:
1425 break;
1426 }
1427 default:
1428 break;
1429 }
1430
1431 if (msg_controllen < tgt_len) {
1432 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1433 tgt_len = msg_controllen;
1434 }
1435
1436 /* We must now copy-and-convert len bytes of payload
1437 * into tgt_len bytes of destination space. Bear in mind
1438 * that in both source and destination we may be dealing
1439 * with a truncated value!
1440 */
Huw Davies52b65492014-04-17 14:02:47 +01001441 switch (cmsg->cmsg_level) {
1442 case SOL_SOCKET:
1443 switch (cmsg->cmsg_type) {
1444 case SCM_RIGHTS:
1445 {
1446 int *fd = (int *)data;
1447 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001448 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001449
Peter Maydell876e23c2015-05-26 19:46:32 +01001450 for (i = 0; i < numfds; i++) {
1451 __put_user(fd[i], target_fd + i);
1452 }
Huw Davies52b65492014-04-17 14:02:47 +01001453 break;
1454 }
1455 case SO_TIMESTAMP:
1456 {
1457 struct timeval *tv = (struct timeval *)data;
1458 struct target_timeval *target_tv =
1459 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001460
Peter Maydellc2aeb252015-05-26 19:46:31 +01001461 if (len != sizeof(struct timeval) ||
1462 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001463 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001464 }
Huw Davies52b65492014-04-17 14:02:47 +01001465
1466 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001467 __put_user(tv->tv_sec, &target_tv->tv_sec);
1468 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001469 break;
1470 }
Huw Davies4bc29752014-04-17 14:02:48 +01001471 case SCM_CREDENTIALS:
1472 {
1473 struct ucred *cred = (struct ucred *)data;
1474 struct target_ucred *target_cred =
1475 (struct target_ucred *)target_data;
1476
1477 __put_user(cred->pid, &target_cred->pid);
1478 __put_user(cred->uid, &target_cred->uid);
1479 __put_user(cred->gid, &target_cred->gid);
1480 break;
1481 }
Huw Davies52b65492014-04-17 14:02:47 +01001482 default:
1483 goto unimplemented;
1484 }
1485 break;
1486
1487 default:
1488 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001489 gemu_log("Unsupported ancillary data: %d/%d\n",
1490 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001491 memcpy(target_data, data, MIN(len, tgt_len));
1492 if (tgt_len > len) {
1493 memset(target_data + len, 0, tgt_len - len);
1494 }
bellard7854b052003-03-29 17:22:23 +00001495 }
1496
Peter Maydellc2aeb252015-05-26 19:46:31 +01001497 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001498 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001499 if (msg_controllen < tgt_space) {
1500 tgt_space = msg_controllen;
1501 }
1502 msg_controllen -= tgt_space;
1503 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001504 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001505 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1506 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001507 }
bellard5a4a8982007-11-11 17:39:18 +00001508 unlock_user(target_cmsg, target_cmsg_addr, space);
1509 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001510 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001511 return 0;
bellard7854b052003-03-29 17:22:23 +00001512}
1513
ths0da46a62007-10-20 20:23:07 +00001514/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001515static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001516 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001517{
blueswir1992f48a2007-10-14 16:27:31 +00001518 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001519 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001520 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001521 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001522
bellard8853f862004-02-22 14:57:26 +00001523 switch(level) {
1524 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001525 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001526 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001527 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001528
bellard2f619692007-11-16 10:46:05 +00001529 if (get_user_u32(val, optval_addr))
1530 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001531 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1532 break;
1533 case SOL_IP:
1534 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001535 case IP_TOS:
1536 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001537 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001538 case IP_ROUTER_ALERT:
1539 case IP_RECVOPTS:
1540 case IP_RETOPTS:
1541 case IP_PKTINFO:
1542 case IP_MTU_DISCOVER:
1543 case IP_RECVERR:
1544 case IP_RECVTOS:
1545#ifdef IP_FREEBIND
1546 case IP_FREEBIND:
1547#endif
1548 case IP_MULTICAST_TTL:
1549 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001550 val = 0;
1551 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001552 if (get_user_u32(val, optval_addr))
1553 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001554 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001555 if (get_user_u8(val, optval_addr))
1556 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001557 }
1558 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1559 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001560 case IP_ADD_MEMBERSHIP:
1561 case IP_DROP_MEMBERSHIP:
1562 if (optlen < sizeof (struct target_ip_mreq) ||
1563 optlen > sizeof (struct target_ip_mreqn))
1564 return -TARGET_EINVAL;
1565
1566 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1567 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1568 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1569 break;
1570
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001571 case IP_BLOCK_SOURCE:
1572 case IP_UNBLOCK_SOURCE:
1573 case IP_ADD_SOURCE_MEMBERSHIP:
1574 case IP_DROP_SOURCE_MEMBERSHIP:
1575 if (optlen != sizeof (struct target_ip_mreq_source))
1576 return -TARGET_EINVAL;
1577
1578 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1579 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1580 unlock_user (ip_mreq_source, optval_addr, 0);
1581 break;
1582
bellard8853f862004-02-22 14:57:26 +00001583 default:
1584 goto unimplemented;
1585 }
1586 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001587 case SOL_IPV6:
1588 switch (optname) {
1589 case IPV6_MTU_DISCOVER:
1590 case IPV6_MTU:
1591 case IPV6_V6ONLY:
1592 case IPV6_RECVPKTINFO:
1593 val = 0;
1594 if (optlen < sizeof(uint32_t)) {
1595 return -TARGET_EINVAL;
1596 }
1597 if (get_user_u32(val, optval_addr)) {
1598 return -TARGET_EFAULT;
1599 }
1600 ret = get_errno(setsockopt(sockfd, level, optname,
1601 &val, sizeof(val)));
1602 break;
1603 default:
1604 goto unimplemented;
1605 }
1606 break;
Jing Huang920394d2012-07-24 13:59:23 +00001607 case SOL_RAW:
1608 switch (optname) {
1609 case ICMP_FILTER:
1610 /* struct icmp_filter takes an u32 value */
1611 if (optlen < sizeof(uint32_t)) {
1612 return -TARGET_EINVAL;
1613 }
1614
1615 if (get_user_u32(val, optval_addr)) {
1616 return -TARGET_EFAULT;
1617 }
1618 ret = get_errno(setsockopt(sockfd, level, optname,
1619 &val, sizeof(val)));
1620 break;
1621
1622 default:
1623 goto unimplemented;
1624 }
1625 break;
bellard3532fa72006-06-24 15:06:03 +00001626 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001627 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001628 case TARGET_SO_RCVTIMEO:
1629 {
1630 struct timeval tv;
1631
1632 optname = SO_RCVTIMEO;
1633
1634set_timeout:
1635 if (optlen != sizeof(struct target_timeval)) {
1636 return -TARGET_EINVAL;
1637 }
1638
1639 if (copy_from_user_timeval(&tv, optval_addr)) {
1640 return -TARGET_EFAULT;
1641 }
1642
1643 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1644 &tv, sizeof(tv)));
1645 return ret;
1646 }
1647 case TARGET_SO_SNDTIMEO:
1648 optname = SO_SNDTIMEO;
1649 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001650 case TARGET_SO_ATTACH_FILTER:
1651 {
1652 struct target_sock_fprog *tfprog;
1653 struct target_sock_filter *tfilter;
1654 struct sock_fprog fprog;
1655 struct sock_filter *filter;
1656 int i;
1657
1658 if (optlen != sizeof(*tfprog)) {
1659 return -TARGET_EINVAL;
1660 }
1661 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1662 return -TARGET_EFAULT;
1663 }
1664 if (!lock_user_struct(VERIFY_READ, tfilter,
1665 tswapal(tfprog->filter), 0)) {
1666 unlock_user_struct(tfprog, optval_addr, 1);
1667 return -TARGET_EFAULT;
1668 }
1669
1670 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301671 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001672 if (filter == NULL) {
1673 unlock_user_struct(tfilter, tfprog->filter, 1);
1674 unlock_user_struct(tfprog, optval_addr, 1);
1675 return -TARGET_ENOMEM;
1676 }
1677 for (i = 0; i < fprog.len; i++) {
1678 filter[i].code = tswap16(tfilter[i].code);
1679 filter[i].jt = tfilter[i].jt;
1680 filter[i].jf = tfilter[i].jf;
1681 filter[i].k = tswap32(tfilter[i].k);
1682 }
1683 fprog.filter = filter;
1684
1685 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1686 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301687 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001688
1689 unlock_user_struct(tfilter, tfprog->filter, 1);
1690 unlock_user_struct(tfprog, optval_addr, 1);
1691 return ret;
1692 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001693 case TARGET_SO_BINDTODEVICE:
1694 {
1695 char *dev_ifname, *addr_ifname;
1696
1697 if (optlen > IFNAMSIZ - 1) {
1698 optlen = IFNAMSIZ - 1;
1699 }
1700 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1701 if (!dev_ifname) {
1702 return -TARGET_EFAULT;
1703 }
1704 optname = SO_BINDTODEVICE;
1705 addr_ifname = alloca(IFNAMSIZ);
1706 memcpy(addr_ifname, dev_ifname, optlen);
1707 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08001708 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1709 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001710 unlock_user (dev_ifname, optval_addr, 0);
1711 return ret;
1712 }
bellard8853f862004-02-22 14:57:26 +00001713 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001714 case TARGET_SO_DEBUG:
1715 optname = SO_DEBUG;
1716 break;
1717 case TARGET_SO_REUSEADDR:
1718 optname = SO_REUSEADDR;
1719 break;
1720 case TARGET_SO_TYPE:
1721 optname = SO_TYPE;
1722 break;
1723 case TARGET_SO_ERROR:
1724 optname = SO_ERROR;
1725 break;
1726 case TARGET_SO_DONTROUTE:
1727 optname = SO_DONTROUTE;
1728 break;
1729 case TARGET_SO_BROADCAST:
1730 optname = SO_BROADCAST;
1731 break;
1732 case TARGET_SO_SNDBUF:
1733 optname = SO_SNDBUF;
1734 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001735 case TARGET_SO_SNDBUFFORCE:
1736 optname = SO_SNDBUFFORCE;
1737 break;
bellard3532fa72006-06-24 15:06:03 +00001738 case TARGET_SO_RCVBUF:
1739 optname = SO_RCVBUF;
1740 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001741 case TARGET_SO_RCVBUFFORCE:
1742 optname = SO_RCVBUFFORCE;
1743 break;
bellard3532fa72006-06-24 15:06:03 +00001744 case TARGET_SO_KEEPALIVE:
1745 optname = SO_KEEPALIVE;
1746 break;
1747 case TARGET_SO_OOBINLINE:
1748 optname = SO_OOBINLINE;
1749 break;
1750 case TARGET_SO_NO_CHECK:
1751 optname = SO_NO_CHECK;
1752 break;
1753 case TARGET_SO_PRIORITY:
1754 optname = SO_PRIORITY;
1755 break;
bellard5e83e8e2005-03-01 22:32:06 +00001756#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001757 case TARGET_SO_BSDCOMPAT:
1758 optname = SO_BSDCOMPAT;
1759 break;
bellard5e83e8e2005-03-01 22:32:06 +00001760#endif
bellard3532fa72006-06-24 15:06:03 +00001761 case TARGET_SO_PASSCRED:
1762 optname = SO_PASSCRED;
1763 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001764 case TARGET_SO_PASSSEC:
1765 optname = SO_PASSSEC;
1766 break;
bellard3532fa72006-06-24 15:06:03 +00001767 case TARGET_SO_TIMESTAMP:
1768 optname = SO_TIMESTAMP;
1769 break;
1770 case TARGET_SO_RCVLOWAT:
1771 optname = SO_RCVLOWAT;
1772 break;
bellard8853f862004-02-22 14:57:26 +00001773 break;
1774 default:
1775 goto unimplemented;
1776 }
bellard3532fa72006-06-24 15:06:03 +00001777 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001778 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001779
bellard2f619692007-11-16 10:46:05 +00001780 if (get_user_u32(val, optval_addr))
1781 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001782 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001783 break;
bellard7854b052003-03-29 17:22:23 +00001784 default:
bellard8853f862004-02-22 14:57:26 +00001785 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001786 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001787 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001788 }
bellard8853f862004-02-22 14:57:26 +00001789 return ret;
bellard7854b052003-03-29 17:22:23 +00001790}
1791
ths0da46a62007-10-20 20:23:07 +00001792/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001793static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001794 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001795{
blueswir1992f48a2007-10-14 16:27:31 +00001796 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001797 int len, val;
1798 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001799
1800 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001801 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001802 level = SOL_SOCKET;
1803 switch (optname) {
1804 /* These don't just return a single integer */
1805 case TARGET_SO_LINGER:
1806 case TARGET_SO_RCVTIMEO:
1807 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001808 case TARGET_SO_PEERNAME:
1809 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001810 case TARGET_SO_PEERCRED: {
1811 struct ucred cr;
1812 socklen_t crlen;
1813 struct target_ucred *tcr;
1814
1815 if (get_user_u32(len, optlen)) {
1816 return -TARGET_EFAULT;
1817 }
1818 if (len < 0) {
1819 return -TARGET_EINVAL;
1820 }
1821
1822 crlen = sizeof(cr);
1823 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1824 &cr, &crlen));
1825 if (ret < 0) {
1826 return ret;
1827 }
1828 if (len > crlen) {
1829 len = crlen;
1830 }
1831 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1832 return -TARGET_EFAULT;
1833 }
1834 __put_user(cr.pid, &tcr->pid);
1835 __put_user(cr.uid, &tcr->uid);
1836 __put_user(cr.gid, &tcr->gid);
1837 unlock_user_struct(tcr, optval_addr, 1);
1838 if (put_user_u32(len, optlen)) {
1839 return -TARGET_EFAULT;
1840 }
1841 break;
1842 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001843 /* Options with 'int' argument. */
1844 case TARGET_SO_DEBUG:
1845 optname = SO_DEBUG;
1846 goto int_case;
1847 case TARGET_SO_REUSEADDR:
1848 optname = SO_REUSEADDR;
1849 goto int_case;
1850 case TARGET_SO_TYPE:
1851 optname = SO_TYPE;
1852 goto int_case;
1853 case TARGET_SO_ERROR:
1854 optname = SO_ERROR;
1855 goto int_case;
1856 case TARGET_SO_DONTROUTE:
1857 optname = SO_DONTROUTE;
1858 goto int_case;
1859 case TARGET_SO_BROADCAST:
1860 optname = SO_BROADCAST;
1861 goto int_case;
1862 case TARGET_SO_SNDBUF:
1863 optname = SO_SNDBUF;
1864 goto int_case;
1865 case TARGET_SO_RCVBUF:
1866 optname = SO_RCVBUF;
1867 goto int_case;
1868 case TARGET_SO_KEEPALIVE:
1869 optname = SO_KEEPALIVE;
1870 goto int_case;
1871 case TARGET_SO_OOBINLINE:
1872 optname = SO_OOBINLINE;
1873 goto int_case;
1874 case TARGET_SO_NO_CHECK:
1875 optname = SO_NO_CHECK;
1876 goto int_case;
1877 case TARGET_SO_PRIORITY:
1878 optname = SO_PRIORITY;
1879 goto int_case;
1880#ifdef SO_BSDCOMPAT
1881 case TARGET_SO_BSDCOMPAT:
1882 optname = SO_BSDCOMPAT;
1883 goto int_case;
1884#endif
1885 case TARGET_SO_PASSCRED:
1886 optname = SO_PASSCRED;
1887 goto int_case;
1888 case TARGET_SO_TIMESTAMP:
1889 optname = SO_TIMESTAMP;
1890 goto int_case;
1891 case TARGET_SO_RCVLOWAT:
1892 optname = SO_RCVLOWAT;
1893 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001894 case TARGET_SO_ACCEPTCONN:
1895 optname = SO_ACCEPTCONN;
1896 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001897 default:
bellard2efbe912005-07-23 15:10:20 +00001898 goto int_case;
1899 }
1900 break;
1901 case SOL_TCP:
1902 /* TCP options all take an 'int' value. */
1903 int_case:
bellard2f619692007-11-16 10:46:05 +00001904 if (get_user_u32(len, optlen))
1905 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001906 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001907 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001908 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001909 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1910 if (ret < 0)
1911 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001912 if (optname == SO_TYPE) {
1913 val = host_to_target_sock_type(val);
1914 }
bellard2efbe912005-07-23 15:10:20 +00001915 if (len > lv)
1916 len = lv;
bellard2f619692007-11-16 10:46:05 +00001917 if (len == 4) {
1918 if (put_user_u32(val, optval_addr))
1919 return -TARGET_EFAULT;
1920 } else {
1921 if (put_user_u8(val, optval_addr))
1922 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001923 }
bellard2f619692007-11-16 10:46:05 +00001924 if (put_user_u32(len, optlen))
1925 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001926 break;
1927 case SOL_IP:
1928 switch(optname) {
1929 case IP_TOS:
1930 case IP_TTL:
1931 case IP_HDRINCL:
1932 case IP_ROUTER_ALERT:
1933 case IP_RECVOPTS:
1934 case IP_RETOPTS:
1935 case IP_PKTINFO:
1936 case IP_MTU_DISCOVER:
1937 case IP_RECVERR:
1938 case IP_RECVTOS:
1939#ifdef IP_FREEBIND
1940 case IP_FREEBIND:
1941#endif
1942 case IP_MULTICAST_TTL:
1943 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001944 if (get_user_u32(len, optlen))
1945 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001946 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001947 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001948 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001949 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1950 if (ret < 0)
1951 return ret;
bellard2efbe912005-07-23 15:10:20 +00001952 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001953 len = 1;
bellard2f619692007-11-16 10:46:05 +00001954 if (put_user_u32(len, optlen)
1955 || put_user_u8(val, optval_addr))
1956 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001957 } else {
bellard2efbe912005-07-23 15:10:20 +00001958 if (len > sizeof(int))
1959 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001960 if (put_user_u32(len, optlen)
1961 || put_user_u32(val, optval_addr))
1962 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001963 }
bellard8853f862004-02-22 14:57:26 +00001964 break;
bellard2efbe912005-07-23 15:10:20 +00001965 default:
thsc02f4992007-12-18 02:39:59 +00001966 ret = -TARGET_ENOPROTOOPT;
1967 break;
bellard8853f862004-02-22 14:57:26 +00001968 }
1969 break;
1970 default:
1971 unimplemented:
1972 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1973 level, optname);
thsc02f4992007-12-18 02:39:59 +00001974 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001975 break;
1976 }
1977 return ret;
bellard7854b052003-03-29 17:22:23 +00001978}
1979
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001980static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1981 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001982{
1983 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001984 struct iovec *vec;
1985 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001986 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001987 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001988 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001989
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001990 if (count == 0) {
1991 errno = 0;
1992 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001993 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001994 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001995 errno = EINVAL;
1996 return NULL;
1997 }
1998
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301999 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002000 if (vec == NULL) {
2001 errno = ENOMEM;
2002 return NULL;
2003 }
2004
2005 target_vec = lock_user(VERIFY_READ, target_addr,
2006 count * sizeof(struct target_iovec), 1);
2007 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002008 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002009 goto fail2;
2010 }
2011
2012 /* ??? If host page size > target page size, this will result in a
2013 value larger than what we can actually support. */
2014 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2015 total_len = 0;
2016
2017 for (i = 0; i < count; i++) {
2018 abi_ulong base = tswapal(target_vec[i].iov_base);
2019 abi_long len = tswapal(target_vec[i].iov_len);
2020
2021 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002022 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002023 goto fail;
2024 } else if (len == 0) {
2025 /* Zero length pointer is ignored. */
2026 vec[i].iov_base = 0;
2027 } else {
2028 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002029 /* If the first buffer pointer is bad, this is a fault. But
2030 * subsequent bad buffers will result in a partial write; this
2031 * is realized by filling the vector with null pointers and
2032 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002033 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002034 if (i == 0) {
2035 err = EFAULT;
2036 goto fail;
2037 } else {
2038 bad_address = true;
2039 }
2040 }
2041 if (bad_address) {
2042 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002043 }
2044 if (len > max_len - total_len) {
2045 len = max_len - total_len;
2046 }
2047 }
2048 vec[i].iov_len = len;
2049 total_len += len;
2050 }
2051
2052 unlock_user(target_vec, target_addr, 0);
2053 return vec;
2054
2055 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002056 while (--i >= 0) {
2057 if (tswapal(target_vec[i].iov_len) > 0) {
2058 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2059 }
2060 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002061 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002062 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302063 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002064 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002065 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002066}
2067
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002068static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2069 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002070{
2071 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002072 int i;
2073
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002074 target_vec = lock_user(VERIFY_READ, target_addr,
2075 count * sizeof(struct target_iovec), 1);
2076 if (target_vec) {
2077 for (i = 0; i < count; i++) {
2078 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002079 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002080 if (len < 0) {
2081 break;
2082 }
balrogd732dcb2008-10-28 10:21:03 +00002083 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2084 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002085 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002086 }
bellard579a97f2007-11-11 14:26:47 +00002087
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302088 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002089}
2090
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002091static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002092{
2093 int host_type = 0;
2094 int target_type = *type;
2095
2096 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2097 case TARGET_SOCK_DGRAM:
2098 host_type = SOCK_DGRAM;
2099 break;
2100 case TARGET_SOCK_STREAM:
2101 host_type = SOCK_STREAM;
2102 break;
2103 default:
2104 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2105 break;
2106 }
2107 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002108#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002109 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002110#else
2111 return -TARGET_EINVAL;
2112#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002113 }
2114 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002115#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002116 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002117#elif !defined(O_NONBLOCK)
2118 return -TARGET_EINVAL;
2119#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002120 }
2121 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002122 return 0;
2123}
2124
2125/* Try to emulate socket type flags after socket creation. */
2126static int sock_flags_fixup(int fd, int target_type)
2127{
2128#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2129 if (target_type & TARGET_SOCK_NONBLOCK) {
2130 int flags = fcntl(fd, F_GETFL);
2131 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2132 close(fd);
2133 return -TARGET_EINVAL;
2134 }
2135 }
2136#endif
2137 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002138}
2139
Laurent Vivier0cf22722015-10-28 21:40:45 +01002140static abi_long packet_target_to_host_sockaddr(void *host_addr,
2141 abi_ulong target_addr,
2142 socklen_t len)
2143{
2144 struct sockaddr *addr = host_addr;
2145 struct target_sockaddr *target_saddr;
2146
2147 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2148 if (!target_saddr) {
2149 return -TARGET_EFAULT;
2150 }
2151
2152 memcpy(addr, target_saddr, len);
2153 addr->sa_family = tswap16(target_saddr->sa_family);
2154 /* spkt_protocol is big-endian */
2155
2156 unlock_user(target_saddr, target_addr, 0);
2157 return 0;
2158}
2159
2160static TargetFdTrans target_packet_trans = {
2161 .target_to_host_addr = packet_target_to_host_sockaddr,
2162};
2163
ths0da46a62007-10-20 20:23:07 +00002164/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002165static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002166{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002167 int target_type = type;
2168 int ret;
2169
2170 ret = target_to_host_sock_type(&type);
2171 if (ret) {
2172 return ret;
2173 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002174
balrog12bc92a2007-10-30 21:06:14 +00002175 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07002176 return -TARGET_EAFNOSUPPORT;
Laurent Vivierff626f22015-10-28 21:40:42 +01002177
2178 if (domain == AF_PACKET ||
2179 (domain == AF_INET && type == SOCK_PACKET)) {
2180 protocol = tswap16(protocol);
2181 }
2182
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002183 ret = get_errno(socket(domain, type, protocol));
2184 if (ret >= 0) {
2185 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002186 if (type == SOCK_PACKET) {
2187 /* Manage an obsolete case :
2188 * if socket type is SOCK_PACKET, bind by name
2189 */
2190 fd_trans_register(ret, &target_packet_trans);
2191 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002192 }
2193 return ret;
bellard3532fa72006-06-24 15:06:03 +00002194}
2195
ths0da46a62007-10-20 20:23:07 +00002196/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002197static abi_long do_bind(int sockfd, abi_ulong target_addr,
2198 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002199{
aurel328f7aeaf2009-01-30 19:47:57 +00002200 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002201 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002202
Blue Swirl38724252010-09-18 05:53:14 +00002203 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002204 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002205 }
aurel328f7aeaf2009-01-30 19:47:57 +00002206
aurel32607175e2009-04-15 16:11:59 +00002207 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002208
Laurent Vivier7b36f782015-10-28 21:40:44 +01002209 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002210 if (ret)
2211 return ret;
2212
bellard3532fa72006-06-24 15:06:03 +00002213 return get_errno(bind(sockfd, addr, addrlen));
2214}
2215
ths0da46a62007-10-20 20:23:07 +00002216/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002217static abi_long do_connect(int sockfd, abi_ulong target_addr,
2218 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002219{
aurel328f7aeaf2009-01-30 19:47:57 +00002220 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002221 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002222
Blue Swirl38724252010-09-18 05:53:14 +00002223 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002224 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002225 }
aurel328f7aeaf2009-01-30 19:47:57 +00002226
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002227 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002228
Laurent Vivier7b36f782015-10-28 21:40:44 +01002229 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002230 if (ret)
2231 return ret;
2232
bellard3532fa72006-06-24 15:06:03 +00002233 return get_errno(connect(sockfd, addr, addrlen));
2234}
2235
Alexander Graff19e00d2014-03-02 19:36:42 +00002236/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2237static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2238 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002239{
balrog6de645c2008-10-28 10:26:29 +00002240 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002241 struct msghdr msg;
2242 int count;
2243 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002244 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002245
bellard3532fa72006-06-24 15:06:03 +00002246 if (msgp->msg_name) {
2247 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002248 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002249 ret = target_to_host_sockaddr(fd, msg.msg_name,
2250 tswapal(msgp->msg_name),
2251 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002252 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002253 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002254 }
bellard3532fa72006-06-24 15:06:03 +00002255 } else {
2256 msg.msg_name = NULL;
2257 msg.msg_namelen = 0;
2258 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002259 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002260 msg.msg_control = alloca(msg.msg_controllen);
2261 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002262
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002263 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002264 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002265 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2266 target_vec, count, send);
2267 if (vec == NULL) {
2268 ret = -host_to_target_errno(errno);
2269 goto out2;
2270 }
bellard3532fa72006-06-24 15:06:03 +00002271 msg.msg_iovlen = count;
2272 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002273
bellard3532fa72006-06-24 15:06:03 +00002274 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002275 ret = target_to_host_cmsg(&msg, msgp);
2276 if (ret == 0)
2277 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002278 } else {
2279 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002280 if (!is_error(ret)) {
2281 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002282 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002283 if (!is_error(ret)) {
2284 msgp->msg_namelen = tswap32(msg.msg_namelen);
2285 if (msg.msg_name != NULL) {
2286 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2287 msg.msg_name, msg.msg_namelen);
2288 if (ret) {
2289 goto out;
2290 }
2291 }
2292
balrog6de645c2008-10-28 10:26:29 +00002293 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002294 }
balrog6de645c2008-10-28 10:26:29 +00002295 }
bellard3532fa72006-06-24 15:06:03 +00002296 }
Jing Huangca619062012-07-24 13:58:02 +00002297
2298out:
bellard3532fa72006-06-24 15:06:03 +00002299 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002300out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002301 return ret;
2302}
2303
2304static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2305 int flags, int send)
2306{
2307 abi_long ret;
2308 struct target_msghdr *msgp;
2309
2310 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2311 msgp,
2312 target_msg,
2313 send ? 1 : 0)) {
2314 return -TARGET_EFAULT;
2315 }
2316 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002317 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002318 return ret;
2319}
2320
Alexander Graff19e00d2014-03-02 19:36:42 +00002321/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2322 * so it might not have this *mmsg-specific flag either.
2323 */
2324#ifndef MSG_WAITFORONE
2325#define MSG_WAITFORONE 0x10000
2326#endif
2327
2328static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2329 unsigned int vlen, unsigned int flags,
2330 int send)
2331{
2332 struct target_mmsghdr *mmsgp;
2333 abi_long ret = 0;
2334 int i;
2335
2336 if (vlen > UIO_MAXIOV) {
2337 vlen = UIO_MAXIOV;
2338 }
2339
2340 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2341 if (!mmsgp) {
2342 return -TARGET_EFAULT;
2343 }
2344
2345 for (i = 0; i < vlen; i++) {
2346 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2347 if (is_error(ret)) {
2348 break;
2349 }
2350 mmsgp[i].msg_len = tswap32(ret);
2351 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2352 if (flags & MSG_WAITFORONE) {
2353 flags |= MSG_DONTWAIT;
2354 }
2355 }
2356
2357 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2358
2359 /* Return number of datagrams sent if we sent any at all;
2360 * otherwise return the error.
2361 */
2362 if (i) {
2363 return i;
2364 }
2365 return ret;
2366}
Alexander Graff19e00d2014-03-02 19:36:42 +00002367
Peter Maydella94b4982013-02-08 04:35:04 +00002368/* If we don't have a system accept4() then just call accept.
2369 * The callsites to do_accept4() will ensure that they don't
2370 * pass a non-zero flags argument in this config.
2371 */
2372#ifndef CONFIG_ACCEPT4
2373static inline int accept4(int sockfd, struct sockaddr *addr,
2374 socklen_t *addrlen, int flags)
2375{
2376 assert(flags == 0);
2377 return accept(sockfd, addr, addrlen);
2378}
2379#endif
2380
2381/* do_accept4() Must return target values and target errnos. */
2382static abi_long do_accept4(int fd, abi_ulong target_addr,
2383 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002384{
bellard2f619692007-11-16 10:46:05 +00002385 socklen_t addrlen;
2386 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002387 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002388 int host_flags;
2389
2390 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002391
Peter Maydella94b4982013-02-08 04:35:04 +00002392 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002393 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002394 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002395
2396 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002397 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002398 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002399
Blue Swirl38724252010-09-18 05:53:14 +00002400 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002401 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002402 }
aurel328f7aeaf2009-01-30 19:47:57 +00002403
Arnaud Patard917507b2009-06-19 10:44:45 +03002404 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2405 return -TARGET_EINVAL;
2406
bellard2f619692007-11-16 10:46:05 +00002407 addr = alloca(addrlen);
2408
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002409 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002410 if (!is_error(ret)) {
2411 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002412 if (put_user_u32(addrlen, target_addrlen_addr))
2413 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002414 }
2415 return ret;
2416}
2417
ths0da46a62007-10-20 20:23:07 +00002418/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002419static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002420 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002421{
bellard2f619692007-11-16 10:46:05 +00002422 socklen_t addrlen;
2423 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002424 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002425
bellard2f619692007-11-16 10:46:05 +00002426 if (get_user_u32(addrlen, target_addrlen_addr))
2427 return -TARGET_EFAULT;
2428
Blue Swirl38724252010-09-18 05:53:14 +00002429 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002430 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002431 }
aurel328f7aeaf2009-01-30 19:47:57 +00002432
Arnaud Patard917507b2009-06-19 10:44:45 +03002433 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2434 return -TARGET_EFAULT;
2435
bellard2f619692007-11-16 10:46:05 +00002436 addr = alloca(addrlen);
2437
pbrook1be9e1d2006-11-19 15:26:04 +00002438 ret = get_errno(getpeername(fd, addr, &addrlen));
2439 if (!is_error(ret)) {
2440 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002441 if (put_user_u32(addrlen, target_addrlen_addr))
2442 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002443 }
2444 return ret;
2445}
2446
ths0da46a62007-10-20 20:23:07 +00002447/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002448static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002449 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002450{
bellard2f619692007-11-16 10:46:05 +00002451 socklen_t addrlen;
2452 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002453 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002454
bellard2f619692007-11-16 10:46:05 +00002455 if (get_user_u32(addrlen, target_addrlen_addr))
2456 return -TARGET_EFAULT;
2457
Blue Swirl38724252010-09-18 05:53:14 +00002458 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002459 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002460 }
aurel328f7aeaf2009-01-30 19:47:57 +00002461
Arnaud Patard917507b2009-06-19 10:44:45 +03002462 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2463 return -TARGET_EFAULT;
2464
bellard2f619692007-11-16 10:46:05 +00002465 addr = alloca(addrlen);
2466
pbrook1be9e1d2006-11-19 15:26:04 +00002467 ret = get_errno(getsockname(fd, addr, &addrlen));
2468 if (!is_error(ret)) {
2469 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002470 if (put_user_u32(addrlen, target_addrlen_addr))
2471 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002472 }
2473 return ret;
2474}
2475
ths0da46a62007-10-20 20:23:07 +00002476/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002477static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002478 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002479{
2480 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002481 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002482
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002483 target_to_host_sock_type(&type);
2484
pbrook1be9e1d2006-11-19 15:26:04 +00002485 ret = get_errno(socketpair(domain, type, protocol, tab));
2486 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002487 if (put_user_s32(tab[0], target_tab_addr)
2488 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2489 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002490 }
2491 return ret;
2492}
2493
ths0da46a62007-10-20 20:23:07 +00002494/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002495static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2496 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002497{
2498 void *addr;
2499 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002500 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002501
Blue Swirl38724252010-09-18 05:53:14 +00002502 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002503 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002504 }
aurel328f7aeaf2009-01-30 19:47:57 +00002505
bellard579a97f2007-11-11 14:26:47 +00002506 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2507 if (!host_msg)
2508 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002509 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002510 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002511 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002512 if (ret) {
2513 unlock_user(host_msg, msg, 0);
2514 return ret;
2515 }
pbrook1be9e1d2006-11-19 15:26:04 +00002516 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2517 } else {
2518 ret = get_errno(send(fd, host_msg, len, flags));
2519 }
2520 unlock_user(host_msg, msg, 0);
2521 return ret;
2522}
2523
ths0da46a62007-10-20 20:23:07 +00002524/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002525static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2526 abi_ulong target_addr,
2527 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002528{
2529 socklen_t addrlen;
2530 void *addr;
2531 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002532 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002533
bellard579a97f2007-11-11 14:26:47 +00002534 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2535 if (!host_msg)
2536 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002537 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002538 if (get_user_u32(addrlen, target_addrlen)) {
2539 ret = -TARGET_EFAULT;
2540 goto fail;
2541 }
Blue Swirl38724252010-09-18 05:53:14 +00002542 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002543 ret = -TARGET_EINVAL;
2544 goto fail;
2545 }
pbrook1be9e1d2006-11-19 15:26:04 +00002546 addr = alloca(addrlen);
2547 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2548 } else {
2549 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002550 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002551 }
2552 if (!is_error(ret)) {
2553 if (target_addr) {
2554 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002555 if (put_user_u32(addrlen, target_addrlen)) {
2556 ret = -TARGET_EFAULT;
2557 goto fail;
2558 }
pbrook1be9e1d2006-11-19 15:26:04 +00002559 }
2560 unlock_user(host_msg, msg, len);
2561 } else {
bellard2f619692007-11-16 10:46:05 +00002562fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002563 unlock_user(host_msg, msg, 0);
2564 }
2565 return ret;
2566}
2567
j_mayer32407102007-09-26 23:01:49 +00002568#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002569/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002570static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002571{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002572 static const unsigned ac[] = { /* number of arguments per call */
2573 [SOCKOP_socket] = 3, /* domain, type, protocol */
2574 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2575 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2576 [SOCKOP_listen] = 2, /* sockfd, backlog */
2577 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2578 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2579 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2580 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2581 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2582 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2583 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2584 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2585 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2586 [SOCKOP_shutdown] = 2, /* sockfd, how */
2587 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2588 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002589 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
2590 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002591 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2592 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2593 };
2594 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002595
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002596 /* first, collect the arguments in a[] according to ac[] */
2597 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2598 unsigned i;
2599 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2600 for (i = 0; i < ac[num]; ++i) {
2601 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002602 return -TARGET_EFAULT;
2603 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002604 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002605 }
bellard2f619692007-11-16 10:46:05 +00002606
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002607 /* now when we have the args, actually handle the call */
2608 switch (num) {
2609 case SOCKOP_socket: /* domain, type, protocol */
2610 return do_socket(a[0], a[1], a[2]);
2611 case SOCKOP_bind: /* sockfd, addr, addrlen */
2612 return do_bind(a[0], a[1], a[2]);
2613 case SOCKOP_connect: /* sockfd, addr, addrlen */
2614 return do_connect(a[0], a[1], a[2]);
2615 case SOCKOP_listen: /* sockfd, backlog */
2616 return get_errno(listen(a[0], a[1]));
2617 case SOCKOP_accept: /* sockfd, addr, addrlen */
2618 return do_accept4(a[0], a[1], a[2], 0);
2619 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2620 return do_accept4(a[0], a[1], a[2], a[3]);
2621 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2622 return do_getsockname(a[0], a[1], a[2]);
2623 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2624 return do_getpeername(a[0], a[1], a[2]);
2625 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2626 return do_socketpair(a[0], a[1], a[2], a[3]);
2627 case SOCKOP_send: /* sockfd, msg, len, flags */
2628 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2629 case SOCKOP_recv: /* sockfd, msg, len, flags */
2630 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2631 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2632 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2633 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2634 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2635 case SOCKOP_shutdown: /* sockfd, how */
2636 return get_errno(shutdown(a[0], a[1]));
2637 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2638 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2639 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2640 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01002641 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
2642 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
2643 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
2644 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002645 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2646 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2647 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2648 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002649 default:
2650 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002651 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002652 }
bellard31e31b82003-02-18 22:55:36 +00002653}
j_mayer32407102007-09-26 23:01:49 +00002654#endif
bellard31e31b82003-02-18 22:55:36 +00002655
bellard8853f862004-02-22 14:57:26 +00002656#define N_SHM_REGIONS 32
2657
2658static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00002659 abi_ulong start;
2660 abi_ulong size;
2661 bool in_use;
bellard8853f862004-02-22 14:57:26 +00002662} shm_regions[N_SHM_REGIONS];
2663
ths3eb6b042007-06-03 14:26:27 +00002664struct target_semid_ds
2665{
2666 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002667 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002668#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002669 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002670#endif
blueswir1992f48a2007-10-14 16:27:31 +00002671 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002672#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002673 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002674#endif
blueswir1992f48a2007-10-14 16:27:31 +00002675 abi_ulong sem_nsems;
2676 abi_ulong __unused3;
2677 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002678};
2679
bellard579a97f2007-11-11 14:26:47 +00002680static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2681 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002682{
2683 struct target_ipc_perm *target_ip;
2684 struct target_semid_ds *target_sd;
2685
bellard579a97f2007-11-11 14:26:47 +00002686 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2687 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002688 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002689 host_ip->__key = tswap32(target_ip->__key);
2690 host_ip->uid = tswap32(target_ip->uid);
2691 host_ip->gid = tswap32(target_ip->gid);
2692 host_ip->cuid = tswap32(target_ip->cuid);
2693 host_ip->cgid = tswap32(target_ip->cgid);
2694#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2695 host_ip->mode = tswap32(target_ip->mode);
2696#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002697 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002698#endif
2699#if defined(TARGET_PPC)
2700 host_ip->__seq = tswap32(target_ip->__seq);
2701#else
2702 host_ip->__seq = tswap16(target_ip->__seq);
2703#endif
ths3eb6b042007-06-03 14:26:27 +00002704 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002705 return 0;
ths3eb6b042007-06-03 14:26:27 +00002706}
2707
bellard579a97f2007-11-11 14:26:47 +00002708static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2709 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002710{
2711 struct target_ipc_perm *target_ip;
2712 struct target_semid_ds *target_sd;
2713
bellard579a97f2007-11-11 14:26:47 +00002714 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2715 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002716 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002717 target_ip->__key = tswap32(host_ip->__key);
2718 target_ip->uid = tswap32(host_ip->uid);
2719 target_ip->gid = tswap32(host_ip->gid);
2720 target_ip->cuid = tswap32(host_ip->cuid);
2721 target_ip->cgid = tswap32(host_ip->cgid);
2722#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2723 target_ip->mode = tswap32(host_ip->mode);
2724#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002725 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002726#endif
2727#if defined(TARGET_PPC)
2728 target_ip->__seq = tswap32(host_ip->__seq);
2729#else
2730 target_ip->__seq = tswap16(host_ip->__seq);
2731#endif
ths3eb6b042007-06-03 14:26:27 +00002732 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002733 return 0;
ths3eb6b042007-06-03 14:26:27 +00002734}
2735
bellard579a97f2007-11-11 14:26:47 +00002736static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2737 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002738{
2739 struct target_semid_ds *target_sd;
2740
bellard579a97f2007-11-11 14:26:47 +00002741 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2742 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002743 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2744 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002745 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2746 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2747 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002748 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002749 return 0;
ths3eb6b042007-06-03 14:26:27 +00002750}
2751
bellard579a97f2007-11-11 14:26:47 +00002752static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2753 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002754{
2755 struct target_semid_ds *target_sd;
2756
bellard579a97f2007-11-11 14:26:47 +00002757 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2758 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002759 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002760 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002761 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2762 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2763 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002764 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002765 return 0;
ths3eb6b042007-06-03 14:26:27 +00002766}
2767
aurel32e5289082009-04-18 16:16:12 +00002768struct target_seminfo {
2769 int semmap;
2770 int semmni;
2771 int semmns;
2772 int semmnu;
2773 int semmsl;
2774 int semopm;
2775 int semume;
2776 int semusz;
2777 int semvmx;
2778 int semaem;
2779};
2780
2781static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2782 struct seminfo *host_seminfo)
2783{
2784 struct target_seminfo *target_seminfo;
2785 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2786 return -TARGET_EFAULT;
2787 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2788 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2789 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2790 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2791 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2792 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2793 __put_user(host_seminfo->semume, &target_seminfo->semume);
2794 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2795 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2796 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2797 unlock_user_struct(target_seminfo, target_addr, 1);
2798 return 0;
2799}
2800
thsfa294812007-02-02 22:05:00 +00002801union semun {
2802 int val;
ths3eb6b042007-06-03 14:26:27 +00002803 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002804 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002805 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002806};
2807
ths3eb6b042007-06-03 14:26:27 +00002808union target_semun {
2809 int val;
aurel32e5289082009-04-18 16:16:12 +00002810 abi_ulong buf;
2811 abi_ulong array;
2812 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002813};
2814
aurel32e5289082009-04-18 16:16:12 +00002815static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2816 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002817{
aurel32e5289082009-04-18 16:16:12 +00002818 int nsems;
2819 unsigned short *array;
2820 union semun semun;
2821 struct semid_ds semid_ds;
2822 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002823
aurel32e5289082009-04-18 16:16:12 +00002824 semun.buf = &semid_ds;
2825
2826 ret = semctl(semid, 0, IPC_STAT, semun);
2827 if (ret == -1)
2828 return get_errno(ret);
2829
2830 nsems = semid_ds.sem_nsems;
2831
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302832 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00002833 if (!*host_array) {
2834 return -TARGET_ENOMEM;
2835 }
aurel32e5289082009-04-18 16:16:12 +00002836 array = lock_user(VERIFY_READ, target_addr,
2837 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002838 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302839 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002840 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002841 }
aurel32e5289082009-04-18 16:16:12 +00002842
2843 for(i=0; i<nsems; i++) {
2844 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002845 }
aurel32e5289082009-04-18 16:16:12 +00002846 unlock_user(array, target_addr, 0);
2847
bellard579a97f2007-11-11 14:26:47 +00002848 return 0;
ths3eb6b042007-06-03 14:26:27 +00002849}
2850
aurel32e5289082009-04-18 16:16:12 +00002851static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2852 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002853{
aurel32e5289082009-04-18 16:16:12 +00002854 int nsems;
2855 unsigned short *array;
2856 union semun semun;
2857 struct semid_ds semid_ds;
2858 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002859
aurel32e5289082009-04-18 16:16:12 +00002860 semun.buf = &semid_ds;
2861
2862 ret = semctl(semid, 0, IPC_STAT, semun);
2863 if (ret == -1)
2864 return get_errno(ret);
2865
2866 nsems = semid_ds.sem_nsems;
2867
2868 array = lock_user(VERIFY_WRITE, target_addr,
2869 nsems*sizeof(unsigned short), 0);
2870 if (!array)
2871 return -TARGET_EFAULT;
2872
2873 for(i=0; i<nsems; i++) {
2874 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002875 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302876 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002877 unlock_user(array, target_addr, 1);
2878
bellard579a97f2007-11-11 14:26:47 +00002879 return 0;
ths3eb6b042007-06-03 14:26:27 +00002880}
2881
aurel32e5289082009-04-18 16:16:12 +00002882static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01002883 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00002884{
Stefan Weild1c002b2015-02-08 15:40:58 +01002885 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00002886 union semun arg;
2887 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302888 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002889 struct seminfo seminfo;
2890 abi_long ret = -TARGET_EINVAL;
2891 abi_long err;
2892 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002893
2894 switch( cmd ) {
2895 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002896 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002897 /* In 64 bit cross-endian situations, we will erroneously pick up
2898 * the wrong half of the union for the "val" element. To rectify
2899 * this, the entire 8-byte structure is byteswapped, followed by
2900 * a swap of the 4 byte val field. In other cases, the data is
2901 * already in proper host byte order. */
2902 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2903 target_su.buf = tswapal(target_su.buf);
2904 arg.val = tswap32(target_su.val);
2905 } else {
2906 arg.val = target_su.val;
2907 }
aurel32e5289082009-04-18 16:16:12 +00002908 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002909 break;
2910 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002911 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002912 err = target_to_host_semarray(semid, &array, target_su.array);
2913 if (err)
2914 return err;
2915 arg.array = array;
2916 ret = get_errno(semctl(semid, semnum, cmd, arg));
2917 err = host_to_target_semarray(semid, target_su.array, &array);
2918 if (err)
2919 return err;
ths3eb6b042007-06-03 14:26:27 +00002920 break;
2921 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002922 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002923 case SEM_STAT:
2924 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2925 if (err)
2926 return err;
2927 arg.buf = &dsarg;
2928 ret = get_errno(semctl(semid, semnum, cmd, arg));
2929 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2930 if (err)
2931 return err;
ths3eb6b042007-06-03 14:26:27 +00002932 break;
aurel32e5289082009-04-18 16:16:12 +00002933 case IPC_INFO:
2934 case SEM_INFO:
2935 arg.__buf = &seminfo;
2936 ret = get_errno(semctl(semid, semnum, cmd, arg));
2937 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2938 if (err)
2939 return err;
2940 break;
2941 case IPC_RMID:
2942 case GETPID:
2943 case GETNCNT:
2944 case GETZCNT:
2945 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2946 break;
ths3eb6b042007-06-03 14:26:27 +00002947 }
2948
2949 return ret;
2950}
2951
aurel32e5289082009-04-18 16:16:12 +00002952struct target_sembuf {
2953 unsigned short sem_num;
2954 short sem_op;
2955 short sem_flg;
2956};
2957
2958static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2959 abi_ulong target_addr,
2960 unsigned nsops)
2961{
2962 struct target_sembuf *target_sembuf;
2963 int i;
2964
2965 target_sembuf = lock_user(VERIFY_READ, target_addr,
2966 nsops*sizeof(struct target_sembuf), 1);
2967 if (!target_sembuf)
2968 return -TARGET_EFAULT;
2969
2970 for(i=0; i<nsops; i++) {
2971 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2972 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2973 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2974 }
2975
2976 unlock_user(target_sembuf, target_addr, 0);
2977
2978 return 0;
2979}
2980
2981static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2982{
2983 struct sembuf sops[nsops];
2984
2985 if (target_to_host_sembuf(sops, ptr, nsops))
2986 return -TARGET_EFAULT;
2987
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002988 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002989}
2990
ths1bc012f2007-06-03 14:27:49 +00002991struct target_msqid_ds
2992{
aurel321c54ff92008-10-13 21:08:44 +00002993 struct target_ipc_perm msg_perm;
2994 abi_ulong msg_stime;
2995#if TARGET_ABI_BITS == 32
2996 abi_ulong __unused1;
2997#endif
2998 abi_ulong msg_rtime;
2999#if TARGET_ABI_BITS == 32
3000 abi_ulong __unused2;
3001#endif
3002 abi_ulong msg_ctime;
3003#if TARGET_ABI_BITS == 32
3004 abi_ulong __unused3;
3005#endif
3006 abi_ulong __msg_cbytes;
3007 abi_ulong msg_qnum;
3008 abi_ulong msg_qbytes;
3009 abi_ulong msg_lspid;
3010 abi_ulong msg_lrpid;
3011 abi_ulong __unused4;
3012 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003013};
3014
bellard579a97f2007-11-11 14:26:47 +00003015static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3016 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003017{
3018 struct target_msqid_ds *target_md;
3019
bellard579a97f2007-11-11 14:26:47 +00003020 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3021 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003022 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3023 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003024 host_md->msg_stime = tswapal(target_md->msg_stime);
3025 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3026 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3027 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3028 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3029 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3030 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3031 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003032 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003033 return 0;
ths1bc012f2007-06-03 14:27:49 +00003034}
3035
bellard579a97f2007-11-11 14:26:47 +00003036static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3037 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003038{
3039 struct target_msqid_ds *target_md;
3040
bellard579a97f2007-11-11 14:26:47 +00003041 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3042 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003043 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3044 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003045 target_md->msg_stime = tswapal(host_md->msg_stime);
3046 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3047 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3048 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3049 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3050 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3051 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3052 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003053 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003054 return 0;
ths1bc012f2007-06-03 14:27:49 +00003055}
3056
aurel321c54ff92008-10-13 21:08:44 +00003057struct target_msginfo {
3058 int msgpool;
3059 int msgmap;
3060 int msgmax;
3061 int msgmnb;
3062 int msgmni;
3063 int msgssz;
3064 int msgtql;
3065 unsigned short int msgseg;
3066};
3067
3068static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3069 struct msginfo *host_msginfo)
3070{
3071 struct target_msginfo *target_msginfo;
3072 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3073 return -TARGET_EFAULT;
3074 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3075 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3076 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3077 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3078 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3079 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3080 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3081 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3082 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003083 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003084}
3085
3086static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003087{
3088 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003089 struct msginfo msginfo;
3090 abi_long ret = -TARGET_EINVAL;
3091
3092 cmd &= 0xff;
3093
3094 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003095 case IPC_STAT:
3096 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003097 case MSG_STAT:
3098 if (target_to_host_msqid_ds(&dsarg,ptr))
3099 return -TARGET_EFAULT;
3100 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3101 if (host_to_target_msqid_ds(ptr,&dsarg))
3102 return -TARGET_EFAULT;
3103 break;
3104 case IPC_RMID:
3105 ret = get_errno(msgctl(msgid, cmd, NULL));
3106 break;
3107 case IPC_INFO:
3108 case MSG_INFO:
3109 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3110 if (host_to_target_msginfo(ptr, &msginfo))
3111 return -TARGET_EFAULT;
3112 break;
ths1bc012f2007-06-03 14:27:49 +00003113 }
aurel321c54ff92008-10-13 21:08:44 +00003114
ths1bc012f2007-06-03 14:27:49 +00003115 return ret;
3116}
3117
3118struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003119 abi_long mtype;
3120 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003121};
3122
blueswir1992f48a2007-10-14 16:27:31 +00003123static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003124 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003125{
3126 struct target_msgbuf *target_mb;
3127 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003128 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003129
Tom Mustaedcc5f92014-08-12 13:53:37 -05003130 if (msgsz < 0) {
3131 return -TARGET_EINVAL;
3132 }
3133
bellard579a97f2007-11-11 14:26:47 +00003134 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3135 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303136 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003137 if (!host_mb) {
3138 unlock_user_struct(target_mb, msgp, 0);
3139 return -TARGET_ENOMEM;
3140 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003141 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003142 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00003143 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303144 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003145 unlock_user_struct(target_mb, msgp, 0);
3146
3147 return ret;
3148}
3149
blueswir1992f48a2007-10-14 16:27:31 +00003150static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00003151 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003152 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003153{
3154 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003155 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003156 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003157 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003158
bellard579a97f2007-11-11 14:26:47 +00003159 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3160 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003161
Jim Meyering0d07fe42012-08-22 13:55:53 +02003162 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003163 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003164
bellard579a97f2007-11-11 14:26:47 +00003165 if (ret > 0) {
3166 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3167 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3168 if (!target_mtext) {
3169 ret = -TARGET_EFAULT;
3170 goto end;
3171 }
aurel321c54ff92008-10-13 21:08:44 +00003172 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003173 unlock_user(target_mtext, target_mtext_addr, ret);
3174 }
aurel321c54ff92008-10-13 21:08:44 +00003175
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003176 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003177
bellard579a97f2007-11-11 14:26:47 +00003178end:
3179 if (target_mb)
3180 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003181 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003182 return ret;
3183}
3184
Riku Voipio88a8c982009-04-03 10:42:00 +03003185static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3186 abi_ulong target_addr)
3187{
3188 struct target_shmid_ds *target_sd;
3189
3190 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3191 return -TARGET_EFAULT;
3192 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3193 return -TARGET_EFAULT;
3194 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3195 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3196 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3197 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3198 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3199 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3200 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3201 unlock_user_struct(target_sd, target_addr, 0);
3202 return 0;
3203}
3204
3205static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3206 struct shmid_ds *host_sd)
3207{
3208 struct target_shmid_ds *target_sd;
3209
3210 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3211 return -TARGET_EFAULT;
3212 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3213 return -TARGET_EFAULT;
3214 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3215 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3216 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3217 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3218 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3219 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3220 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3221 unlock_user_struct(target_sd, target_addr, 1);
3222 return 0;
3223}
3224
3225struct target_shminfo {
3226 abi_ulong shmmax;
3227 abi_ulong shmmin;
3228 abi_ulong shmmni;
3229 abi_ulong shmseg;
3230 abi_ulong shmall;
3231};
3232
3233static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3234 struct shminfo *host_shminfo)
3235{
3236 struct target_shminfo *target_shminfo;
3237 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3238 return -TARGET_EFAULT;
3239 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3240 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3241 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3242 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3243 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3244 unlock_user_struct(target_shminfo, target_addr, 1);
3245 return 0;
3246}
3247
3248struct target_shm_info {
3249 int used_ids;
3250 abi_ulong shm_tot;
3251 abi_ulong shm_rss;
3252 abi_ulong shm_swp;
3253 abi_ulong swap_attempts;
3254 abi_ulong swap_successes;
3255};
3256
3257static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3258 struct shm_info *host_shm_info)
3259{
3260 struct target_shm_info *target_shm_info;
3261 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3262 return -TARGET_EFAULT;
3263 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3264 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3265 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3266 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3267 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3268 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3269 unlock_user_struct(target_shm_info, target_addr, 1);
3270 return 0;
3271}
3272
3273static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3274{
3275 struct shmid_ds dsarg;
3276 struct shminfo shminfo;
3277 struct shm_info shm_info;
3278 abi_long ret = -TARGET_EINVAL;
3279
3280 cmd &= 0xff;
3281
3282 switch(cmd) {
3283 case IPC_STAT:
3284 case IPC_SET:
3285 case SHM_STAT:
3286 if (target_to_host_shmid_ds(&dsarg, buf))
3287 return -TARGET_EFAULT;
3288 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3289 if (host_to_target_shmid_ds(buf, &dsarg))
3290 return -TARGET_EFAULT;
3291 break;
3292 case IPC_INFO:
3293 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3294 if (host_to_target_shminfo(buf, &shminfo))
3295 return -TARGET_EFAULT;
3296 break;
3297 case SHM_INFO:
3298 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3299 if (host_to_target_shm_info(buf, &shm_info))
3300 return -TARGET_EFAULT;
3301 break;
3302 case IPC_RMID:
3303 case SHM_LOCK:
3304 case SHM_UNLOCK:
3305 ret = get_errno(shmctl(shmid, cmd, NULL));
3306 break;
3307 }
3308
3309 return ret;
3310}
3311
3312static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3313{
3314 abi_long raddr;
3315 void *host_raddr;
3316 struct shmid_ds shm_info;
3317 int i,ret;
3318
3319 /* find out the length of the shared memory segment */
3320 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3321 if (is_error(ret)) {
3322 /* can't get length, bail out */
3323 return ret;
3324 }
3325
3326 mmap_lock();
3327
3328 if (shmaddr)
3329 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3330 else {
3331 abi_ulong mmap_start;
3332
3333 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3334
3335 if (mmap_start == -1) {
3336 errno = ENOMEM;
3337 host_raddr = (void *)-1;
3338 } else
3339 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3340 }
3341
3342 if (host_raddr == (void *)-1) {
3343 mmap_unlock();
3344 return get_errno((long)host_raddr);
3345 }
3346 raddr=h2g((unsigned long)host_raddr);
3347
3348 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3349 PAGE_VALID | PAGE_READ |
3350 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3351
3352 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003353 if (!shm_regions[i].in_use) {
3354 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03003355 shm_regions[i].start = raddr;
3356 shm_regions[i].size = shm_info.shm_segsz;
3357 break;
3358 }
3359 }
3360
3361 mmap_unlock();
3362 return raddr;
3363
3364}
3365
3366static inline abi_long do_shmdt(abi_ulong shmaddr)
3367{
3368 int i;
3369
3370 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003371 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
3372 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003373 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003374 break;
3375 }
3376 }
3377
3378 return get_errno(shmdt(g2h(shmaddr)));
3379}
3380
aurel321c54ff92008-10-13 21:08:44 +00003381#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003382/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003383/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003384static abi_long do_ipc(unsigned int call, abi_long first,
3385 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003386 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003387{
3388 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003389 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003390
3391 version = call >> 16;
3392 call &= 0xffff;
3393
3394 switch (call) {
thsfa294812007-02-02 22:05:00 +00003395 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003396 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003397 break;
3398
3399 case IPCOP_semget:
3400 ret = get_errno(semget(first, second, third));
3401 break;
3402
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003403 case IPCOP_semctl: {
3404 /* The semun argument to semctl is passed by value, so dereference the
3405 * ptr argument. */
3406 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003407 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01003408 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00003409 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003410 }
thsd96372e2007-02-02 22:05:44 +00003411
aurel321c54ff92008-10-13 21:08:44 +00003412 case IPCOP_msgget:
3413 ret = get_errno(msgget(first, second));
3414 break;
thsd96372e2007-02-02 22:05:44 +00003415
aurel321c54ff92008-10-13 21:08:44 +00003416 case IPCOP_msgsnd:
3417 ret = do_msgsnd(first, ptr, second, third);
3418 break;
thsd96372e2007-02-02 22:05:44 +00003419
aurel321c54ff92008-10-13 21:08:44 +00003420 case IPCOP_msgctl:
3421 ret = do_msgctl(first, second, ptr);
3422 break;
thsd96372e2007-02-02 22:05:44 +00003423
aurel321c54ff92008-10-13 21:08:44 +00003424 case IPCOP_msgrcv:
3425 switch (version) {
3426 case 0:
3427 {
3428 struct target_ipc_kludge {
3429 abi_long msgp;
3430 abi_long msgtyp;
3431 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003432
aurel321c54ff92008-10-13 21:08:44 +00003433 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3434 ret = -TARGET_EFAULT;
3435 break;
ths1bc012f2007-06-03 14:27:49 +00003436 }
aurel321c54ff92008-10-13 21:08:44 +00003437
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003438 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003439
3440 unlock_user_struct(tmp, ptr, 0);
3441 break;
3442 }
3443 default:
3444 ret = do_msgrcv(first, ptr, second, fifth, third);
3445 }
3446 break;
thsd96372e2007-02-02 22:05:44 +00003447
bellard8853f862004-02-22 14:57:26 +00003448 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003449 switch (version) {
3450 default:
bellard5a4a8982007-11-11 17:39:18 +00003451 {
3452 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003453 raddr = do_shmat(first, ptr, second);
3454 if (is_error(raddr))
3455 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003456 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003457 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003458 break;
3459 }
3460 case 1:
3461 ret = -TARGET_EINVAL;
3462 break;
bellard5a4a8982007-11-11 17:39:18 +00003463 }
bellard8853f862004-02-22 14:57:26 +00003464 break;
3465 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003466 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003467 break;
3468
3469 case IPCOP_shmget:
3470 /* IPC_* flag values are the same on all linux platforms */
3471 ret = get_errno(shmget(first, second, third));
3472 break;
3473
3474 /* IPC_* and SHM_* command values are the same on all linux platforms */
3475 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003476 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003477 break;
3478 default:
j_mayer32407102007-09-26 23:01:49 +00003479 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003480 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003481 break;
3482 }
3483 return ret;
3484}
j_mayer32407102007-09-26 23:01:49 +00003485#endif
bellard8853f862004-02-22 14:57:26 +00003486
bellard31e31b82003-02-18 22:55:36 +00003487/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003488
Blue Swirl001faf32009-05-13 17:53:17 +00003489#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003490#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3491enum {
3492#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02003493STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00003494};
3495#undef STRUCT
3496#undef STRUCT_SPECIAL
3497
Blue Swirl001faf32009-05-13 17:53:17 +00003498#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003499#define STRUCT_SPECIAL(name)
3500#include "syscall_types.h"
3501#undef STRUCT
3502#undef STRUCT_SPECIAL
3503
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003504typedef struct IOCTLEntry IOCTLEntry;
3505
3506typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003507 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003508
3509struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08003510 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00003511 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003512 const char *name;
3513 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003514 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003515 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003516};
bellard31e31b82003-02-18 22:55:36 +00003517
3518#define IOC_R 0x0001
3519#define IOC_W 0x0002
3520#define IOC_RW (IOC_R | IOC_W)
3521
3522#define MAX_STRUCT_SIZE 4096
3523
Peter Maydelldace20d2011-01-10 13:11:24 +00003524#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003525/* So fiemap access checks don't overflow on 32 bit systems.
3526 * This is very slightly smaller than the limit imposed by
3527 * the underlying kernel.
3528 */
3529#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3530 / sizeof(struct fiemap_extent))
3531
3532static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003533 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00003534{
3535 /* The parameter for this ioctl is a struct fiemap followed
3536 * by an array of struct fiemap_extent whose size is set
3537 * in fiemap->fm_extent_count. The array is filled in by the
3538 * ioctl.
3539 */
3540 int target_size_in, target_size_out;
3541 struct fiemap *fm;
3542 const argtype *arg_type = ie->arg_type;
3543 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3544 void *argptr, *p;
3545 abi_long ret;
3546 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3547 uint32_t outbufsz;
3548 int free_fm = 0;
3549
3550 assert(arg_type[0] == TYPE_PTR);
3551 assert(ie->access == IOC_RW);
3552 arg_type++;
3553 target_size_in = thunk_type_size(arg_type, 0);
3554 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3555 if (!argptr) {
3556 return -TARGET_EFAULT;
3557 }
3558 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3559 unlock_user(argptr, arg, 0);
3560 fm = (struct fiemap *)buf_temp;
3561 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3562 return -TARGET_EINVAL;
3563 }
3564
3565 outbufsz = sizeof (*fm) +
3566 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3567
3568 if (outbufsz > MAX_STRUCT_SIZE) {
3569 /* We can't fit all the extents into the fixed size buffer.
3570 * Allocate one that is large enough and use it instead.
3571 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303572 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00003573 if (!fm) {
3574 return -TARGET_ENOMEM;
3575 }
3576 memcpy(fm, buf_temp, sizeof(struct fiemap));
3577 free_fm = 1;
3578 }
3579 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3580 if (!is_error(ret)) {
3581 target_size_out = target_size_in;
3582 /* An extent_count of 0 means we were only counting the extents
3583 * so there are no structs to copy
3584 */
3585 if (fm->fm_extent_count != 0) {
3586 target_size_out += fm->fm_mapped_extents * extent_size;
3587 }
3588 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3589 if (!argptr) {
3590 ret = -TARGET_EFAULT;
3591 } else {
3592 /* Convert the struct fiemap */
3593 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3594 if (fm->fm_extent_count != 0) {
3595 p = argptr + target_size_in;
3596 /* ...and then all the struct fiemap_extents */
3597 for (i = 0; i < fm->fm_mapped_extents; i++) {
3598 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3599 THUNK_TARGET);
3600 p += extent_size;
3601 }
3602 }
3603 unlock_user(argptr, arg, target_size_out);
3604 }
3605 }
3606 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303607 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00003608 }
3609 return ret;
3610}
Peter Maydelldace20d2011-01-10 13:11:24 +00003611#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003612
Laurent Vivier059c2f22011-03-30 00:12:12 +02003613static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003614 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02003615{
3616 const argtype *arg_type = ie->arg_type;
3617 int target_size;
3618 void *argptr;
3619 int ret;
3620 struct ifconf *host_ifconf;
3621 uint32_t outbufsz;
3622 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3623 int target_ifreq_size;
3624 int nb_ifreq;
3625 int free_buf = 0;
3626 int i;
3627 int target_ifc_len;
3628 abi_long target_ifc_buf;
3629 int host_ifc_len;
3630 char *host_ifc_buf;
3631
3632 assert(arg_type[0] == TYPE_PTR);
3633 assert(ie->access == IOC_RW);
3634
3635 arg_type++;
3636 target_size = thunk_type_size(arg_type, 0);
3637
3638 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3639 if (!argptr)
3640 return -TARGET_EFAULT;
3641 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3642 unlock_user(argptr, arg, 0);
3643
3644 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3645 target_ifc_len = host_ifconf->ifc_len;
3646 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3647
3648 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3649 nb_ifreq = target_ifc_len / target_ifreq_size;
3650 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3651
3652 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3653 if (outbufsz > MAX_STRUCT_SIZE) {
3654 /* We can't fit all the extents into the fixed size buffer.
3655 * Allocate one that is large enough and use it instead.
3656 */
3657 host_ifconf = malloc(outbufsz);
3658 if (!host_ifconf) {
3659 return -TARGET_ENOMEM;
3660 }
3661 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3662 free_buf = 1;
3663 }
3664 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3665
3666 host_ifconf->ifc_len = host_ifc_len;
3667 host_ifconf->ifc_buf = host_ifc_buf;
3668
3669 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3670 if (!is_error(ret)) {
3671 /* convert host ifc_len to target ifc_len */
3672
3673 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3674 target_ifc_len = nb_ifreq * target_ifreq_size;
3675 host_ifconf->ifc_len = target_ifc_len;
3676
3677 /* restore target ifc_buf */
3678
3679 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3680
3681 /* copy struct ifconf to target user */
3682
3683 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3684 if (!argptr)
3685 return -TARGET_EFAULT;
3686 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3687 unlock_user(argptr, arg, target_size);
3688
3689 /* copy ifreq[] to target user */
3690
3691 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3692 for (i = 0; i < nb_ifreq ; i++) {
3693 thunk_convert(argptr + i * target_ifreq_size,
3694 host_ifc_buf + i * sizeof(struct ifreq),
3695 ifreq_arg_type, THUNK_TARGET);
3696 }
3697 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3698 }
3699
3700 if (free_buf) {
3701 free(host_ifconf);
3702 }
3703
3704 return ret;
3705}
3706
Alexander Graf56e904e2012-01-31 18:42:06 +01003707static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003708 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01003709{
3710 void *argptr;
3711 struct dm_ioctl *host_dm;
3712 abi_long guest_data;
3713 uint32_t guest_data_size;
3714 int target_size;
3715 const argtype *arg_type = ie->arg_type;
3716 abi_long ret;
3717 void *big_buf = NULL;
3718 char *host_data;
3719
3720 arg_type++;
3721 target_size = thunk_type_size(arg_type, 0);
3722 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3723 if (!argptr) {
3724 ret = -TARGET_EFAULT;
3725 goto out;
3726 }
3727 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3728 unlock_user(argptr, arg, 0);
3729
3730 /* buf_temp is too small, so fetch things into a bigger buffer */
3731 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3732 memcpy(big_buf, buf_temp, target_size);
3733 buf_temp = big_buf;
3734 host_dm = big_buf;
3735
3736 guest_data = arg + host_dm->data_start;
3737 if ((guest_data - arg) < 0) {
3738 ret = -EINVAL;
3739 goto out;
3740 }
3741 guest_data_size = host_dm->data_size - host_dm->data_start;
3742 host_data = (char*)host_dm + host_dm->data_start;
3743
3744 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3745 switch (ie->host_cmd) {
3746 case DM_REMOVE_ALL:
3747 case DM_LIST_DEVICES:
3748 case DM_DEV_CREATE:
3749 case DM_DEV_REMOVE:
3750 case DM_DEV_SUSPEND:
3751 case DM_DEV_STATUS:
3752 case DM_DEV_WAIT:
3753 case DM_TABLE_STATUS:
3754 case DM_TABLE_CLEAR:
3755 case DM_TABLE_DEPS:
3756 case DM_LIST_VERSIONS:
3757 /* no input data */
3758 break;
3759 case DM_DEV_RENAME:
3760 case DM_DEV_SET_GEOMETRY:
3761 /* data contains only strings */
3762 memcpy(host_data, argptr, guest_data_size);
3763 break;
3764 case DM_TARGET_MSG:
3765 memcpy(host_data, argptr, guest_data_size);
3766 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3767 break;
3768 case DM_TABLE_LOAD:
3769 {
3770 void *gspec = argptr;
3771 void *cur_data = host_data;
3772 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3773 int spec_size = thunk_type_size(arg_type, 0);
3774 int i;
3775
3776 for (i = 0; i < host_dm->target_count; i++) {
3777 struct dm_target_spec *spec = cur_data;
3778 uint32_t next;
3779 int slen;
3780
3781 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3782 slen = strlen((char*)gspec + spec_size) + 1;
3783 next = spec->next;
3784 spec->next = sizeof(*spec) + slen;
3785 strcpy((char*)&spec[1], gspec + spec_size);
3786 gspec += next;
3787 cur_data += spec->next;
3788 }
3789 break;
3790 }
3791 default:
3792 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08003793 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003794 goto out;
3795 }
3796 unlock_user(argptr, guest_data, 0);
3797
3798 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3799 if (!is_error(ret)) {
3800 guest_data = arg + host_dm->data_start;
3801 guest_data_size = host_dm->data_size - host_dm->data_start;
3802 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3803 switch (ie->host_cmd) {
3804 case DM_REMOVE_ALL:
3805 case DM_DEV_CREATE:
3806 case DM_DEV_REMOVE:
3807 case DM_DEV_RENAME:
3808 case DM_DEV_SUSPEND:
3809 case DM_DEV_STATUS:
3810 case DM_TABLE_LOAD:
3811 case DM_TABLE_CLEAR:
3812 case DM_TARGET_MSG:
3813 case DM_DEV_SET_GEOMETRY:
3814 /* no return data */
3815 break;
3816 case DM_LIST_DEVICES:
3817 {
3818 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3819 uint32_t remaining_data = guest_data_size;
3820 void *cur_data = argptr;
3821 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3822 int nl_size = 12; /* can't use thunk_size due to alignment */
3823
3824 while (1) {
3825 uint32_t next = nl->next;
3826 if (next) {
3827 nl->next = nl_size + (strlen(nl->name) + 1);
3828 }
3829 if (remaining_data < nl->next) {
3830 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3831 break;
3832 }
3833 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3834 strcpy(cur_data + nl_size, nl->name);
3835 cur_data += nl->next;
3836 remaining_data -= nl->next;
3837 if (!next) {
3838 break;
3839 }
3840 nl = (void*)nl + next;
3841 }
3842 break;
3843 }
3844 case DM_DEV_WAIT:
3845 case DM_TABLE_STATUS:
3846 {
3847 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3848 void *cur_data = argptr;
3849 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3850 int spec_size = thunk_type_size(arg_type, 0);
3851 int i;
3852
3853 for (i = 0; i < host_dm->target_count; i++) {
3854 uint32_t next = spec->next;
3855 int slen = strlen((char*)&spec[1]) + 1;
3856 spec->next = (cur_data - argptr) + spec_size + slen;
3857 if (guest_data_size < spec->next) {
3858 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3859 break;
3860 }
3861 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3862 strcpy(cur_data + spec_size, (char*)&spec[1]);
3863 cur_data = argptr + spec->next;
3864 spec = (void*)host_dm + host_dm->data_start + next;
3865 }
3866 break;
3867 }
3868 case DM_TABLE_DEPS:
3869 {
3870 void *hdata = (void*)host_dm + host_dm->data_start;
3871 int count = *(uint32_t*)hdata;
3872 uint64_t *hdev = hdata + 8;
3873 uint64_t *gdev = argptr + 8;
3874 int i;
3875
3876 *(uint32_t*)argptr = tswap32(count);
3877 for (i = 0; i < count; i++) {
3878 *gdev = tswap64(*hdev);
3879 gdev++;
3880 hdev++;
3881 }
3882 break;
3883 }
3884 case DM_LIST_VERSIONS:
3885 {
3886 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3887 uint32_t remaining_data = guest_data_size;
3888 void *cur_data = argptr;
3889 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3890 int vers_size = thunk_type_size(arg_type, 0);
3891
3892 while (1) {
3893 uint32_t next = vers->next;
3894 if (next) {
3895 vers->next = vers_size + (strlen(vers->name) + 1);
3896 }
3897 if (remaining_data < vers->next) {
3898 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3899 break;
3900 }
3901 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3902 strcpy(cur_data + vers_size, vers->name);
3903 cur_data += vers->next;
3904 remaining_data -= vers->next;
3905 if (!next) {
3906 break;
3907 }
3908 vers = (void*)vers + next;
3909 }
3910 break;
3911 }
3912 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08003913 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003914 ret = -TARGET_EINVAL;
3915 goto out;
3916 }
3917 unlock_user(argptr, guest_data, guest_data_size);
3918
3919 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3920 if (!argptr) {
3921 ret = -TARGET_EFAULT;
3922 goto out;
3923 }
3924 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3925 unlock_user(argptr, arg, target_size);
3926 }
3927out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003928 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003929 return ret;
3930}
3931
Alexander Grafa59b5e32014-08-22 13:15:50 +02003932static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003933 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02003934{
3935 void *argptr;
3936 int target_size;
3937 const argtype *arg_type = ie->arg_type;
3938 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3939 abi_long ret;
3940
3941 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3942 struct blkpg_partition host_part;
3943
3944 /* Read and convert blkpg */
3945 arg_type++;
3946 target_size = thunk_type_size(arg_type, 0);
3947 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3948 if (!argptr) {
3949 ret = -TARGET_EFAULT;
3950 goto out;
3951 }
3952 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3953 unlock_user(argptr, arg, 0);
3954
3955 switch (host_blkpg->op) {
3956 case BLKPG_ADD_PARTITION:
3957 case BLKPG_DEL_PARTITION:
3958 /* payload is struct blkpg_partition */
3959 break;
3960 default:
3961 /* Unknown opcode */
3962 ret = -TARGET_EINVAL;
3963 goto out;
3964 }
3965
3966 /* Read and convert blkpg->data */
3967 arg = (abi_long)(uintptr_t)host_blkpg->data;
3968 target_size = thunk_type_size(part_arg_type, 0);
3969 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3970 if (!argptr) {
3971 ret = -TARGET_EFAULT;
3972 goto out;
3973 }
3974 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3975 unlock_user(argptr, arg, 0);
3976
3977 /* Swizzle the data pointer to our local copy and call! */
3978 host_blkpg->data = &host_part;
3979 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3980
3981out:
3982 return ret;
3983}
3984
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003985static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003986 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003987{
3988 const argtype *arg_type = ie->arg_type;
3989 const StructEntry *se;
3990 const argtype *field_types;
3991 const int *dst_offsets, *src_offsets;
3992 int target_size;
3993 void *argptr;
3994 abi_ulong *target_rt_dev_ptr;
3995 unsigned long *host_rt_dev_ptr;
3996 abi_long ret;
3997 int i;
3998
3999 assert(ie->access == IOC_W);
4000 assert(*arg_type == TYPE_PTR);
4001 arg_type++;
4002 assert(*arg_type == TYPE_STRUCT);
4003 target_size = thunk_type_size(arg_type, 0);
4004 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4005 if (!argptr) {
4006 return -TARGET_EFAULT;
4007 }
4008 arg_type++;
4009 assert(*arg_type == (int)STRUCT_rtentry);
4010 se = struct_entries + *arg_type++;
4011 assert(se->convert[0] == NULL);
4012 /* convert struct here to be able to catch rt_dev string */
4013 field_types = se->field_types;
4014 dst_offsets = se->field_offsets[THUNK_HOST];
4015 src_offsets = se->field_offsets[THUNK_TARGET];
4016 for (i = 0; i < se->nb_fields; i++) {
4017 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4018 assert(*field_types == TYPE_PTRVOID);
4019 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4020 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4021 if (*target_rt_dev_ptr != 0) {
4022 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4023 tswapal(*target_rt_dev_ptr));
4024 if (!*host_rt_dev_ptr) {
4025 unlock_user(argptr, arg, 0);
4026 return -TARGET_EFAULT;
4027 }
4028 } else {
4029 *host_rt_dev_ptr = 0;
4030 }
4031 field_types++;
4032 continue;
4033 }
4034 field_types = thunk_convert(buf_temp + dst_offsets[i],
4035 argptr + src_offsets[i],
4036 field_types, THUNK_HOST);
4037 }
4038 unlock_user(argptr, arg, 0);
4039
4040 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4041 if (*host_rt_dev_ptr != 0) {
4042 unlock_user((void *)*host_rt_dev_ptr,
4043 *target_rt_dev_ptr, 0);
4044 }
4045 return ret;
4046}
4047
Paul Burtonca56f5b2014-06-22 11:25:47 +01004048static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004049 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004050{
4051 int sig = target_to_host_signal(arg);
4052 return get_errno(ioctl(fd, ie->host_cmd, sig));
4053}
4054
blueswir19f106a72008-10-05 10:52:52 +00004055static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004056#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004057 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4058#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4059 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004060#include "ioctls.h"
4061 { 0, 0, },
4062};
4063
pbrook53a59602006-03-25 19:31:22 +00004064/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004065/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004066static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004067{
4068 const IOCTLEntry *ie;
4069 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004070 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004071 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004072 int target_size;
4073 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004074
4075 ie = ioctl_entries;
4076 for(;;) {
4077 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004078 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004079 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004080 }
4081 if (ie->target_cmd == cmd)
4082 break;
4083 ie++;
4084 }
4085 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004086#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004087 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004088#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004089 if (ie->do_ioctl) {
4090 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4091 }
4092
bellard31e31b82003-02-18 22:55:36 +00004093 switch(arg_type[0]) {
4094 case TYPE_NULL:
4095 /* no argument */
4096 ret = get_errno(ioctl(fd, ie->host_cmd));
4097 break;
4098 case TYPE_PTRVOID:
4099 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004100 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4101 break;
4102 case TYPE_PTR:
4103 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004104 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004105 switch(ie->access) {
4106 case IOC_R:
4107 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4108 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004109 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4110 if (!argptr)
4111 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004112 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4113 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004114 }
4115 break;
4116 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004117 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4118 if (!argptr)
4119 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004120 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4121 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004122 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4123 break;
4124 default:
4125 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004126 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4127 if (!argptr)
4128 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004129 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4130 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004131 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4132 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004133 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4134 if (!argptr)
4135 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004136 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4137 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004138 }
4139 break;
4140 }
4141 break;
4142 default:
j_mayer32407102007-09-26 23:01:49 +00004143 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4144 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004145 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004146 break;
4147 }
4148 return ret;
4149}
4150
blueswir1b39bc502008-10-05 10:51:10 +00004151static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004152 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4153 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4154 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4155 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4156 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4157 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4158 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4159 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4160 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4161 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4162 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4163 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4164 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4165 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4166 { 0, 0, 0, 0 }
4167};
4168
blueswir1b39bc502008-10-05 10:51:10 +00004169static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004170 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4171 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4172 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4173 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4174 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4175 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4176 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4177 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4178 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4179 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4180 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4181 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4182 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4183 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4184 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4185 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4186 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4187 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4188 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4189 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4190 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4191 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4192 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4193 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4194 { 0, 0, 0, 0 }
4195};
4196
blueswir1b39bc502008-10-05 10:51:10 +00004197static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004198 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4199 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4200 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4201 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4202 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4203 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4204 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4205 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4206 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4207 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4208 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4209 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4210 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4211 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4212 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4213 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4214 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4215 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4216 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4217 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4218 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4219 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4220 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4221 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4222 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4223 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4224 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4225 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4226 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4227 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4228 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4229 { 0, 0, 0, 0 }
4230};
4231
blueswir1b39bc502008-10-05 10:51:10 +00004232static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004233 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4234 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4235 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4236 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4237 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4238 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4239 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4240 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4241 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4242 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4243 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4244 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4245 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4246 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4247 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4248 { 0, 0, 0, 0 }
4249};
4250
4251static void target_to_host_termios (void *dst, const void *src)
4252{
4253 struct host_termios *host = dst;
4254 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004255
ths5fafdf22007-09-16 21:08:06 +00004256 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004257 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004258 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004259 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004260 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004261 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004262 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004263 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4264 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004265
Arnaud Patard44607122009-04-21 17:39:08 +03004266 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004267 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4268 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004269 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004270 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004271 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004272 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004273 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004274 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004275 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004276 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4277 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004278 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4279 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4280 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4281 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4282 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004283 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004284}
ths3b46e622007-09-17 08:09:54 +00004285
bellard31e31b82003-02-18 22:55:36 +00004286static void host_to_target_termios (void *dst, const void *src)
4287{
4288 struct target_termios *target = dst;
4289 const struct host_termios *host = src;
4290
ths5fafdf22007-09-16 21:08:06 +00004291 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004292 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004293 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004294 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004295 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004296 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004297 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004298 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4299 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004300
Arnaud Patard44607122009-04-21 17:39:08 +03004301 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004302 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4303 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4304 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4305 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4306 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4307 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4308 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4309 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4310 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4311 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4312 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4313 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4314 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4315 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4316 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4317 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4318 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4319}
4320
blueswir18e853dc2008-10-05 10:49:32 +00004321static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004322 .convert = { host_to_target_termios, target_to_host_termios },
4323 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4324 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4325};
4326
bellard5286db72003-06-05 00:57:30 +00004327static bitmask_transtbl mmap_flags_tbl[] = {
4328 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4329 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4330 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4331 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4332 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4333 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4334 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4335 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004336 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4337 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004338 { 0, 0, 0, 0 }
4339};
4340
bellard2ab83ea2003-06-15 19:56:46 +00004341#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004342
4343/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004344static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004345
bellard03acab62007-11-11 14:57:14 +00004346static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004347{
4348 int size;
pbrook53a59602006-03-25 19:31:22 +00004349 void *p;
bellard6dbad632003-03-16 18:05:05 +00004350
4351 if (!ldt_table)
4352 return 0;
4353 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4354 if (size > bytecount)
4355 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004356 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4357 if (!p)
bellard03acab62007-11-11 14:57:14 +00004358 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004359 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004360 memcpy(p, ldt_table, size);
4361 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004362 return size;
4363}
4364
4365/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004366static abi_long write_ldt(CPUX86State *env,
4367 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004368{
4369 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004370 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004371 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004372 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004373 uint32_t *lp, entry_1, entry_2;
4374
4375 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004376 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004377 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004378 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004379 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004380 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004381 ldt_info.limit = tswap32(target_ldt_info->limit);
4382 ldt_info.flags = tswap32(target_ldt_info->flags);
4383 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004384
bellard6dbad632003-03-16 18:05:05 +00004385 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004386 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004387 seg_32bit = ldt_info.flags & 1;
4388 contents = (ldt_info.flags >> 1) & 3;
4389 read_exec_only = (ldt_info.flags >> 3) & 1;
4390 limit_in_pages = (ldt_info.flags >> 4) & 1;
4391 seg_not_present = (ldt_info.flags >> 5) & 1;
4392 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004393#ifdef TARGET_ABI32
4394 lm = 0;
4395#else
4396 lm = (ldt_info.flags >> 7) & 1;
4397#endif
bellard6dbad632003-03-16 18:05:05 +00004398 if (contents == 3) {
4399 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004400 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004401 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004402 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004403 }
4404 /* allocate the LDT */
4405 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004406 env->ldt.base = target_mmap(0,
4407 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4408 PROT_READ|PROT_WRITE,
4409 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4410 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004411 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004412 memset(g2h(env->ldt.base), 0,
4413 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004414 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004415 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004416 }
4417
4418 /* NOTE: same code as Linux kernel */
4419 /* Allow LDTs to be cleared by the user. */
4420 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4421 if (oldmode ||
4422 (contents == 0 &&
4423 read_exec_only == 1 &&
4424 seg_32bit == 0 &&
4425 limit_in_pages == 0 &&
4426 seg_not_present == 1 &&
4427 useable == 0 )) {
4428 entry_1 = 0;
4429 entry_2 = 0;
4430 goto install;
4431 }
4432 }
ths3b46e622007-09-17 08:09:54 +00004433
bellard6dbad632003-03-16 18:05:05 +00004434 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4435 (ldt_info.limit & 0x0ffff);
4436 entry_2 = (ldt_info.base_addr & 0xff000000) |
4437 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4438 (ldt_info.limit & 0xf0000) |
4439 ((read_exec_only ^ 1) << 9) |
4440 (contents << 10) |
4441 ((seg_not_present ^ 1) << 15) |
4442 (seg_32bit << 22) |
4443 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004444 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004445 0x7000;
4446 if (!oldmode)
4447 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004448
bellard6dbad632003-03-16 18:05:05 +00004449 /* Install the new entry ... */
4450install:
4451 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4452 lp[0] = tswap32(entry_1);
4453 lp[1] = tswap32(entry_2);
4454 return 0;
4455}
4456
4457/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004458static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4459 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004460{
bellard03acab62007-11-11 14:57:14 +00004461 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004462
bellard6dbad632003-03-16 18:05:05 +00004463 switch (func) {
4464 case 0:
4465 ret = read_ldt(ptr, bytecount);
4466 break;
4467 case 1:
4468 ret = write_ldt(env, ptr, bytecount, 1);
4469 break;
4470 case 0x11:
4471 ret = write_ldt(env, ptr, bytecount, 0);
4472 break;
bellard03acab62007-11-11 14:57:14 +00004473 default:
4474 ret = -TARGET_ENOSYS;
4475 break;
bellard6dbad632003-03-16 18:05:05 +00004476 }
4477 return ret;
4478}
bellard1b6b0292003-03-22 17:31:38 +00004479
blueswir14583f582008-08-24 10:35:55 +00004480#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004481abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004482{
4483 uint64_t *gdt_table = g2h(env->gdt.base);
4484 struct target_modify_ldt_ldt_s ldt_info;
4485 struct target_modify_ldt_ldt_s *target_ldt_info;
4486 int seg_32bit, contents, read_exec_only, limit_in_pages;
4487 int seg_not_present, useable, lm;
4488 uint32_t *lp, entry_1, entry_2;
4489 int i;
4490
4491 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4492 if (!target_ldt_info)
4493 return -TARGET_EFAULT;
4494 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004495 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004496 ldt_info.limit = tswap32(target_ldt_info->limit);
4497 ldt_info.flags = tswap32(target_ldt_info->flags);
4498 if (ldt_info.entry_number == -1) {
4499 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4500 if (gdt_table[i] == 0) {
4501 ldt_info.entry_number = i;
4502 target_ldt_info->entry_number = tswap32(i);
4503 break;
4504 }
4505 }
4506 }
4507 unlock_user_struct(target_ldt_info, ptr, 1);
4508
4509 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4510 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4511 return -TARGET_EINVAL;
4512 seg_32bit = ldt_info.flags & 1;
4513 contents = (ldt_info.flags >> 1) & 3;
4514 read_exec_only = (ldt_info.flags >> 3) & 1;
4515 limit_in_pages = (ldt_info.flags >> 4) & 1;
4516 seg_not_present = (ldt_info.flags >> 5) & 1;
4517 useable = (ldt_info.flags >> 6) & 1;
4518#ifdef TARGET_ABI32
4519 lm = 0;
4520#else
4521 lm = (ldt_info.flags >> 7) & 1;
4522#endif
4523
4524 if (contents == 3) {
4525 if (seg_not_present == 0)
4526 return -TARGET_EINVAL;
4527 }
4528
4529 /* NOTE: same code as Linux kernel */
4530 /* Allow LDTs to be cleared by the user. */
4531 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4532 if ((contents == 0 &&
4533 read_exec_only == 1 &&
4534 seg_32bit == 0 &&
4535 limit_in_pages == 0 &&
4536 seg_not_present == 1 &&
4537 useable == 0 )) {
4538 entry_1 = 0;
4539 entry_2 = 0;
4540 goto install;
4541 }
4542 }
4543
4544 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4545 (ldt_info.limit & 0x0ffff);
4546 entry_2 = (ldt_info.base_addr & 0xff000000) |
4547 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4548 (ldt_info.limit & 0xf0000) |
4549 ((read_exec_only ^ 1) << 9) |
4550 (contents << 10) |
4551 ((seg_not_present ^ 1) << 15) |
4552 (seg_32bit << 22) |
4553 (limit_in_pages << 23) |
4554 (useable << 20) |
4555 (lm << 21) |
4556 0x7000;
4557
4558 /* Install the new entry ... */
4559install:
4560 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4561 lp[0] = tswap32(entry_1);
4562 lp[1] = tswap32(entry_2);
4563 return 0;
4564}
4565
blueswir18fcd3692008-08-17 20:26:25 +00004566static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004567{
4568 struct target_modify_ldt_ldt_s *target_ldt_info;
4569 uint64_t *gdt_table = g2h(env->gdt.base);
4570 uint32_t base_addr, limit, flags;
4571 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4572 int seg_not_present, useable, lm;
4573 uint32_t *lp, entry_1, entry_2;
4574
4575 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4576 if (!target_ldt_info)
4577 return -TARGET_EFAULT;
4578 idx = tswap32(target_ldt_info->entry_number);
4579 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4580 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4581 unlock_user_struct(target_ldt_info, ptr, 1);
4582 return -TARGET_EINVAL;
4583 }
4584 lp = (uint32_t *)(gdt_table + idx);
4585 entry_1 = tswap32(lp[0]);
4586 entry_2 = tswap32(lp[1]);
4587
4588 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4589 contents = (entry_2 >> 10) & 3;
4590 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4591 seg_32bit = (entry_2 >> 22) & 1;
4592 limit_in_pages = (entry_2 >> 23) & 1;
4593 useable = (entry_2 >> 20) & 1;
4594#ifdef TARGET_ABI32
4595 lm = 0;
4596#else
4597 lm = (entry_2 >> 21) & 1;
4598#endif
4599 flags = (seg_32bit << 0) | (contents << 1) |
4600 (read_exec_only << 3) | (limit_in_pages << 4) |
4601 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4602 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4603 base_addr = (entry_1 >> 16) |
4604 (entry_2 & 0xff000000) |
4605 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004606 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004607 target_ldt_info->limit = tswap32(limit);
4608 target_ldt_info->flags = tswap32(flags);
4609 unlock_user_struct(target_ldt_info, ptr, 1);
4610 return 0;
4611}
blueswir14583f582008-08-24 10:35:55 +00004612#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004613
bellardd2fd1af2007-11-14 18:08:56 +00004614#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004615abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004616{
Juan Quintela1add8692011-06-16 17:37:09 +01004617 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004618 abi_ulong val;
4619 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004620
bellardd2fd1af2007-11-14 18:08:56 +00004621 switch(code) {
4622 case TARGET_ARCH_SET_GS:
4623 case TARGET_ARCH_SET_FS:
4624 if (code == TARGET_ARCH_SET_GS)
4625 idx = R_GS;
4626 else
4627 idx = R_FS;
4628 cpu_x86_load_seg(env, idx, 0);
4629 env->segs[idx].base = addr;
4630 break;
4631 case TARGET_ARCH_GET_GS:
4632 case TARGET_ARCH_GET_FS:
4633 if (code == TARGET_ARCH_GET_GS)
4634 idx = R_GS;
4635 else
4636 idx = R_FS;
4637 val = env->segs[idx].base;
4638 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004639 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004640 break;
4641 default:
4642 ret = -TARGET_EINVAL;
4643 break;
4644 }
Juan Quintela1add8692011-06-16 17:37:09 +01004645 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004646}
4647#endif
4648
bellard2ab83ea2003-06-15 19:56:46 +00004649#endif /* defined(TARGET_I386) */
4650
Riku Voipio05098a92011-03-04 15:27:29 +02004651#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004652
pbrookd865bab2008-06-07 22:12:17 +00004653
4654static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4655typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004656 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004657 pthread_mutex_t mutex;
4658 pthread_cond_t cond;
4659 pthread_t thread;
4660 uint32_t tid;
4661 abi_ulong child_tidptr;
4662 abi_ulong parent_tidptr;
4663 sigset_t sigmask;
4664} new_thread_info;
4665
4666static void *clone_func(void *arg)
4667{
4668 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004669 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004670 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004671 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004672
Emilio G. Cota70903762015-08-23 20:23:41 -04004673 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00004674 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004675 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004676 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004677 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004678 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004679 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004680 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004681 if (info->child_tidptr)
4682 put_user_u32(info->tid, info->child_tidptr);
4683 if (info->parent_tidptr)
4684 put_user_u32(info->tid, info->parent_tidptr);
4685 /* Enable signals. */
4686 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4687 /* Signal to the parent that we're ready. */
4688 pthread_mutex_lock(&info->mutex);
4689 pthread_cond_broadcast(&info->cond);
4690 pthread_mutex_unlock(&info->mutex);
4691 /* Wait until the parent has finshed initializing the tls state. */
4692 pthread_mutex_lock(&clone_lock);
4693 pthread_mutex_unlock(&clone_lock);
4694 cpu_loop(env);
4695 /* never exits */
4696 return NULL;
4697}
bellard1b6b0292003-03-22 17:31:38 +00004698
ths0da46a62007-10-20 20:23:07 +00004699/* do_fork() Must return host values and target errnos (unlike most
4700 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004701static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004702 abi_ulong parent_tidptr, target_ulong newtls,
4703 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004704{
Andreas Färber0429a972013-08-26 18:14:44 +02004705 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004706 int ret;
bellard5cd43932003-03-29 16:54:36 +00004707 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004708 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004709 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004710 unsigned int nptl_flags;
4711 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004712
balrog436d1242008-09-21 02:39:45 +00004713 /* Emulate vfork() with fork() */
4714 if (flags & CLONE_VFORK)
4715 flags &= ~(CLONE_VFORK | CLONE_VM);
4716
bellard1b6b0292003-03-22 17:31:38 +00004717 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004718 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004719 new_thread_info info;
4720 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004721
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02004722 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00004723 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004724 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004725 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004726 /* Init regs that differ from the parent. */
4727 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004728 new_cpu = ENV_GET_CPU(new_env);
4729 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004730 ts->bprm = parent_ts->bprm;
4731 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004732 nptl_flags = flags;
4733 flags &= ~CLONE_NPTL_FLAGS2;
4734
pbrookc2764712009-03-07 15:24:59 +00004735 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4736 ts->child_tidptr = child_tidptr;
4737 }
4738
pbrookd865bab2008-06-07 22:12:17 +00004739 if (nptl_flags & CLONE_SETTLS)
4740 cpu_set_tls (new_env, newtls);
4741
4742 /* Grab a mutex so that thread setup appears atomic. */
4743 pthread_mutex_lock(&clone_lock);
4744
4745 memset(&info, 0, sizeof(info));
4746 pthread_mutex_init(&info.mutex, NULL);
4747 pthread_mutex_lock(&info.mutex);
4748 pthread_cond_init(&info.cond, NULL);
4749 info.env = new_env;
4750 if (nptl_flags & CLONE_CHILD_SETTID)
4751 info.child_tidptr = child_tidptr;
4752 if (nptl_flags & CLONE_PARENT_SETTID)
4753 info.parent_tidptr = parent_tidptr;
4754
4755 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004756 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4757 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004758 /* It is not safe to deliver signals until the child has finished
4759 initializing, so temporarily block all signals. */
4760 sigfillset(&sigmask);
4761 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4762
4763 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004764 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004765
4766 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4767 pthread_attr_destroy(&attr);
4768 if (ret == 0) {
4769 /* Wait for the child to initialize. */
4770 pthread_cond_wait(&info.cond, &info.mutex);
4771 ret = info.tid;
4772 if (flags & CLONE_PARENT_SETTID)
4773 put_user_u32(ret, parent_tidptr);
4774 } else {
4775 ret = -1;
4776 }
4777 pthread_mutex_unlock(&info.mutex);
4778 pthread_cond_destroy(&info.cond);
4779 pthread_mutex_destroy(&info.mutex);
4780 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004781 } else {
4782 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01004783 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
4784 return -TARGET_EINVAL;
4785 }
pbrookd865bab2008-06-07 22:12:17 +00004786 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004787 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004788 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004789 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02004790 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00004791 cpu_clone_regs(env, newsp);
4792 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004793 /* There is a race condition here. The parent process could
4794 theoretically read the TID in the child process before the child
4795 tid is set. This would require using either ptrace
4796 (not implemented) or having *_tidptr to point at a shared memory
4797 mapping. We can't repeat the spinlock hack used above because
4798 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004799 if (flags & CLONE_CHILD_SETTID)
4800 put_user_u32(gettid(), child_tidptr);
4801 if (flags & CLONE_PARENT_SETTID)
4802 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004803 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004804 if (flags & CLONE_SETTLS)
4805 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004806 if (flags & CLONE_CHILD_CLEARTID)
4807 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004808 } else {
4809 fork_end(0);
4810 }
bellard1b6b0292003-03-22 17:31:38 +00004811 }
4812 return ret;
4813}
4814
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004815/* warning : doesn't handle linux specific flags... */
4816static int target_to_host_fcntl_cmd(int cmd)
4817{
4818 switch(cmd) {
4819 case TARGET_F_DUPFD:
4820 case TARGET_F_GETFD:
4821 case TARGET_F_SETFD:
4822 case TARGET_F_GETFL:
4823 case TARGET_F_SETFL:
4824 return cmd;
4825 case TARGET_F_GETLK:
4826 return F_GETLK;
4827 case TARGET_F_SETLK:
4828 return F_SETLK;
4829 case TARGET_F_SETLKW:
4830 return F_SETLKW;
4831 case TARGET_F_GETOWN:
4832 return F_GETOWN;
4833 case TARGET_F_SETOWN:
4834 return F_SETOWN;
4835 case TARGET_F_GETSIG:
4836 return F_GETSIG;
4837 case TARGET_F_SETSIG:
4838 return F_SETSIG;
4839#if TARGET_ABI_BITS == 32
4840 case TARGET_F_GETLK64:
4841 return F_GETLK64;
4842 case TARGET_F_SETLK64:
4843 return F_SETLK64;
4844 case TARGET_F_SETLKW64:
4845 return F_SETLKW64;
4846#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004847 case TARGET_F_SETLEASE:
4848 return F_SETLEASE;
4849 case TARGET_F_GETLEASE:
4850 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004851#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004852 case TARGET_F_DUPFD_CLOEXEC:
4853 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004854#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004855 case TARGET_F_NOTIFY:
4856 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004857#ifdef F_GETOWN_EX
4858 case TARGET_F_GETOWN_EX:
4859 return F_GETOWN_EX;
4860#endif
4861#ifdef F_SETOWN_EX
4862 case TARGET_F_SETOWN_EX:
4863 return F_SETOWN_EX;
4864#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004865 default:
4866 return -TARGET_EINVAL;
4867 }
4868 return -TARGET_EINVAL;
4869}
4870
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004871#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4872static const bitmask_transtbl flock_tbl[] = {
4873 TRANSTBL_CONVERT(F_RDLCK),
4874 TRANSTBL_CONVERT(F_WRLCK),
4875 TRANSTBL_CONVERT(F_UNLCK),
4876 TRANSTBL_CONVERT(F_EXLCK),
4877 TRANSTBL_CONVERT(F_SHLCK),
4878 { 0, 0, 0, 0 }
4879};
4880
blueswir1992f48a2007-10-14 16:27:31 +00004881static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004882{
4883 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004884 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004885 struct flock64 fl64;
4886 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004887#ifdef F_GETOWN_EX
4888 struct f_owner_ex fox;
4889 struct target_f_owner_ex *target_fox;
4890#endif
blueswir1992f48a2007-10-14 16:27:31 +00004891 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004892 int host_cmd = target_to_host_fcntl_cmd(cmd);
4893
4894 if (host_cmd == -TARGET_EINVAL)
4895 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004896
bellard7775e9e2003-05-14 22:46:48 +00004897 switch(cmd) {
4898 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004899 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4900 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004901 fl.l_type =
4902 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004903 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004904 fl.l_start = tswapal(target_fl->l_start);
4905 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004906 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004907 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004908 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004909 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004910 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4911 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004912 target_fl->l_type =
4913 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004914 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004915 target_fl->l_start = tswapal(fl.l_start);
4916 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004917 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004918 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004919 }
4920 break;
ths3b46e622007-09-17 08:09:54 +00004921
bellard7775e9e2003-05-14 22:46:48 +00004922 case TARGET_F_SETLK:
4923 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004924 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4925 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004926 fl.l_type =
4927 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004928 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004929 fl.l_start = tswapal(target_fl->l_start);
4930 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004931 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004932 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004933 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004934 break;
ths3b46e622007-09-17 08:09:54 +00004935
bellard7775e9e2003-05-14 22:46:48 +00004936 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004937 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4938 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004939 fl64.l_type =
4940 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004941 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004942 fl64.l_start = tswap64(target_fl64->l_start);
4943 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004944 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004945 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004946 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004947 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004948 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4949 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004950 target_fl64->l_type =
4951 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004952 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004953 target_fl64->l_start = tswap64(fl64.l_start);
4954 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004955 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004956 unlock_user_struct(target_fl64, arg, 1);
4957 }
bellard9ee1fa22007-11-11 15:11:19 +00004958 break;
bellard7775e9e2003-05-14 22:46:48 +00004959 case TARGET_F_SETLK64:
4960 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004961 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4962 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004963 fl64.l_type =
4964 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004965 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004966 fl64.l_start = tswap64(target_fl64->l_start);
4967 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004968 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004969 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004970 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004971 break;
4972
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004973 case TARGET_F_GETFL:
4974 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004975 if (ret >= 0) {
4976 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4977 }
bellardffa65c32004-01-04 23:57:22 +00004978 break;
4979
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004980 case TARGET_F_SETFL:
4981 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4982 break;
4983
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004984#ifdef F_GETOWN_EX
4985 case TARGET_F_GETOWN_EX:
4986 ret = get_errno(fcntl(fd, host_cmd, &fox));
4987 if (ret >= 0) {
4988 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4989 return -TARGET_EFAULT;
4990 target_fox->type = tswap32(fox.type);
4991 target_fox->pid = tswap32(fox.pid);
4992 unlock_user_struct(target_fox, arg, 1);
4993 }
4994 break;
4995#endif
4996
4997#ifdef F_SETOWN_EX
4998 case TARGET_F_SETOWN_EX:
4999 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5000 return -TARGET_EFAULT;
5001 fox.type = tswap32(target_fox->type);
5002 fox.pid = tswap32(target_fox->pid);
5003 unlock_user_struct(target_fox, arg, 0);
5004 ret = get_errno(fcntl(fd, host_cmd, &fox));
5005 break;
5006#endif
5007
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005008 case TARGET_F_SETOWN:
5009 case TARGET_F_GETOWN:
5010 case TARGET_F_SETSIG:
5011 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005012 case TARGET_F_SETLEASE:
5013 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005014 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005015 break;
5016
bellard7775e9e2003-05-14 22:46:48 +00005017 default:
bellard9ee1fa22007-11-11 15:11:19 +00005018 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005019 break;
5020 }
5021 return ret;
5022}
5023
bellard67867302003-11-23 17:05:30 +00005024#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005025
bellard67867302003-11-23 17:05:30 +00005026static inline int high2lowuid(int uid)
5027{
5028 if (uid > 65535)
5029 return 65534;
5030 else
5031 return uid;
5032}
5033
5034static inline int high2lowgid(int gid)
5035{
5036 if (gid > 65535)
5037 return 65534;
5038 else
5039 return gid;
5040}
5041
5042static inline int low2highuid(int uid)
5043{
5044 if ((int16_t)uid == -1)
5045 return -1;
5046 else
5047 return uid;
5048}
5049
5050static inline int low2highgid(int gid)
5051{
5052 if ((int16_t)gid == -1)
5053 return -1;
5054 else
5055 return gid;
5056}
Riku Voipio0c866a72011-04-18 15:23:06 +03005057static inline int tswapid(int id)
5058{
5059 return tswap16(id);
5060}
Peter Maydell76ca3102014-03-02 19:36:41 +00005061
5062#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5063
Riku Voipio0c866a72011-04-18 15:23:06 +03005064#else /* !USE_UID16 */
5065static inline int high2lowuid(int uid)
5066{
5067 return uid;
5068}
5069static inline int high2lowgid(int gid)
5070{
5071 return gid;
5072}
5073static inline int low2highuid(int uid)
5074{
5075 return uid;
5076}
5077static inline int low2highgid(int gid)
5078{
5079 return gid;
5080}
5081static inline int tswapid(int id)
5082{
5083 return tswap32(id);
5084}
Peter Maydell76ca3102014-03-02 19:36:41 +00005085
5086#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5087
bellard67867302003-11-23 17:05:30 +00005088#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005089
bellard31e31b82003-02-18 22:55:36 +00005090void syscall_init(void)
5091{
bellard2ab83ea2003-06-15 19:56:46 +00005092 IOCTLEntry *ie;
5093 const argtype *arg_type;
5094 int size;
thsb92c47c2007-11-01 00:07:38 +00005095 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005096
Alexander Graf8be656b2015-05-06 23:47:32 +02005097 thunk_init(STRUCT_MAX);
5098
Blue Swirl001faf32009-05-13 17:53:17 +00005099#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005100#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005101#include "syscall_types.h"
5102#undef STRUCT
5103#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005104
Peter Maydelldd6e9572012-07-23 08:07:22 +00005105 /* Build target_to_host_errno_table[] table from
5106 * host_to_target_errno_table[]. */
5107 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5108 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5109 }
5110
bellard2ab83ea2003-06-15 19:56:46 +00005111 /* we patch the ioctl size if necessary. We rely on the fact that
5112 no ioctl has all the bits at '1' in the size field */
5113 ie = ioctl_entries;
5114 while (ie->target_cmd != 0) {
5115 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5116 TARGET_IOC_SIZEMASK) {
5117 arg_type = ie->arg_type;
5118 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005119 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005120 ie->target_cmd);
5121 exit(1);
5122 }
5123 arg_type++;
5124 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005125 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005126 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5127 (size << TARGET_IOC_SIZESHIFT);
5128 }
thsb92c47c2007-11-01 00:07:38 +00005129
bellard2ab83ea2003-06-15 19:56:46 +00005130 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005131#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5132 (defined(__x86_64__) && defined(TARGET_X86_64))
5133 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5134 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5135 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005136 }
5137#endif
5138 ie++;
5139 }
bellard31e31b82003-02-18 22:55:36 +00005140}
bellardc573ff62004-01-04 15:51:36 +00005141
blueswir1992f48a2007-10-14 16:27:31 +00005142#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005143static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5144{
thsaf325d32008-06-10 15:29:15 +00005145#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005146 return ((uint64_t)word0 << 32) | word1;
5147#else
5148 return ((uint64_t)word1 << 32) | word0;
5149#endif
5150}
blueswir1992f48a2007-10-14 16:27:31 +00005151#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005152static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5153{
5154 return word0;
5155}
blueswir1992f48a2007-10-14 16:27:31 +00005156#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005157
5158#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005159static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5160 abi_long arg2,
5161 abi_long arg3,
5162 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005163{
Riku Voipio48e515d2011-07-12 15:40:51 +03005164 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005165 arg2 = arg3;
5166 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005167 }
pbrookce4defa2006-02-09 16:49:55 +00005168 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5169}
5170#endif
5171
5172#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005173static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5174 abi_long arg2,
5175 abi_long arg3,
5176 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005177{
Riku Voipio48e515d2011-07-12 15:40:51 +03005178 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005179 arg2 = arg3;
5180 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005181 }
pbrookce4defa2006-02-09 16:49:55 +00005182 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5183}
5184#endif
5185
bellard579a97f2007-11-11 14:26:47 +00005186static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5187 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005188{
5189 struct target_timespec *target_ts;
5190
bellard579a97f2007-11-11 14:26:47 +00005191 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5192 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005193 host_ts->tv_sec = tswapal(target_ts->tv_sec);
5194 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005195 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005196 return 0;
pbrook53a59602006-03-25 19:31:22 +00005197}
5198
bellard579a97f2007-11-11 14:26:47 +00005199static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5200 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005201{
5202 struct target_timespec *target_ts;
5203
bellard579a97f2007-11-11 14:26:47 +00005204 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5205 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005206 target_ts->tv_sec = tswapal(host_ts->tv_sec);
5207 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005208 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005209 return 0;
pbrook53a59602006-03-25 19:31:22 +00005210}
5211
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005212static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5213 abi_ulong target_addr)
5214{
5215 struct target_itimerspec *target_itspec;
5216
5217 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5218 return -TARGET_EFAULT;
5219 }
5220
5221 host_itspec->it_interval.tv_sec =
5222 tswapal(target_itspec->it_interval.tv_sec);
5223 host_itspec->it_interval.tv_nsec =
5224 tswapal(target_itspec->it_interval.tv_nsec);
5225 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5226 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5227
5228 unlock_user_struct(target_itspec, target_addr, 1);
5229 return 0;
5230}
5231
5232static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5233 struct itimerspec *host_its)
5234{
5235 struct target_itimerspec *target_itspec;
5236
5237 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5238 return -TARGET_EFAULT;
5239 }
5240
5241 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5242 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5243
5244 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5245 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5246
5247 unlock_user_struct(target_itspec, target_addr, 0);
5248 return 0;
5249}
5250
Peter Maydellc0659762014-08-09 15:42:32 +01005251static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5252 abi_ulong target_addr)
5253{
5254 struct target_sigevent *target_sevp;
5255
5256 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5257 return -TARGET_EFAULT;
5258 }
5259
5260 /* This union is awkward on 64 bit systems because it has a 32 bit
5261 * integer and a pointer in it; we follow the conversion approach
5262 * used for handling sigval types in signal.c so the guest should get
5263 * the correct value back even if we did a 64 bit byteswap and it's
5264 * using the 32 bit integer.
5265 */
5266 host_sevp->sigev_value.sival_ptr =
5267 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5268 host_sevp->sigev_signo =
5269 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5270 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5271 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5272
5273 unlock_user_struct(target_sevp, target_addr, 1);
5274 return 0;
5275}
5276
Tom Musta6f6a4032014-08-12 13:53:42 -05005277#if defined(TARGET_NR_mlockall)
5278static inline int target_to_host_mlockall_arg(int arg)
5279{
5280 int result = 0;
5281
5282 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5283 result |= MCL_CURRENT;
5284 }
5285 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5286 result |= MCL_FUTURE;
5287 }
5288 return result;
5289}
5290#endif
5291
balrog6a24a772008-09-20 02:23:36 +00005292static inline abi_long host_to_target_stat64(void *cpu_env,
5293 abi_ulong target_addr,
5294 struct stat *host_st)
5295{
Alexander Graf09701192013-09-03 20:12:15 +01005296#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005297 if (((CPUARMState *)cpu_env)->eabi) {
5298 struct target_eabi_stat64 *target_st;
5299
5300 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5301 return -TARGET_EFAULT;
5302 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5303 __put_user(host_st->st_dev, &target_st->st_dev);
5304 __put_user(host_st->st_ino, &target_st->st_ino);
5305#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5306 __put_user(host_st->st_ino, &target_st->__st_ino);
5307#endif
5308 __put_user(host_st->st_mode, &target_st->st_mode);
5309 __put_user(host_st->st_nlink, &target_st->st_nlink);
5310 __put_user(host_st->st_uid, &target_st->st_uid);
5311 __put_user(host_st->st_gid, &target_st->st_gid);
5312 __put_user(host_st->st_rdev, &target_st->st_rdev);
5313 __put_user(host_st->st_size, &target_st->st_size);
5314 __put_user(host_st->st_blksize, &target_st->st_blksize);
5315 __put_user(host_st->st_blocks, &target_st->st_blocks);
5316 __put_user(host_st->st_atime, &target_st->target_st_atime);
5317 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5318 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5319 unlock_user_struct(target_st, target_addr, 1);
5320 } else
5321#endif
5322 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005323#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005324 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005325#else
5326 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005327#endif
balrog6a24a772008-09-20 02:23:36 +00005328
5329 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5330 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005331 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005332 __put_user(host_st->st_dev, &target_st->st_dev);
5333 __put_user(host_st->st_ino, &target_st->st_ino);
5334#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5335 __put_user(host_st->st_ino, &target_st->__st_ino);
5336#endif
5337 __put_user(host_st->st_mode, &target_st->st_mode);
5338 __put_user(host_st->st_nlink, &target_st->st_nlink);
5339 __put_user(host_st->st_uid, &target_st->st_uid);
5340 __put_user(host_st->st_gid, &target_st->st_gid);
5341 __put_user(host_st->st_rdev, &target_st->st_rdev);
5342 /* XXX: better use of kernel struct */
5343 __put_user(host_st->st_size, &target_st->st_size);
5344 __put_user(host_st->st_blksize, &target_st->st_blksize);
5345 __put_user(host_st->st_blocks, &target_st->st_blocks);
5346 __put_user(host_st->st_atime, &target_st->target_st_atime);
5347 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5348 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5349 unlock_user_struct(target_st, target_addr, 1);
5350 }
5351
5352 return 0;
5353}
balrog6a24a772008-09-20 02:23:36 +00005354
pbrookbd0c5662008-05-29 14:34:11 +00005355/* ??? Using host futex calls even when target atomic operations
5356 are not really atomic probably breaks things. However implementing
5357 futexes locally would make futexes shared between multiple processes
5358 tricky. However they're probably useless because guest atomic
5359 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005360static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5361 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005362{
5363 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005364 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005365
5366 /* ??? We assume FUTEX_* constants are the same on both host
5367 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005368#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005369 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005370#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005371 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005372#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005373 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005374 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005375 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005376 if (timeout) {
5377 pts = &ts;
5378 target_to_host_timespec(pts, timeout);
5379 } else {
5380 pts = NULL;
5381 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005382 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005383 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005384 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005385 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005386 case FUTEX_FD:
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_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005389 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005390 case FUTEX_WAKE_OP:
5391 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5392 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5393 But the prototype takes a `struct timespec *'; insert casts
5394 to satisfy the compiler. We do not need to tswap TIMEOUT
5395 since it's not compared to guest memory. */
5396 pts = (struct timespec *)(uintptr_t) timeout;
5397 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5398 g2h(uaddr2),
5399 (base_op == FUTEX_CMP_REQUEUE
5400 ? tswap32(val3)
5401 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005402 default:
5403 return -TARGET_ENOSYS;
5404 }
5405}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005406#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5407static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
5408 abi_long handle, abi_long mount_id,
5409 abi_long flags)
5410{
5411 struct file_handle *target_fh;
5412 struct file_handle *fh;
5413 int mid = 0;
5414 abi_long ret;
5415 char *name;
5416 unsigned int size, total_size;
5417
5418 if (get_user_s32(size, handle)) {
5419 return -TARGET_EFAULT;
5420 }
5421
5422 name = lock_user_string(pathname);
5423 if (!name) {
5424 return -TARGET_EFAULT;
5425 }
5426
5427 total_size = sizeof(struct file_handle) + size;
5428 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
5429 if (!target_fh) {
5430 unlock_user(name, pathname, 0);
5431 return -TARGET_EFAULT;
5432 }
5433
5434 fh = g_malloc0(total_size);
5435 fh->handle_bytes = size;
5436
5437 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
5438 unlock_user(name, pathname, 0);
5439
5440 /* man name_to_handle_at(2):
5441 * Other than the use of the handle_bytes field, the caller should treat
5442 * the file_handle structure as an opaque data type
5443 */
5444
5445 memcpy(target_fh, fh, total_size);
5446 target_fh->handle_bytes = tswap32(fh->handle_bytes);
5447 target_fh->handle_type = tswap32(fh->handle_type);
5448 g_free(fh);
5449 unlock_user(target_fh, handle, total_size);
5450
5451 if (put_user_s32(mid, mount_id)) {
5452 return -TARGET_EFAULT;
5453 }
5454
5455 return ret;
5456
5457}
5458#endif
5459
5460#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5461static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
5462 abi_long flags)
5463{
5464 struct file_handle *target_fh;
5465 struct file_handle *fh;
5466 unsigned int size, total_size;
5467 abi_long ret;
5468
5469 if (get_user_s32(size, handle)) {
5470 return -TARGET_EFAULT;
5471 }
5472
5473 total_size = sizeof(struct file_handle) + size;
5474 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
5475 if (!target_fh) {
5476 return -TARGET_EFAULT;
5477 }
5478
Thomas Huthe9d49d52015-10-09 17:56:38 +02005479 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005480 fh->handle_bytes = size;
5481 fh->handle_type = tswap32(target_fh->handle_type);
5482
5483 ret = get_errno(open_by_handle_at(mount_fd, fh,
5484 target_to_host_bitmask(flags, fcntl_flags_tbl)));
5485
5486 g_free(fh);
5487
5488 unlock_user(target_fh, handle, total_size);
5489
5490 return ret;
5491}
5492#endif
pbrookbd0c5662008-05-29 14:34:11 +00005493
Laurent Viviere36800c2015-10-02 14:48:09 +02005494#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
5495
5496/* signalfd siginfo conversion */
5497
5498static void
5499host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
5500 const struct signalfd_siginfo *info)
5501{
5502 int sig = host_to_target_signal(info->ssi_signo);
5503
5504 /* linux/signalfd.h defines a ssi_addr_lsb
5505 * not defined in sys/signalfd.h but used by some kernels
5506 */
5507
5508#ifdef BUS_MCEERR_AO
5509 if (tinfo->ssi_signo == SIGBUS &&
5510 (tinfo->ssi_code == BUS_MCEERR_AR ||
5511 tinfo->ssi_code == BUS_MCEERR_AO)) {
5512 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
5513 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
5514 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
5515 }
5516#endif
5517
5518 tinfo->ssi_signo = tswap32(sig);
5519 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
5520 tinfo->ssi_code = tswap32(info->ssi_code);
5521 tinfo->ssi_pid = tswap32(info->ssi_pid);
5522 tinfo->ssi_uid = tswap32(info->ssi_uid);
5523 tinfo->ssi_fd = tswap32(info->ssi_fd);
5524 tinfo->ssi_tid = tswap32(info->ssi_tid);
5525 tinfo->ssi_band = tswap32(info->ssi_band);
5526 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
5527 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
5528 tinfo->ssi_status = tswap32(info->ssi_status);
5529 tinfo->ssi_int = tswap32(info->ssi_int);
5530 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
5531 tinfo->ssi_utime = tswap64(info->ssi_utime);
5532 tinfo->ssi_stime = tswap64(info->ssi_stime);
5533 tinfo->ssi_addr = tswap64(info->ssi_addr);
5534}
5535
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005536static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02005537{
5538 int i;
5539
5540 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
5541 host_to_target_signalfd_siginfo(buf + i, buf + i);
5542 }
5543
5544 return len;
5545}
5546
5547static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005548 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02005549};
5550
5551static abi_long do_signalfd4(int fd, abi_long mask, int flags)
5552{
5553 int host_flags;
5554 target_sigset_t *target_mask;
5555 sigset_t host_mask;
5556 abi_long ret;
5557
5558 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
5559 return -TARGET_EINVAL;
5560 }
5561 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
5562 return -TARGET_EFAULT;
5563 }
5564
5565 target_to_host_sigset(&host_mask, target_mask);
5566
5567 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
5568
5569 ret = get_errno(signalfd(fd, &host_mask, host_flags));
5570 if (ret >= 0) {
5571 fd_trans_register(ret, &target_signalfd_trans);
5572 }
5573
5574 unlock_user_struct(target_mask, mask, 0);
5575
5576 return ret;
5577}
5578#endif
5579
pbrook1d9d8b52009-04-16 15:17:02 +00005580/* Map host to target signal numbers for the wait family of syscalls.
5581 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005582int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005583{
5584 if (WIFSIGNALED(status)) {
5585 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5586 }
5587 if (WIFSTOPPED(status)) {
5588 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5589 | (status & 0xff);
5590 }
5591 return status;
5592}
5593
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005594static int open_self_cmdline(void *cpu_env, int fd)
5595{
5596 int fd_orig = -1;
5597 bool word_skipped = false;
5598
5599 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5600 if (fd_orig < 0) {
5601 return fd_orig;
5602 }
5603
5604 while (true) {
5605 ssize_t nb_read;
5606 char buf[128];
5607 char *cp_buf = buf;
5608
5609 nb_read = read(fd_orig, buf, sizeof(buf));
5610 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005611 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005612 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005613 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005614 return -1;
5615 } else if (nb_read == 0) {
5616 break;
5617 }
5618
5619 if (!word_skipped) {
5620 /* Skip the first string, which is the path to qemu-*-static
5621 instead of the actual command. */
5622 cp_buf = memchr(buf, 0, sizeof(buf));
5623 if (cp_buf) {
5624 /* Null byte found, skip one string */
5625 cp_buf++;
5626 nb_read -= cp_buf - buf;
5627 word_skipped = true;
5628 }
5629 }
5630
5631 if (word_skipped) {
5632 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005633 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08005634 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005635 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005636 return -1;
5637 }
5638 }
5639 }
5640
5641 return close(fd_orig);
5642}
5643
Alexander Graf36c08d42011-11-02 20:23:24 +01005644static int open_self_maps(void *cpu_env, int fd)
5645{
Andreas Färber0429a972013-08-26 18:14:44 +02005646 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5647 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005648 FILE *fp;
5649 char *line = NULL;
5650 size_t len = 0;
5651 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005652
Alexander Graf1a49ef22012-05-01 16:30:28 +01005653 fp = fopen("/proc/self/maps", "r");
5654 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005655 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005656 }
5657
5658 while ((read = getline(&line, &len, fp)) != -1) {
5659 int fields, dev_maj, dev_min, inode;
5660 uint64_t min, max, offset;
5661 char flag_r, flag_w, flag_x, flag_p;
5662 char path[512] = "";
5663 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5664 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5665 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5666
5667 if ((fields < 10) || (fields > 11)) {
5668 continue;
5669 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005670 if (h2g_valid(min)) {
5671 int flags = page_get_flags(h2g(min));
5672 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5673 if (page_check_range(h2g(min), max - min, flags) == -1) {
5674 continue;
5675 }
5676 if (h2g(min) == ts->info->stack_limit) {
5677 pstrcpy(path, sizeof(path), " [stack]");
5678 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005679 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005680 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005681 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005682 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005683 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005684 }
5685 }
5686
5687 free(line);
5688 fclose(fp);
5689
Alexander Graf36c08d42011-11-02 20:23:24 +01005690 return 0;
5691}
5692
Alexander Graf480b8e72011-11-02 20:23:25 +01005693static int open_self_stat(void *cpu_env, int fd)
5694{
Andreas Färber0429a972013-08-26 18:14:44 +02005695 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5696 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005697 abi_ulong start_stack = ts->info->start_stack;
5698 int i;
5699
5700 for (i = 0; i < 44; i++) {
5701 char buf[128];
5702 int len;
5703 uint64_t val = 0;
5704
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005705 if (i == 0) {
5706 /* pid */
5707 val = getpid();
5708 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5709 } else if (i == 1) {
5710 /* app name */
5711 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5712 } else if (i == 27) {
5713 /* stack bottom */
5714 val = start_stack;
5715 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5716 } else {
5717 /* for the rest, there is MasterCard */
5718 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005719 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005720
Alexander Graf480b8e72011-11-02 20:23:25 +01005721 len = strlen(buf);
5722 if (write(fd, buf, len) != len) {
5723 return -1;
5724 }
5725 }
5726
5727 return 0;
5728}
5729
Alexander Graf257450e2011-11-02 20:23:26 +01005730static int open_self_auxv(void *cpu_env, int fd)
5731{
Andreas Färber0429a972013-08-26 18:14:44 +02005732 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5733 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005734 abi_ulong auxv = ts->info->saved_auxv;
5735 abi_ulong len = ts->info->auxv_len;
5736 char *ptr;
5737
5738 /*
5739 * Auxiliary vector is stored in target process stack.
5740 * read in whole auxv vector and copy it to file
5741 */
5742 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5743 if (ptr != NULL) {
5744 while (len > 0) {
5745 ssize_t r;
5746 r = write(fd, ptr, len);
5747 if (r <= 0) {
5748 break;
5749 }
5750 len -= r;
5751 ptr += r;
5752 }
5753 lseek(fd, 0, SEEK_SET);
5754 unlock_user(ptr, auxv, len);
5755 }
5756
5757 return 0;
5758}
5759
Andreas Schwab463d8e72013-07-02 14:04:12 +01005760static int is_proc_myself(const char *filename, const char *entry)
5761{
5762 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5763 filename += strlen("/proc/");
5764 if (!strncmp(filename, "self/", strlen("self/"))) {
5765 filename += strlen("self/");
5766 } else if (*filename >= '1' && *filename <= '9') {
5767 char myself[80];
5768 snprintf(myself, sizeof(myself), "%d/", getpid());
5769 if (!strncmp(filename, myself, strlen(myself))) {
5770 filename += strlen(myself);
5771 } else {
5772 return 0;
5773 }
5774 } else {
5775 return 0;
5776 }
5777 if (!strcmp(filename, entry)) {
5778 return 1;
5779 }
5780 }
5781 return 0;
5782}
5783
Laurent Vivierde6b9932013-08-30 01:46:40 +02005784#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5785static int is_proc(const char *filename, const char *entry)
5786{
5787 return strcmp(filename, entry) == 0;
5788}
5789
5790static int open_net_route(void *cpu_env, int fd)
5791{
5792 FILE *fp;
5793 char *line = NULL;
5794 size_t len = 0;
5795 ssize_t read;
5796
5797 fp = fopen("/proc/net/route", "r");
5798 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005799 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02005800 }
5801
5802 /* read header */
5803
5804 read = getline(&line, &len, fp);
5805 dprintf(fd, "%s", line);
5806
5807 /* read routes */
5808
5809 while ((read = getline(&line, &len, fp)) != -1) {
5810 char iface[16];
5811 uint32_t dest, gw, mask;
5812 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5813 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5814 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5815 &mask, &mtu, &window, &irtt);
5816 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5817 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5818 metric, tswap32(mask), mtu, window, irtt);
5819 }
5820
5821 free(line);
5822 fclose(fp);
5823
5824 return 0;
5825}
5826#endif
5827
Riku Voipio0b2effd2014-08-06 10:36:37 +03005828static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005829{
5830 struct fake_open {
5831 const char *filename;
5832 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005833 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005834 };
5835 const struct fake_open *fake_open;
5836 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005837 { "maps", open_self_maps, is_proc_myself },
5838 { "stat", open_self_stat, is_proc_myself },
5839 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005840 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005841#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5842 { "/proc/net/route", open_net_route, is_proc },
5843#endif
5844 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005845 };
5846
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005847 if (is_proc_myself(pathname, "exe")) {
5848 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01005849 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005850 }
5851
Alexander Graf3be14d02011-11-02 20:23:23 +01005852 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005853 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005854 break;
5855 }
5856 }
5857
5858 if (fake_open->filename) {
5859 const char *tmpdir;
5860 char filename[PATH_MAX];
5861 int fd, r;
5862
5863 /* create temporary file to map stat to */
5864 tmpdir = getenv("TMPDIR");
5865 if (!tmpdir)
5866 tmpdir = "/tmp";
5867 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5868 fd = mkstemp(filename);
5869 if (fd < 0) {
5870 return fd;
5871 }
5872 unlink(filename);
5873
5874 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005875 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01005876 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01005877 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01005878 return r;
5879 }
5880 lseek(fd, 0, SEEK_SET);
5881
5882 return fd;
5883 }
5884
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01005885 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01005886}
5887
Alexander Grafaecc8862014-11-10 21:33:03 +01005888#define TIMER_MAGIC 0x0caf0000
5889#define TIMER_MAGIC_MASK 0xffff0000
5890
5891/* Convert QEMU provided timer ID back to internal 16bit index format */
5892static target_timer_t get_timer_id(abi_long arg)
5893{
5894 target_timer_t timerid = arg;
5895
5896 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
5897 return -TARGET_EINVAL;
5898 }
5899
5900 timerid &= 0xffff;
5901
5902 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
5903 return -TARGET_EINVAL;
5904 }
5905
5906 return timerid;
5907}
5908
ths0da46a62007-10-20 20:23:07 +00005909/* do_syscall() should always have a single exit point at the end so
5910 that actions, such as logging of syscall results, can be performed.
5911 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005912abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5913 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005914 abi_long arg5, abi_long arg6, abi_long arg7,
5915 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005916{
Andreas Färber182735e2013-05-29 22:29:20 +02005917 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005918 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005919 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005920 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005921 void *p;
ths3b46e622007-09-17 08:09:54 +00005922
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01005923#if defined(DEBUG_ERESTARTSYS)
5924 /* Debug-only code for exercising the syscall-restart code paths
5925 * in the per-architecture cpu main loops: restart every syscall
5926 * the guest makes once before letting it through.
5927 */
5928 {
5929 static int flag;
5930
5931 flag = !flag;
5932 if (flag) {
5933 return -TARGET_ERESTARTSYS;
5934 }
5935 }
5936#endif
5937
bellard72f03902003-02-18 23:33:18 +00005938#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005939 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005940#endif
thsb92c47c2007-11-01 00:07:38 +00005941 if(do_strace)
5942 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5943
bellard31e31b82003-02-18 22:55:36 +00005944 switch(num) {
5945 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005946 /* In old applications this may be used to implement _exit(2).
5947 However in threaded applictions it is used for thread termination,
5948 and _exit_group is used for application termination.
5949 Do thread termination if we have more then one thread. */
5950 /* FIXME: This probably breaks if a signal arrives. We should probably
5951 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005952 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005953 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005954
Andreas Färber9b056fc2013-06-24 23:53:10 +02005955 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005956 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005957 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005958 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005959 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005960 if (ts->child_tidptr) {
5961 put_user_u32(0, ts->child_tidptr);
5962 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5963 NULL, NULL, 0);
5964 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005965 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005966 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005967 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04005968 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005969 pthread_exit(NULL);
5970 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005971#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005972 _mcleanup();
5973#endif
bellarde9009672005-04-26 20:42:36 +00005974 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005975 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005976 ret = 0; /* avoid warning */
5977 break;
5978 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005979 if (arg3 == 0)
5980 ret = 0;
5981 else {
5982 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5983 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01005984 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005985 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005986 fd_trans_host_to_target_data(arg1)) {
5987 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02005988 }
aurel3238d840e2009-01-30 19:48:17 +00005989 unlock_user(p, arg2, ret);
5990 }
bellard31e31b82003-02-18 22:55:36 +00005991 break;
5992 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005993 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5994 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01005995 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00005996 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005997 break;
Chen Gang704eff62015-08-21 05:37:33 +08005998#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00005999 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006000 if (!(p = lock_user_string(arg1)))
6001 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006002 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6003 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6004 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006005 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006006 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006007 break;
Chen Gang704eff62015-08-21 05:37:33 +08006008#endif
ths82424832007-09-24 09:21:55 +00006009 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006010 if (!(p = lock_user_string(arg2)))
6011 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006012 ret = get_errno(do_openat(cpu_env, arg1, p,
6013 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6014 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006015 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006016 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006017 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006018#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6019 case TARGET_NR_name_to_handle_at:
6020 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6021 break;
6022#endif
6023#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6024 case TARGET_NR_open_by_handle_at:
6025 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006026 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006027 break;
6028#endif
bellard31e31b82003-02-18 22:55:36 +00006029 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006030 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006031 ret = get_errno(close(arg1));
6032 break;
6033 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006034 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006035 break;
Chen Gang704eff62015-08-21 05:37:33 +08006036#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006037 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006038 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006039 break;
Chen Gang704eff62015-08-21 05:37:33 +08006040#endif
thse5febef2007-04-01 18:31:35 +00006041#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006042 case TARGET_NR_waitpid:
6043 {
pbrook53a59602006-03-25 19:31:22 +00006044 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006045 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006046 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006047 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006048 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006049 }
6050 break;
thse5febef2007-04-01 18:31:35 +00006051#endif
pbrookf0cbb612008-05-30 18:20:05 +00006052#ifdef TARGET_NR_waitid
6053 case TARGET_NR_waitid:
6054 {
6055 siginfo_t info;
6056 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006057 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006058 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006059 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006060 goto efault;
6061 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006062 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006063 }
6064 }
6065 break;
6066#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006067#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006068 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006069 if (!(p = lock_user_string(arg1)))
6070 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006071 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006072 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006073 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006074 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006075#endif
Chen Gang704eff62015-08-21 05:37:33 +08006076#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006077 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006078 {
6079 void * p2;
6080 p = lock_user_string(arg1);
6081 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006082 if (!p || !p2)
6083 ret = -TARGET_EFAULT;
6084 else
6085 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006086 unlock_user(p2, arg2, 0);
6087 unlock_user(p, arg1, 0);
6088 }
bellard31e31b82003-02-18 22:55:36 +00006089 break;
Chen Gang704eff62015-08-21 05:37:33 +08006090#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006091#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006092 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006093 {
6094 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006095 if (!arg2 || !arg4)
6096 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006097 p = lock_user_string(arg2);
6098 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006099 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006100 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006101 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006102 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006103 unlock_user(p, arg2, 0);
6104 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006105 }
6106 break;
6107#endif
Chen Gang704eff62015-08-21 05:37:33 +08006108#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006109 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006110 if (!(p = lock_user_string(arg1)))
6111 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006112 ret = get_errno(unlink(p));
6113 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006114 break;
Chen Gang704eff62015-08-21 05:37:33 +08006115#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006116#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006117 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006118 if (!(p = lock_user_string(arg2)))
6119 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006120 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006121 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006122 break;
balrogb7d35e62007-12-12 00:40:24 +00006123#endif
bellard31e31b82003-02-18 22:55:36 +00006124 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006125 {
6126 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006127 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006128 abi_ulong gp;
6129 abi_ulong guest_argp;
6130 abi_ulong guest_envp;
6131 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006132 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006133 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006134
bellardf7341ff2003-03-30 21:00:25 +00006135 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006136 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006137 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006138 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006139 goto efault;
ths03aa1972007-12-02 06:28:08 +00006140 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006141 break;
bellard7854b052003-03-29 17:22:23 +00006142 argc++;
bellard2f619692007-11-16 10:46:05 +00006143 }
bellardf7341ff2003-03-30 21:00:25 +00006144 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006145 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006146 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006147 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006148 goto efault;
ths03aa1972007-12-02 06:28:08 +00006149 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006150 break;
bellard7854b052003-03-29 17:22:23 +00006151 envc++;
bellard2f619692007-11-16 10:46:05 +00006152 }
bellard7854b052003-03-29 17:22:23 +00006153
bellardf7341ff2003-03-30 21:00:25 +00006154 argp = alloca((argc + 1) * sizeof(void *));
6155 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006156
pbrookda94d262008-05-30 18:24:00 +00006157 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006158 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006159 if (get_user_ual(addr, gp))
6160 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006161 if (!addr)
6162 break;
bellard2f619692007-11-16 10:46:05 +00006163 if (!(*q = lock_user_string(addr)))
6164 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006165 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006166 }
bellardf7341ff2003-03-30 21:00:25 +00006167 *q = NULL;
6168
pbrookda94d262008-05-30 18:24:00 +00006169 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006170 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006171 if (get_user_ual(addr, gp))
6172 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006173 if (!addr)
6174 break;
bellard2f619692007-11-16 10:46:05 +00006175 if (!(*q = lock_user_string(addr)))
6176 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006177 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006178 }
bellardf7341ff2003-03-30 21:00:25 +00006179 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006180
bellard2f619692007-11-16 10:46:05 +00006181 if (!(p = lock_user_string(arg1)))
6182 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01006183 /* Although execve() is not an interruptible syscall it is
6184 * a special case where we must use the safe_syscall wrapper:
6185 * if we allow a signal to happen before we make the host
6186 * syscall then we will 'lose' it, because at the point of
6187 * execve the process leaves QEMU's control. So we use the
6188 * safe syscall wrapper to ensure that we either take the
6189 * signal as a guest signal, or else it does not happen
6190 * before the execve completes and makes it the other
6191 * program's problem.
6192 */
6193 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00006194 unlock_user(p, arg1, 0);
6195
bellard2f619692007-11-16 10:46:05 +00006196 goto execve_end;
6197
6198 execve_efault:
6199 ret = -TARGET_EFAULT;
6200
6201 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006202 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006203 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006204 if (get_user_ual(addr, gp)
6205 || !addr)
6206 break;
pbrook53a59602006-03-25 19:31:22 +00006207 unlock_user(*q, addr, 0);
6208 }
6209 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006210 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006211 if (get_user_ual(addr, gp)
6212 || !addr)
6213 break;
pbrook53a59602006-03-25 19:31:22 +00006214 unlock_user(*q, addr, 0);
6215 }
bellard7854b052003-03-29 17:22:23 +00006216 }
bellard31e31b82003-02-18 22:55:36 +00006217 break;
6218 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006219 if (!(p = lock_user_string(arg1)))
6220 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006221 ret = get_errno(chdir(p));
6222 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006223 break;
bellarda315a142005-01-30 22:59:18 +00006224#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006225 case TARGET_NR_time:
6226 {
pbrook53a59602006-03-25 19:31:22 +00006227 time_t host_time;
6228 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006229 if (!is_error(ret)
6230 && arg1
6231 && put_user_sal(host_time, arg1))
6232 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006233 }
6234 break;
bellarda315a142005-01-30 22:59:18 +00006235#endif
Chen Gang704eff62015-08-21 05:37:33 +08006236#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006237 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006238 if (!(p = lock_user_string(arg1)))
6239 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006240 ret = get_errno(mknod(p, arg2, arg3));
6241 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006242 break;
Chen Gang704eff62015-08-21 05:37:33 +08006243#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006244#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006245 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006246 if (!(p = lock_user_string(arg2)))
6247 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006248 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00006249 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00006250 break;
6251#endif
Chen Gang704eff62015-08-21 05:37:33 +08006252#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00006253 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00006254 if (!(p = lock_user_string(arg1)))
6255 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006256 ret = get_errno(chmod(p, arg2));
6257 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006258 break;
Chen Gang704eff62015-08-21 05:37:33 +08006259#endif
bellardebc05482003-09-30 21:08:41 +00006260#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00006261 case TARGET_NR_break:
6262 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006263#endif
6264#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00006265 case TARGET_NR_oldstat:
6266 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006267#endif
bellard31e31b82003-02-18 22:55:36 +00006268 case TARGET_NR_lseek:
6269 ret = get_errno(lseek(arg1, arg2, arg3));
6270 break;
Richard Henderson92317332010-05-03 10:07:53 -07006271#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
6272 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00006273 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07006274 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00006275 ret = get_errno(getpid());
6276 break;
Richard Henderson92317332010-05-03 10:07:53 -07006277#endif
6278#ifdef TARGET_NR_getpid
6279 case TARGET_NR_getpid:
6280 ret = get_errno(getpid());
6281 break;
6282#endif
bellard31e31b82003-02-18 22:55:36 +00006283 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01006284 {
6285 /* need to look at the data field */
6286 void *p2, *p3;
6287
6288 if (arg1) {
6289 p = lock_user_string(arg1);
6290 if (!p) {
6291 goto efault;
6292 }
6293 } else {
6294 p = NULL;
6295 }
6296
6297 p2 = lock_user_string(arg2);
6298 if (!p2) {
6299 if (arg1) {
6300 unlock_user(p, arg1, 0);
6301 }
6302 goto efault;
6303 }
6304
6305 if (arg3) {
6306 p3 = lock_user_string(arg3);
6307 if (!p3) {
6308 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006309 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01006310 }
6311 unlock_user(p2, arg2, 0);
6312 goto efault;
6313 }
6314 } else {
6315 p3 = NULL;
6316 }
6317
6318 /* FIXME - arg5 should be locked, but it isn't clear how to
6319 * do that since it's not guaranteed to be a NULL-terminated
6320 * string.
6321 */
6322 if (!arg5) {
6323 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
6324 } else {
6325 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
6326 }
6327 ret = get_errno(ret);
6328
6329 if (arg1) {
6330 unlock_user(p, arg1, 0);
6331 }
6332 unlock_user(p2, arg2, 0);
6333 if (arg3) {
6334 unlock_user(p3, arg3, 0);
6335 }
6336 }
6337 break;
thse5febef2007-04-01 18:31:35 +00006338#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00006339 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00006340 if (!(p = lock_user_string(arg1)))
6341 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006342 ret = get_errno(umount(p));
6343 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006344 break;
thse5febef2007-04-01 18:31:35 +00006345#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006346#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006347 case TARGET_NR_stime:
6348 {
pbrook53a59602006-03-25 19:31:22 +00006349 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00006350 if (get_user_sal(host_time, arg1))
6351 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006352 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00006353 }
6354 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006355#endif
bellard31e31b82003-02-18 22:55:36 +00006356 case TARGET_NR_ptrace:
6357 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00006358#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006359 case TARGET_NR_alarm:
6360 ret = alarm(arg1);
6361 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006362#endif
bellardebc05482003-09-30 21:08:41 +00006363#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00006364 case TARGET_NR_oldfstat:
6365 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006366#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006367#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006368 case TARGET_NR_pause:
6369 ret = get_errno(pause());
6370 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006371#endif
thse5febef2007-04-01 18:31:35 +00006372#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00006373 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00006374 {
pbrook53a59602006-03-25 19:31:22 +00006375 struct utimbuf tbuf, *host_tbuf;
6376 struct target_utimbuf *target_tbuf;
6377 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006378 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
6379 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006380 tbuf.actime = tswapal(target_tbuf->actime);
6381 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00006382 unlock_user_struct(target_tbuf, arg2, 0);
6383 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00006384 } else {
pbrook53a59602006-03-25 19:31:22 +00006385 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00006386 }
bellard579a97f2007-11-11 14:26:47 +00006387 if (!(p = lock_user_string(arg1)))
6388 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006389 ret = get_errno(utime(p, host_tbuf));
6390 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00006391 }
6392 break;
thse5febef2007-04-01 18:31:35 +00006393#endif
Chen Gang704eff62015-08-21 05:37:33 +08006394#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00006395 case TARGET_NR_utimes:
6396 {
bellard978a66f2004-12-06 22:58:05 +00006397 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00006398 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00006399 if (copy_from_user_timeval(&tv[0], arg2)
6400 || copy_from_user_timeval(&tv[1],
6401 arg2 + sizeof(struct target_timeval)))
6402 goto efault;
bellard978a66f2004-12-06 22:58:05 +00006403 tvp = tv;
6404 } else {
6405 tvp = NULL;
6406 }
bellard579a97f2007-11-11 14:26:47 +00006407 if (!(p = lock_user_string(arg1)))
6408 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006409 ret = get_errno(utimes(p, tvp));
6410 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00006411 }
6412 break;
Chen Gang704eff62015-08-21 05:37:33 +08006413#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006414#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00006415 case TARGET_NR_futimesat:
6416 {
6417 struct timeval *tvp, tv[2];
6418 if (arg3) {
6419 if (copy_from_user_timeval(&tv[0], arg3)
6420 || copy_from_user_timeval(&tv[1],
6421 arg3 + sizeof(struct target_timeval)))
6422 goto efault;
6423 tvp = tv;
6424 } else {
6425 tvp = NULL;
6426 }
6427 if (!(p = lock_user_string(arg2)))
6428 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006429 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00006430 unlock_user(p, arg2, 0);
6431 }
6432 break;
6433#endif
bellardebc05482003-09-30 21:08:41 +00006434#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00006435 case TARGET_NR_stty:
6436 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006437#endif
6438#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00006439 case TARGET_NR_gtty:
6440 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006441#endif
Chen Gang704eff62015-08-21 05:37:33 +08006442#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00006443 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00006444 if (!(p = lock_user_string(arg1)))
6445 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02006446 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00006447 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006448 break;
Chen Gang704eff62015-08-21 05:37:33 +08006449#endif
ths92a34c12007-09-24 09:27:49 +00006450#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
6451 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00006452 if (!(p = lock_user_string(arg2)))
6453 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006454 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006455 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00006456 break;
6457#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006458#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006459 case TARGET_NR_nice:
6460 ret = get_errno(nice(arg1));
6461 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006462#endif
bellardebc05482003-09-30 21:08:41 +00006463#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00006464 case TARGET_NR_ftime:
6465 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006466#endif
bellard31e31b82003-02-18 22:55:36 +00006467 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00006468 sync();
6469 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00006470 break;
6471 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00006472 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00006473 break;
Chen Gang704eff62015-08-21 05:37:33 +08006474#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00006475 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00006476 {
6477 void *p2;
6478 p = lock_user_string(arg1);
6479 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006480 if (!p || !p2)
6481 ret = -TARGET_EFAULT;
6482 else
6483 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006484 unlock_user(p2, arg2, 0);
6485 unlock_user(p, arg1, 0);
6486 }
bellard31e31b82003-02-18 22:55:36 +00006487 break;
Chen Gang704eff62015-08-21 05:37:33 +08006488#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006489#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006490 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006491 {
bellard579a97f2007-11-11 14:26:47 +00006492 void *p2;
ths722183f2007-09-24 09:24:37 +00006493 p = lock_user_string(arg2);
6494 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006495 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006496 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006497 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006498 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006499 unlock_user(p2, arg4, 0);
6500 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006501 }
6502 break;
6503#endif
Chen Gang704eff62015-08-21 05:37:33 +08006504#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00006505 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006506 if (!(p = lock_user_string(arg1)))
6507 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006508 ret = get_errno(mkdir(p, arg2));
6509 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006510 break;
Chen Gang704eff62015-08-21 05:37:33 +08006511#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006512#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006513 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006514 if (!(p = lock_user_string(arg2)))
6515 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006516 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006517 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006518 break;
6519#endif
Chen Gang704eff62015-08-21 05:37:33 +08006520#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00006521 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006522 if (!(p = lock_user_string(arg1)))
6523 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006524 ret = get_errno(rmdir(p));
6525 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006526 break;
Chen Gang704eff62015-08-21 05:37:33 +08006527#endif
bellard31e31b82003-02-18 22:55:36 +00006528 case TARGET_NR_dup:
6529 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02006530 if (ret >= 0) {
6531 fd_trans_dup(arg1, ret);
6532 }
bellard31e31b82003-02-18 22:55:36 +00006533 break;
Chen Gang704eff62015-08-21 05:37:33 +08006534#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00006535 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006536 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006537 break;
Chen Gang704eff62015-08-21 05:37:33 +08006538#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03006539#ifdef TARGET_NR_pipe2
6540 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006541 ret = do_pipe(cpu_env, arg1,
6542 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006543 break;
6544#endif
bellard31e31b82003-02-18 22:55:36 +00006545 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006546 {
pbrook53a59602006-03-25 19:31:22 +00006547 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006548 struct tms tms;
6549 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006550 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006551 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6552 if (!tmsp)
6553 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006554 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6555 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6556 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6557 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006558 }
bellardc596ed12003-07-13 17:32:31 +00006559 if (!is_error(ret))
6560 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006561 }
6562 break;
bellardebc05482003-09-30 21:08:41 +00006563#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006564 case TARGET_NR_prof:
6565 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006566#endif
thse5febef2007-04-01 18:31:35 +00006567#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006568 case TARGET_NR_signal:
6569 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006570#endif
bellard31e31b82003-02-18 22:55:36 +00006571 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006572 if (arg1 == 0) {
6573 ret = get_errno(acct(NULL));
6574 } else {
6575 if (!(p = lock_user_string(arg1)))
6576 goto efault;
6577 ret = get_errno(acct(path(p)));
6578 unlock_user(p, arg1, 0);
6579 }
pbrook24836682006-04-16 14:14:53 +00006580 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006581#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006582 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006583 if (!(p = lock_user_string(arg1)))
6584 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006585 ret = get_errno(umount2(p, arg2));
6586 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006587 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006588#endif
bellardebc05482003-09-30 21:08:41 +00006589#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006590 case TARGET_NR_lock:
6591 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006592#endif
bellard31e31b82003-02-18 22:55:36 +00006593 case TARGET_NR_ioctl:
6594 ret = do_ioctl(arg1, arg2, arg3);
6595 break;
6596 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006597 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006598 break;
bellardebc05482003-09-30 21:08:41 +00006599#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006600 case TARGET_NR_mpx:
6601 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006602#endif
bellard31e31b82003-02-18 22:55:36 +00006603 case TARGET_NR_setpgid:
6604 ret = get_errno(setpgid(arg1, arg2));
6605 break;
bellardebc05482003-09-30 21:08:41 +00006606#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006607 case TARGET_NR_ulimit:
6608 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006609#endif
6610#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006611 case TARGET_NR_oldolduname:
6612 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006613#endif
bellard31e31b82003-02-18 22:55:36 +00006614 case TARGET_NR_umask:
6615 ret = get_errno(umask(arg1));
6616 break;
6617 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006618 if (!(p = lock_user_string(arg1)))
6619 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006620 ret = get_errno(chroot(p));
6621 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006622 break;
Chen Gang704eff62015-08-21 05:37:33 +08006623#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00006624 case TARGET_NR_ustat:
6625 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08006626#endif
6627#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00006628 case TARGET_NR_dup2:
6629 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006630 if (ret >= 0) {
6631 fd_trans_dup(arg1, arg2);
6632 }
bellard31e31b82003-02-18 22:55:36 +00006633 break;
Chen Gang704eff62015-08-21 05:37:33 +08006634#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03006635#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6636 case TARGET_NR_dup3:
6637 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006638 if (ret >= 0) {
6639 fd_trans_dup(arg1, arg2);
6640 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03006641 break;
6642#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006643#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006644 case TARGET_NR_getppid:
6645 ret = get_errno(getppid());
6646 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006647#endif
Chen Gang704eff62015-08-21 05:37:33 +08006648#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00006649 case TARGET_NR_getpgrp:
6650 ret = get_errno(getpgrp());
6651 break;
Chen Gang704eff62015-08-21 05:37:33 +08006652#endif
bellard31e31b82003-02-18 22:55:36 +00006653 case TARGET_NR_setsid:
6654 ret = get_errno(setsid());
6655 break;
thse5febef2007-04-01 18:31:35 +00006656#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006657 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006658 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006659#if defined(TARGET_ALPHA)
6660 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006661 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006662 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006663 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6664 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006665 act._sa_handler = old_act->_sa_handler;
6666 target_siginitset(&act.sa_mask, old_act->sa_mask);
6667 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006668 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006669 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006670 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006671 }
6672 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006673 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006674 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6675 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006676 old_act->_sa_handler = oact._sa_handler;
6677 old_act->sa_mask = oact.sa_mask.sig[0];
6678 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006679 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006680 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006681#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006682 struct target_sigaction act, oact, *pact, *old_act;
6683
6684 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006685 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6686 goto efault;
bellard106ec872006-06-27 21:08:10 +00006687 act._sa_handler = old_act->_sa_handler;
6688 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6689 act.sa_flags = old_act->sa_flags;
6690 unlock_user_struct(old_act, arg2, 0);
6691 pact = &act;
6692 } else {
6693 pact = NULL;
6694 }
6695
6696 ret = get_errno(do_sigaction(arg1, pact, &oact));
6697
6698 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006699 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6700 goto efault;
bellard106ec872006-06-27 21:08:10 +00006701 old_act->_sa_handler = oact._sa_handler;
6702 old_act->sa_flags = oact.sa_flags;
6703 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6704 old_act->sa_mask.sig[1] = 0;
6705 old_act->sa_mask.sig[2] = 0;
6706 old_act->sa_mask.sig[3] = 0;
6707 unlock_user_struct(old_act, arg3, 1);
6708 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006709#else
6710 struct target_old_sigaction *old_act;
6711 struct target_sigaction act, oact, *pact;
6712 if (arg2) {
6713 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6714 goto efault;
6715 act._sa_handler = old_act->_sa_handler;
6716 target_siginitset(&act.sa_mask, old_act->sa_mask);
6717 act.sa_flags = old_act->sa_flags;
6718 act.sa_restorer = old_act->sa_restorer;
6719 unlock_user_struct(old_act, arg2, 0);
6720 pact = &act;
6721 } else {
6722 pact = NULL;
6723 }
6724 ret = get_errno(do_sigaction(arg1, pact, &oact));
6725 if (!is_error(ret) && arg3) {
6726 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6727 goto efault;
6728 old_act->_sa_handler = oact._sa_handler;
6729 old_act->sa_mask = oact.sa_mask.sig[0];
6730 old_act->sa_flags = oact.sa_flags;
6731 old_act->sa_restorer = oact.sa_restorer;
6732 unlock_user_struct(old_act, arg3, 1);
6733 }
ths388bb212007-05-13 13:58:00 +00006734#endif
bellard31e31b82003-02-18 22:55:36 +00006735 }
6736 break;
thse5febef2007-04-01 18:31:35 +00006737#endif
bellard66fb9762003-03-23 01:06:05 +00006738 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006739 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006740#if defined(TARGET_ALPHA)
6741 struct target_sigaction act, oact, *pact = 0;
6742 struct target_rt_sigaction *rt_act;
6743 /* ??? arg4 == sizeof(sigset_t). */
6744 if (arg2) {
6745 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6746 goto efault;
6747 act._sa_handler = rt_act->_sa_handler;
6748 act.sa_mask = rt_act->sa_mask;
6749 act.sa_flags = rt_act->sa_flags;
6750 act.sa_restorer = arg5;
6751 unlock_user_struct(rt_act, arg2, 0);
6752 pact = &act;
6753 }
6754 ret = get_errno(do_sigaction(arg1, pact, &oact));
6755 if (!is_error(ret) && arg3) {
6756 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6757 goto efault;
6758 rt_act->_sa_handler = oact._sa_handler;
6759 rt_act->sa_mask = oact.sa_mask;
6760 rt_act->sa_flags = oact.sa_flags;
6761 unlock_user_struct(rt_act, arg3, 1);
6762 }
6763#else
pbrook53a59602006-03-25 19:31:22 +00006764 struct target_sigaction *act;
6765 struct target_sigaction *oact;
6766
bellard579a97f2007-11-11 14:26:47 +00006767 if (arg2) {
6768 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6769 goto efault;
6770 } else
pbrook53a59602006-03-25 19:31:22 +00006771 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006772 if (arg3) {
6773 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6774 ret = -TARGET_EFAULT;
6775 goto rt_sigaction_fail;
6776 }
6777 } else
pbrook53a59602006-03-25 19:31:22 +00006778 oact = NULL;
6779 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006780 rt_sigaction_fail:
6781 if (act)
pbrook53a59602006-03-25 19:31:22 +00006782 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006783 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006784 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006785#endif
pbrook53a59602006-03-25 19:31:22 +00006786 }
bellard66fb9762003-03-23 01:06:05 +00006787 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006788#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006789 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006790 {
6791 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006792 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006793 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006794 host_to_target_old_sigset(&target_set, &cur_set);
6795 ret = target_set;
6796 }
6797 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006798#endif
6799#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006800 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006801 {
6802 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006803 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006804 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006805 target_to_host_old_sigset(&set, &target_set);
6806 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006807 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006808 host_to_target_old_sigset(&target_set, &oset);
6809 ret = target_set;
6810 }
6811 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006812#endif
thse5febef2007-04-01 18:31:35 +00006813#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006814 case TARGET_NR_sigprocmask:
6815 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006816#if defined(TARGET_ALPHA)
6817 sigset_t set, oldset;
6818 abi_ulong mask;
6819 int how;
6820
6821 switch (arg1) {
6822 case TARGET_SIG_BLOCK:
6823 how = SIG_BLOCK;
6824 break;
6825 case TARGET_SIG_UNBLOCK:
6826 how = SIG_UNBLOCK;
6827 break;
6828 case TARGET_SIG_SETMASK:
6829 how = SIG_SETMASK;
6830 break;
6831 default:
6832 ret = -TARGET_EINVAL;
6833 goto fail;
6834 }
6835 mask = arg2;
6836 target_to_host_old_sigset(&set, &mask);
6837
Alex Barcelo1c275922014-03-14 14:36:55 +00006838 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006839 if (!is_error(ret)) {
6840 host_to_target_old_sigset(&mask, &oldset);
6841 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006842 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006843 }
6844#else
bellard66fb9762003-03-23 01:06:05 +00006845 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006846 int how;
ths3b46e622007-09-17 08:09:54 +00006847
pbrook53a59602006-03-25 19:31:22 +00006848 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006849 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006850 case TARGET_SIG_BLOCK:
6851 how = SIG_BLOCK;
6852 break;
6853 case TARGET_SIG_UNBLOCK:
6854 how = SIG_UNBLOCK;
6855 break;
6856 case TARGET_SIG_SETMASK:
6857 how = SIG_SETMASK;
6858 break;
6859 default:
ths0da46a62007-10-20 20:23:07 +00006860 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006861 goto fail;
6862 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006863 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006864 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006865 target_to_host_old_sigset(&set, p);
6866 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006867 set_ptr = &set;
6868 } else {
6869 how = 0;
6870 set_ptr = NULL;
6871 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006872 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006873 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006874 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006875 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006876 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006877 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006878 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006879#endif
bellard66fb9762003-03-23 01:06:05 +00006880 }
6881 break;
thse5febef2007-04-01 18:31:35 +00006882#endif
bellard66fb9762003-03-23 01:06:05 +00006883 case TARGET_NR_rt_sigprocmask:
6884 {
6885 int how = arg1;
6886 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006887
pbrook53a59602006-03-25 19:31:22 +00006888 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006889 switch(how) {
6890 case TARGET_SIG_BLOCK:
6891 how = SIG_BLOCK;
6892 break;
6893 case TARGET_SIG_UNBLOCK:
6894 how = SIG_UNBLOCK;
6895 break;
6896 case TARGET_SIG_SETMASK:
6897 how = SIG_SETMASK;
6898 break;
6899 default:
ths0da46a62007-10-20 20:23:07 +00006900 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006901 goto fail;
6902 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006903 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006904 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006905 target_to_host_sigset(&set, p);
6906 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006907 set_ptr = &set;
6908 } else {
6909 how = 0;
6910 set_ptr = NULL;
6911 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006912 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006913 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006914 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006915 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006916 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006917 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006918 }
6919 }
6920 break;
thse5febef2007-04-01 18:31:35 +00006921#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006922 case TARGET_NR_sigpending:
6923 {
6924 sigset_t set;
6925 ret = get_errno(sigpending(&set));
6926 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006927 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006928 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006929 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006930 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006931 }
6932 }
6933 break;
thse5febef2007-04-01 18:31:35 +00006934#endif
bellard66fb9762003-03-23 01:06:05 +00006935 case TARGET_NR_rt_sigpending:
6936 {
6937 sigset_t set;
6938 ret = get_errno(sigpending(&set));
6939 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006940 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006941 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006942 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006943 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006944 }
6945 }
6946 break;
thse5febef2007-04-01 18:31:35 +00006947#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006948 case TARGET_NR_sigsuspend:
6949 {
6950 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006951#if defined(TARGET_ALPHA)
6952 abi_ulong mask = arg1;
6953 target_to_host_old_sigset(&set, &mask);
6954#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006955 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006956 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006957 target_to_host_old_sigset(&set, p);
6958 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006959#endif
bellard66fb9762003-03-23 01:06:05 +00006960 ret = get_errno(sigsuspend(&set));
6961 }
6962 break;
thse5febef2007-04-01 18:31:35 +00006963#endif
bellard66fb9762003-03-23 01:06:05 +00006964 case TARGET_NR_rt_sigsuspend:
6965 {
6966 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006967 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006968 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006969 target_to_host_sigset(&set, p);
6970 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006971 ret = get_errno(sigsuspend(&set));
6972 }
6973 break;
6974 case TARGET_NR_rt_sigtimedwait:
6975 {
bellard66fb9762003-03-23 01:06:05 +00006976 sigset_t set;
6977 struct timespec uts, *puts;
6978 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006979
Anthony Liguoric227f092009-10-01 16:12:16 -05006980 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006981 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006982 target_to_host_sigset(&set, p);
6983 unlock_user(p, arg1, 0);
6984 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006985 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006986 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006987 } else {
6988 puts = NULL;
6989 }
6990 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006991 if (!is_error(ret)) {
6992 if (arg2) {
6993 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6994 0);
6995 if (!p) {
6996 goto efault;
6997 }
6998 host_to_target_siginfo(p, &uinfo);
6999 unlock_user(p, arg2, sizeof(target_siginfo_t));
7000 }
7001 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007002 }
7003 }
7004 break;
7005 case TARGET_NR_rt_sigqueueinfo:
7006 {
7007 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05007008 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007009 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007010 target_to_host_siginfo(&uinfo, p);
7011 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007012 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7013 }
7014 break;
thse5febef2007-04-01 18:31:35 +00007015#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007016 case TARGET_NR_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007017 ret = do_sigreturn(cpu_env);
7018 break;
thse5febef2007-04-01 18:31:35 +00007019#endif
bellard66fb9762003-03-23 01:06:05 +00007020 case TARGET_NR_rt_sigreturn:
bellard66fb9762003-03-23 01:06:05 +00007021 ret = do_rt_sigreturn(cpu_env);
7022 break;
bellard31e31b82003-02-18 22:55:36 +00007023 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007024 if (!(p = lock_user_string(arg1)))
7025 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007026 ret = get_errno(sethostname(p, arg2));
7027 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007028 break;
7029 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007030 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007031 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007032 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007033 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007034 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7035 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007036 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7037 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007038 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007039 ret = get_errno(setrlimit(resource, &rlim));
7040 }
7041 break;
bellard31e31b82003-02-18 22:55:36 +00007042 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007043 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007044 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007045 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007046 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007047
bellard9de5e442003-03-23 16:49:39 +00007048 ret = get_errno(getrlimit(resource, &rlim));
7049 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007050 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7051 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007052 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7053 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007054 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007055 }
7056 }
7057 break;
bellard31e31b82003-02-18 22:55:36 +00007058 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007059 {
7060 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007061 ret = get_errno(getrusage(arg1, &rusage));
7062 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007063 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007064 }
7065 }
7066 break;
bellard31e31b82003-02-18 22:55:36 +00007067 case TARGET_NR_gettimeofday:
7068 {
bellard31e31b82003-02-18 22:55:36 +00007069 struct timeval tv;
7070 ret = get_errno(gettimeofday(&tv, NULL));
7071 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007072 if (copy_to_user_timeval(arg1, &tv))
7073 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007074 }
7075 }
7076 break;
7077 case TARGET_NR_settimeofday:
7078 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007079 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007080 struct timezone tz, *ptz = NULL;
7081
Paul Burtonb67d8032014-06-22 11:25:41 +01007082 if (arg1) {
7083 if (copy_from_user_timeval(&tv, arg1)) {
7084 goto efault;
7085 }
7086 ptv = &tv;
7087 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007088
7089 if (arg2) {
7090 if (copy_from_user_timezone(&tz, arg2)) {
7091 goto efault;
7092 }
7093 ptz = &tz;
7094 }
7095
Paul Burtonb67d8032014-06-22 11:25:41 +01007096 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007097 }
7098 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007099#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007100 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007101#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7102 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7103#else
bellardf2674e32003-07-09 12:26:09 +00007104 {
pbrook53a59602006-03-25 19:31:22 +00007105 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007106 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007107 long nsel;
7108
bellard579a97f2007-11-11 14:26:47 +00007109 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7110 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007111 nsel = tswapal(sel->n);
7112 inp = tswapal(sel->inp);
7113 outp = tswapal(sel->outp);
7114 exp = tswapal(sel->exp);
7115 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007116 unlock_user_struct(sel, arg1, 0);
7117 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007118 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007119#endif
bellardf2674e32003-07-09 12:26:09 +00007120 break;
bellard048f6b42005-11-26 18:47:20 +00007121#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007122#ifdef TARGET_NR_pselect6
7123 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007124 {
7125 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7126 fd_set rfds, wfds, efds;
7127 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7128 struct timespec ts, *ts_ptr;
7129
7130 /*
7131 * The 6th arg is actually two args smashed together,
7132 * so we cannot use the C library.
7133 */
7134 sigset_t set;
7135 struct {
7136 sigset_t *set;
7137 size_t size;
7138 } sig, *sig_ptr;
7139
7140 abi_ulong arg_sigset, arg_sigsize, *arg7;
7141 target_sigset_t *target_sigset;
7142
7143 n = arg1;
7144 rfd_addr = arg2;
7145 wfd_addr = arg3;
7146 efd_addr = arg4;
7147 ts_addr = arg5;
7148
7149 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7150 if (ret) {
7151 goto fail;
7152 }
7153 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7154 if (ret) {
7155 goto fail;
7156 }
7157 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7158 if (ret) {
7159 goto fail;
7160 }
7161
7162 /*
7163 * This takes a timespec, and not a timeval, so we cannot
7164 * use the do_select() helper ...
7165 */
7166 if (ts_addr) {
7167 if (target_to_host_timespec(&ts, ts_addr)) {
7168 goto efault;
7169 }
7170 ts_ptr = &ts;
7171 } else {
7172 ts_ptr = NULL;
7173 }
7174
7175 /* Extract the two packed args for the sigset */
7176 if (arg6) {
7177 sig_ptr = &sig;
7178 sig.size = _NSIG / 8;
7179
7180 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7181 if (!arg7) {
7182 goto efault;
7183 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007184 arg_sigset = tswapal(arg7[0]);
7185 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007186 unlock_user(arg7, arg6, 0);
7187
7188 if (arg_sigset) {
7189 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007190 if (arg_sigsize != sizeof(*target_sigset)) {
7191 /* Like the kernel, we enforce correct size sigsets */
7192 ret = -TARGET_EINVAL;
7193 goto fail;
7194 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007195 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7196 sizeof(*target_sigset), 1);
7197 if (!target_sigset) {
7198 goto efault;
7199 }
7200 target_to_host_sigset(&set, target_sigset);
7201 unlock_user(target_sigset, arg_sigset, 0);
7202 } else {
7203 sig.set = NULL;
7204 }
7205 } else {
7206 sig_ptr = NULL;
7207 }
7208
7209 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7210 ts_ptr, sig_ptr));
7211
7212 if (!is_error(ret)) {
7213 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7214 goto efault;
7215 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7216 goto efault;
7217 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7218 goto efault;
7219
7220 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
7221 goto efault;
7222 }
7223 }
7224 break;
Riku Voipio9e423822010-05-07 12:28:05 +00007225#endif
Chen Gang704eff62015-08-21 05:37:33 +08007226#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00007227 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00007228 {
7229 void *p2;
7230 p = lock_user_string(arg1);
7231 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007232 if (!p || !p2)
7233 ret = -TARGET_EFAULT;
7234 else
7235 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007236 unlock_user(p2, arg2, 0);
7237 unlock_user(p, arg1, 0);
7238 }
bellard31e31b82003-02-18 22:55:36 +00007239 break;
Chen Gang704eff62015-08-21 05:37:33 +08007240#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007241#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00007242 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00007243 {
bellard579a97f2007-11-11 14:26:47 +00007244 void *p2;
thsf0b62432007-09-24 09:25:40 +00007245 p = lock_user_string(arg1);
7246 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00007247 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007248 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00007249 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007250 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00007251 unlock_user(p2, arg3, 0);
7252 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00007253 }
7254 break;
7255#endif
bellardebc05482003-09-30 21:08:41 +00007256#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00007257 case TARGET_NR_oldlstat:
7258 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007259#endif
Chen Gang704eff62015-08-21 05:37:33 +08007260#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00007261 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00007262 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01007263 void *p2;
pbrook53a59602006-03-25 19:31:22 +00007264 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00007265 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007266 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00007267 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09007268 } else if (!arg3) {
7269 /* Short circuit this for the magic exe check. */
7270 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01007271 } else if (is_proc_myself((const char *)p, "exe")) {
7272 char real[PATH_MAX], *temp;
7273 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09007274 /* Return value is # of bytes that we wrote to the buffer. */
7275 if (temp == NULL) {
7276 ret = get_errno(-1);
7277 } else {
7278 /* Don't worry about sign mismatch as earlier mapping
7279 * logic would have thrown a bad address error. */
7280 ret = MIN(strlen(real), arg3);
7281 /* We cannot NUL terminate the string. */
7282 memcpy(p2, real, ret);
7283 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01007284 } else {
7285 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00007286 }
pbrook53a59602006-03-25 19:31:22 +00007287 unlock_user(p2, arg2, ret);
7288 unlock_user(p, arg1, 0);
7289 }
bellard31e31b82003-02-18 22:55:36 +00007290 break;
Chen Gang704eff62015-08-21 05:37:33 +08007291#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007292#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00007293 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00007294 {
bellard579a97f2007-11-11 14:26:47 +00007295 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00007296 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007297 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007298 if (!p || !p2) {
7299 ret = -TARGET_EFAULT;
7300 } else if (is_proc_myself((const char *)p, "exe")) {
7301 char real[PATH_MAX], *temp;
7302 temp = realpath(exec_path, real);
7303 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
7304 snprintf((char *)p2, arg4, "%s", real);
7305 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01007306 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01007307 }
bellard579a97f2007-11-11 14:26:47 +00007308 unlock_user(p2, arg3, ret);
7309 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00007310 }
7311 break;
7312#endif
thse5febef2007-04-01 18:31:35 +00007313#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00007314 case TARGET_NR_uselib:
7315 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007316#endif
7317#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00007318 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00007319 if (!(p = lock_user_string(arg1)))
7320 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007321 ret = get_errno(swapon(p, arg2));
7322 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007323 break;
thse5febef2007-04-01 18:31:35 +00007324#endif
bellard31e31b82003-02-18 22:55:36 +00007325 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00007326 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
7327 /* arg4 must be ignored in all other cases */
7328 p = lock_user_string(arg4);
7329 if (!p) {
7330 goto efault;
7331 }
7332 ret = get_errno(reboot(arg1, arg2, arg3, p));
7333 unlock_user(p, arg4, 0);
7334 } else {
7335 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
7336 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02007337 break;
thse5febef2007-04-01 18:31:35 +00007338#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00007339 case TARGET_NR_readdir:
7340 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007341#endif
7342#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00007343 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01007344#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7345 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007346 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
7347 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00007348 {
blueswir1992f48a2007-10-14 16:27:31 +00007349 abi_ulong *v;
7350 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00007351 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
7352 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007353 v1 = tswapal(v[0]);
7354 v2 = tswapal(v[1]);
7355 v3 = tswapal(v[2]);
7356 v4 = tswapal(v[3]);
7357 v5 = tswapal(v[4]);
7358 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00007359 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00007360 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00007361 target_to_host_bitmask(v4, mmap_flags_tbl),
7362 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00007363 }
bellard31e31b82003-02-18 22:55:36 +00007364#else
ths5fafdf22007-09-16 21:08:06 +00007365 ret = get_errno(target_mmap(arg1, arg2, arg3,
7366 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00007367 arg5,
7368 arg6));
bellard31e31b82003-02-18 22:55:36 +00007369#endif
bellard6fb883e2003-07-09 17:12:39 +00007370 break;
thse5febef2007-04-01 18:31:35 +00007371#endif
bellarda315a142005-01-30 22:59:18 +00007372#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00007373 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00007374#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00007375#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00007376#endif
ths5fafdf22007-09-16 21:08:06 +00007377 ret = get_errno(target_mmap(arg1, arg2, arg3,
7378 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00007379 arg5,
bellardc573ff62004-01-04 15:51:36 +00007380 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00007381 break;
bellarda315a142005-01-30 22:59:18 +00007382#endif
bellard31e31b82003-02-18 22:55:36 +00007383 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00007384 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007385 break;
bellard9de5e442003-03-23 16:49:39 +00007386 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01007387 {
Andreas Färber0429a972013-08-26 18:14:44 +02007388 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01007389 /* Special hack to detect libc making the stack executable. */
7390 if ((arg3 & PROT_GROWSDOWN)
7391 && arg1 >= ts->info->stack_limit
7392 && arg1 <= ts->info->start_stack) {
7393 arg3 &= ~PROT_GROWSDOWN;
7394 arg2 = arg2 + arg1 - ts->info->stack_limit;
7395 arg1 = ts->info->stack_limit;
7396 }
7397 }
bellard54936002003-05-13 00:25:15 +00007398 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007399 break;
thse5febef2007-04-01 18:31:35 +00007400#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00007401 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00007402 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00007403 break;
thse5febef2007-04-01 18:31:35 +00007404#endif
pbrook53a59602006-03-25 19:31:22 +00007405 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00007406#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00007407 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00007408 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007409 break;
thse5febef2007-04-01 18:31:35 +00007410#endif
7411#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00007412 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00007413 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007414 break;
thse5febef2007-04-01 18:31:35 +00007415#endif
7416#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00007417 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00007418 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007419 break;
thse5febef2007-04-01 18:31:35 +00007420#endif
7421#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00007422 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05007423 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00007424 break;
thse5febef2007-04-01 18:31:35 +00007425#endif
7426#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00007427 case TARGET_NR_munlockall:
7428 ret = get_errno(munlockall());
7429 break;
thse5febef2007-04-01 18:31:35 +00007430#endif
bellard31e31b82003-02-18 22:55:36 +00007431 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00007432 if (!(p = lock_user_string(arg1)))
7433 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007434 ret = get_errno(truncate(p, arg2));
7435 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007436 break;
7437 case TARGET_NR_ftruncate:
7438 ret = get_errno(ftruncate(arg1, arg2));
7439 break;
7440 case TARGET_NR_fchmod:
7441 ret = get_errno(fchmod(arg1, arg2));
7442 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007443#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00007444 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00007445 if (!(p = lock_user_string(arg2)))
7446 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007447 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007448 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00007449 break;
7450#endif
bellard31e31b82003-02-18 22:55:36 +00007451 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07007452 /* Note that negative values are valid for getpriority, so we must
7453 differentiate based on errno settings. */
7454 errno = 0;
7455 ret = getpriority(arg1, arg2);
7456 if (ret == -1 && errno != 0) {
7457 ret = -host_to_target_errno(errno);
7458 break;
7459 }
7460#ifdef TARGET_ALPHA
7461 /* Return value is the unbiased priority. Signal no error. */
7462 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
7463#else
7464 /* Return value is a biased priority to avoid negative numbers. */
7465 ret = 20 - ret;
7466#endif
bellard31e31b82003-02-18 22:55:36 +00007467 break;
7468 case TARGET_NR_setpriority:
7469 ret = get_errno(setpriority(arg1, arg2, arg3));
7470 break;
bellardebc05482003-09-30 21:08:41 +00007471#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00007472 case TARGET_NR_profil:
7473 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007474#endif
bellard31e31b82003-02-18 22:55:36 +00007475 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00007476 if (!(p = lock_user_string(arg1)))
7477 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007478 ret = get_errno(statfs(path(p), &stfs));
7479 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007480 convert_statfs:
7481 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007482 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007483
bellard579a97f2007-11-11 14:26:47 +00007484 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
7485 goto efault;
7486 __put_user(stfs.f_type, &target_stfs->f_type);
7487 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7488 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7489 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7490 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7491 __put_user(stfs.f_files, &target_stfs->f_files);
7492 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7493 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7494 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7495 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007496 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7497 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00007498 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007499 }
7500 break;
7501 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00007502 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00007503 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00007504#ifdef TARGET_NR_statfs64
7505 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00007506 if (!(p = lock_user_string(arg1)))
7507 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007508 ret = get_errno(statfs(path(p), &stfs));
7509 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00007510 convert_statfs64:
7511 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007512 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007513
bellard579a97f2007-11-11 14:26:47 +00007514 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7515 goto efault;
7516 __put_user(stfs.f_type, &target_stfs->f_type);
7517 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7518 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7519 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7520 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7521 __put_user(stfs.f_files, &target_stfs->f_files);
7522 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7523 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7524 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7525 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007526 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7527 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007528 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007529 }
7530 break;
7531 case TARGET_NR_fstatfs64:
7532 ret = get_errno(fstatfs(arg1, &stfs));
7533 goto convert_statfs64;
7534#endif
bellardebc05482003-09-30 21:08:41 +00007535#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007536 case TARGET_NR_ioperm:
7537 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007538#endif
thse5febef2007-04-01 18:31:35 +00007539#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007540 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007541 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007542 break;
thse5febef2007-04-01 18:31:35 +00007543#endif
bellard3532fa72006-06-24 15:06:03 +00007544#ifdef TARGET_NR_accept
7545 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007546 ret = do_accept4(arg1, arg2, arg3, 0);
7547 break;
7548#endif
7549#ifdef TARGET_NR_accept4
7550 case TARGET_NR_accept4:
7551#ifdef CONFIG_ACCEPT4
7552 ret = do_accept4(arg1, arg2, arg3, arg4);
7553#else
7554 goto unimplemented;
7555#endif
bellard3532fa72006-06-24 15:06:03 +00007556 break;
7557#endif
7558#ifdef TARGET_NR_bind
7559 case TARGET_NR_bind:
7560 ret = do_bind(arg1, arg2, arg3);
7561 break;
7562#endif
7563#ifdef TARGET_NR_connect
7564 case TARGET_NR_connect:
7565 ret = do_connect(arg1, arg2, arg3);
7566 break;
7567#endif
7568#ifdef TARGET_NR_getpeername
7569 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007570 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007571 break;
7572#endif
7573#ifdef TARGET_NR_getsockname
7574 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007575 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007576 break;
7577#endif
7578#ifdef TARGET_NR_getsockopt
7579 case TARGET_NR_getsockopt:
7580 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7581 break;
7582#endif
7583#ifdef TARGET_NR_listen
7584 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007585 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007586 break;
7587#endif
7588#ifdef TARGET_NR_recv
7589 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007590 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007591 break;
7592#endif
7593#ifdef TARGET_NR_recvfrom
7594 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007595 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007596 break;
7597#endif
7598#ifdef TARGET_NR_recvmsg
7599 case TARGET_NR_recvmsg:
7600 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7601 break;
7602#endif
7603#ifdef TARGET_NR_send
7604 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007605 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007606 break;
7607#endif
7608#ifdef TARGET_NR_sendmsg
7609 case TARGET_NR_sendmsg:
7610 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7611 break;
7612#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007613#ifdef TARGET_NR_sendmmsg
7614 case TARGET_NR_sendmmsg:
7615 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7616 break;
7617 case TARGET_NR_recvmmsg:
7618 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7619 break;
7620#endif
bellard3532fa72006-06-24 15:06:03 +00007621#ifdef TARGET_NR_sendto
7622 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007623 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007624 break;
7625#endif
7626#ifdef TARGET_NR_shutdown
7627 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007628 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007629 break;
7630#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01007631#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
7632 case TARGET_NR_getrandom:
7633 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
7634 if (!p) {
7635 goto efault;
7636 }
7637 ret = get_errno(getrandom(p, arg2, arg3));
7638 unlock_user(p, arg1, ret);
7639 break;
7640#endif
bellard3532fa72006-06-24 15:06:03 +00007641#ifdef TARGET_NR_socket
7642 case TARGET_NR_socket:
7643 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007644 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00007645 break;
7646#endif
7647#ifdef TARGET_NR_socketpair
7648 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007649 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007650 break;
7651#endif
7652#ifdef TARGET_NR_setsockopt
7653 case TARGET_NR_setsockopt:
7654 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7655 break;
7656#endif
ths7494b0f2007-02-11 18:26:53 +00007657
bellard31e31b82003-02-18 22:55:36 +00007658 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007659 if (!(p = lock_user_string(arg2)))
7660 goto efault;
thse5574482007-02-11 20:03:13 +00007661 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7662 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007663 break;
7664
bellard31e31b82003-02-18 22:55:36 +00007665 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007666 {
bellard66fb9762003-03-23 01:06:05 +00007667 struct itimerval value, ovalue, *pvalue;
7668
pbrook53a59602006-03-25 19:31:22 +00007669 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007670 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007671 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7672 || copy_from_user_timeval(&pvalue->it_value,
7673 arg2 + sizeof(struct target_timeval)))
7674 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007675 } else {
7676 pvalue = NULL;
7677 }
7678 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007679 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007680 if (copy_to_user_timeval(arg3,
7681 &ovalue.it_interval)
7682 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7683 &ovalue.it_value))
7684 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007685 }
7686 }
7687 break;
bellard31e31b82003-02-18 22:55:36 +00007688 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007689 {
bellard66fb9762003-03-23 01:06:05 +00007690 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007691
bellard66fb9762003-03-23 01:06:05 +00007692 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007693 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007694 if (copy_to_user_timeval(arg2,
7695 &value.it_interval)
7696 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7697 &value.it_value))
7698 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007699 }
7700 }
7701 break;
Chen Gang704eff62015-08-21 05:37:33 +08007702#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00007703 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007704 if (!(p = lock_user_string(arg1)))
7705 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007706 ret = get_errno(stat(path(p), &st));
7707 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007708 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007709#endif
7710#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00007711 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007712 if (!(p = lock_user_string(arg1)))
7713 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007714 ret = get_errno(lstat(path(p), &st));
7715 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007716 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007717#endif
bellard31e31b82003-02-18 22:55:36 +00007718 case TARGET_NR_fstat:
7719 {
7720 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08007721#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00007722 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08007723#endif
bellard31e31b82003-02-18 22:55:36 +00007724 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007725 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007726
bellard579a97f2007-11-11 14:26:47 +00007727 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7728 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007729 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007730 __put_user(st.st_dev, &target_st->st_dev);
7731 __put_user(st.st_ino, &target_st->st_ino);
7732 __put_user(st.st_mode, &target_st->st_mode);
7733 __put_user(st.st_uid, &target_st->st_uid);
7734 __put_user(st.st_gid, &target_st->st_gid);
7735 __put_user(st.st_nlink, &target_st->st_nlink);
7736 __put_user(st.st_rdev, &target_st->st_rdev);
7737 __put_user(st.st_size, &target_st->st_size);
7738 __put_user(st.st_blksize, &target_st->st_blksize);
7739 __put_user(st.st_blocks, &target_st->st_blocks);
7740 __put_user(st.st_atime, &target_st->target_st_atime);
7741 __put_user(st.st_mtime, &target_st->target_st_mtime);
7742 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007743 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007744 }
7745 }
7746 break;
bellardebc05482003-09-30 21:08:41 +00007747#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007748 case TARGET_NR_olduname:
7749 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007750#endif
7751#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007752 case TARGET_NR_iopl:
7753 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007754#endif
bellard31e31b82003-02-18 22:55:36 +00007755 case TARGET_NR_vhangup:
7756 ret = get_errno(vhangup());
7757 break;
bellardebc05482003-09-30 21:08:41 +00007758#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007759 case TARGET_NR_idle:
7760 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007761#endif
bellard42ad6ae2005-01-03 22:48:11 +00007762#ifdef TARGET_NR_syscall
7763 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007764 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7765 arg6, arg7, arg8, 0);
7766 break;
bellard42ad6ae2005-01-03 22:48:11 +00007767#endif
bellard31e31b82003-02-18 22:55:36 +00007768 case TARGET_NR_wait4:
7769 {
7770 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007771 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007772 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007773 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007774 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007775 if (target_rusage)
7776 rusage_ptr = &rusage;
7777 else
7778 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007779 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00007780 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007781 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007782 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007783 if (put_user_s32(status, status_ptr))
7784 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007785 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007786 if (target_rusage) {
7787 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7788 if (rusage_err) {
7789 ret = rusage_err;
7790 }
7791 }
bellard31e31b82003-02-18 22:55:36 +00007792 }
7793 }
7794 break;
thse5febef2007-04-01 18:31:35 +00007795#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007796 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007797 if (!(p = lock_user_string(arg1)))
7798 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007799 ret = get_errno(swapoff(p));
7800 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007801 break;
thse5febef2007-04-01 18:31:35 +00007802#endif
bellard31e31b82003-02-18 22:55:36 +00007803 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007804 {
pbrook53a59602006-03-25 19:31:22 +00007805 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007806 struct sysinfo value;
7807 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007808 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007809 {
bellard579a97f2007-11-11 14:26:47 +00007810 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7811 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007812 __put_user(value.uptime, &target_value->uptime);
7813 __put_user(value.loads[0], &target_value->loads[0]);
7814 __put_user(value.loads[1], &target_value->loads[1]);
7815 __put_user(value.loads[2], &target_value->loads[2]);
7816 __put_user(value.totalram, &target_value->totalram);
7817 __put_user(value.freeram, &target_value->freeram);
7818 __put_user(value.sharedram, &target_value->sharedram);
7819 __put_user(value.bufferram, &target_value->bufferram);
7820 __put_user(value.totalswap, &target_value->totalswap);
7821 __put_user(value.freeswap, &target_value->freeswap);
7822 __put_user(value.procs, &target_value->procs);
7823 __put_user(value.totalhigh, &target_value->totalhigh);
7824 __put_user(value.freehigh, &target_value->freehigh);
7825 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007826 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007827 }
7828 }
7829 break;
thse5febef2007-04-01 18:31:35 +00007830#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007831 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007832 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7833 break;
thse5febef2007-04-01 18:31:35 +00007834#endif
aurel32e5289082009-04-18 16:16:12 +00007835#ifdef TARGET_NR_semget
7836 case TARGET_NR_semget:
7837 ret = get_errno(semget(arg1, arg2, arg3));
7838 break;
7839#endif
7840#ifdef TARGET_NR_semop
7841 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007842 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007843 break;
7844#endif
7845#ifdef TARGET_NR_semctl
7846 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01007847 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00007848 break;
7849#endif
aurel32eeb438c2008-10-13 21:08:55 +00007850#ifdef TARGET_NR_msgctl
7851 case TARGET_NR_msgctl:
7852 ret = do_msgctl(arg1, arg2, arg3);
7853 break;
7854#endif
7855#ifdef TARGET_NR_msgget
7856 case TARGET_NR_msgget:
7857 ret = get_errno(msgget(arg1, arg2));
7858 break;
7859#endif
7860#ifdef TARGET_NR_msgrcv
7861 case TARGET_NR_msgrcv:
7862 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7863 break;
7864#endif
7865#ifdef TARGET_NR_msgsnd
7866 case TARGET_NR_msgsnd:
7867 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7868 break;
7869#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007870#ifdef TARGET_NR_shmget
7871 case TARGET_NR_shmget:
7872 ret = get_errno(shmget(arg1, arg2, arg3));
7873 break;
7874#endif
7875#ifdef TARGET_NR_shmctl
7876 case TARGET_NR_shmctl:
7877 ret = do_shmctl(arg1, arg2, arg3);
7878 break;
7879#endif
7880#ifdef TARGET_NR_shmat
7881 case TARGET_NR_shmat:
7882 ret = do_shmat(arg1, arg2, arg3);
7883 break;
7884#endif
7885#ifdef TARGET_NR_shmdt
7886 case TARGET_NR_shmdt:
7887 ret = do_shmdt(arg1);
7888 break;
7889#endif
bellard31e31b82003-02-18 22:55:36 +00007890 case TARGET_NR_fsync:
7891 ret = get_errno(fsync(arg1));
7892 break;
bellard31e31b82003-02-18 22:55:36 +00007893 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007894 /* Linux manages to have three different orderings for its
7895 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7896 * match the kernel's CONFIG_CLONE_* settings.
7897 * Microblaze is further special in that it uses a sixth
7898 * implicit argument to clone for the TLS pointer.
7899 */
7900#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007901 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007902#elif defined(TARGET_CLONE_BACKWARDS)
7903 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7904#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007905 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007906#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007907 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007908#endif
bellard1b6b0292003-03-22 17:31:38 +00007909 break;
bellardec86b0f2003-04-11 00:15:04 +00007910#ifdef __NR_exit_group
7911 /* new thread calls */
7912 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007913#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007914 _mcleanup();
7915#endif
bellarde9009672005-04-26 20:42:36 +00007916 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007917 ret = get_errno(exit_group(arg1));
7918 break;
7919#endif
bellard31e31b82003-02-18 22:55:36 +00007920 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007921 if (!(p = lock_user_string(arg1)))
7922 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007923 ret = get_errno(setdomainname(p, arg2));
7924 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007925 break;
7926 case TARGET_NR_uname:
7927 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007928 {
7929 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007930
bellard579a97f2007-11-11 14:26:47 +00007931 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7932 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007933 ret = get_errno(sys_uname(buf));
7934 if (!is_error(ret)) {
7935 /* Overrite the native machine name with whatever is being
7936 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007937 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007938 /* Allow the user to override the reported release. */
7939 if (qemu_uname_release && *qemu_uname_release)
7940 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007941 }
pbrook53a59602006-03-25 19:31:22 +00007942 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007943 }
bellard31e31b82003-02-18 22:55:36 +00007944 break;
bellard6dbad632003-03-16 18:05:05 +00007945#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007946 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007947 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007948 break;
j_mayer84409dd2007-04-06 08:56:50 +00007949#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007950 case TARGET_NR_vm86old:
7951 goto unimplemented;
7952 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007953 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007954 break;
7955#endif
j_mayer84409dd2007-04-06 08:56:50 +00007956#endif
bellard31e31b82003-02-18 22:55:36 +00007957 case TARGET_NR_adjtimex:
7958 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007959#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007960 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007961#endif
bellard31e31b82003-02-18 22:55:36 +00007962 case TARGET_NR_init_module:
7963 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007964#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007965 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007966#endif
bellard31e31b82003-02-18 22:55:36 +00007967 goto unimplemented;
7968 case TARGET_NR_quotactl:
7969 goto unimplemented;
7970 case TARGET_NR_getpgid:
7971 ret = get_errno(getpgid(arg1));
7972 break;
7973 case TARGET_NR_fchdir:
7974 ret = get_errno(fchdir(arg1));
7975 break;
j_mayer84409dd2007-04-06 08:56:50 +00007976#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007977 case TARGET_NR_bdflush:
7978 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007979#endif
thse5febef2007-04-01 18:31:35 +00007980#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007981 case TARGET_NR_sysfs:
7982 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007983#endif
bellard31e31b82003-02-18 22:55:36 +00007984 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007985 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007986 break;
thse5febef2007-04-01 18:31:35 +00007987#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007988 case TARGET_NR_afs_syscall:
7989 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007990#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007991#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007992 case TARGET_NR__llseek:
7993 {
7994 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007995#if !defined(__NR_llseek)
7996 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7997 if (res == -1) {
7998 ret = get_errno(res);
7999 } else {
8000 ret = 0;
8001 }
8002#else
bellard31e31b82003-02-18 22:55:36 +00008003 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008004#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008005 if ((ret == 0) && put_user_s64(res, arg4)) {
8006 goto efault;
8007 }
bellard31e31b82003-02-18 22:55:36 +00008008 }
8009 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008010#endif
Chen Gang704eff62015-08-21 05:37:33 +08008011#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008012 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008013#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008014#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008015 {
pbrook53a59602006-03-25 19:31:22 +00008016 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008017 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008018 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008019
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308020 dirp = g_try_malloc(count);
8021 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008022 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008023 goto fail;
8024 }
ths3b46e622007-09-17 08:09:54 +00008025
bellard4add45b2003-06-05 01:52:59 +00008026 ret = get_errno(sys_getdents(arg1, dirp, count));
8027 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008028 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008029 struct target_dirent *tde;
8030 int len = ret;
8031 int reclen, treclen;
8032 int count1, tnamelen;
8033
8034 count1 = 0;
8035 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008036 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8037 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008038 tde = target_dirp;
8039 while (len > 0) {
8040 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008041 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8042 assert(tnamelen >= 0);
8043 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8044 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008045 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008046 tde->d_ino = tswapal(de->d_ino);
8047 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008048 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008049 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008050 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008051 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008052 count1 += treclen;
8053 }
8054 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008055 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008056 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308057 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008058 }
8059#else
bellard31e31b82003-02-18 22:55:36 +00008060 {
aurel326556a832008-10-13 21:08:17 +00008061 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008062 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008063
bellard579a97f2007-11-11 14:26:47 +00008064 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8065 goto efault;
bellard72f03902003-02-18 23:33:18 +00008066 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008067 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008068 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008069 int len = ret;
8070 int reclen;
8071 de = dirp;
8072 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008073 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008074 if (reclen > len)
8075 break;
bellard8083a3e2003-03-24 23:12:16 +00008076 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008077 tswapls(&de->d_ino);
8078 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008079 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008080 len -= reclen;
8081 }
8082 }
pbrook53a59602006-03-25 19:31:22 +00008083 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008084 }
bellard4add45b2003-06-05 01:52:59 +00008085#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008086#else
8087 /* Implement getdents in terms of getdents64 */
8088 {
8089 struct linux_dirent64 *dirp;
8090 abi_long count = arg3;
8091
8092 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8093 if (!dirp) {
8094 goto efault;
8095 }
8096 ret = get_errno(sys_getdents64(arg1, dirp, count));
8097 if (!is_error(ret)) {
8098 /* Convert the dirent64 structs to target dirent. We do this
8099 * in-place, since we can guarantee that a target_dirent is no
8100 * larger than a dirent64; however this means we have to be
8101 * careful to read everything before writing in the new format.
8102 */
8103 struct linux_dirent64 *de;
8104 struct target_dirent *tde;
8105 int len = ret;
8106 int tlen = 0;
8107
8108 de = dirp;
8109 tde = (struct target_dirent *)dirp;
8110 while (len > 0) {
8111 int namelen, treclen;
8112 int reclen = de->d_reclen;
8113 uint64_t ino = de->d_ino;
8114 int64_t off = de->d_off;
8115 uint8_t type = de->d_type;
8116
8117 namelen = strlen(de->d_name);
8118 treclen = offsetof(struct target_dirent, d_name)
8119 + namelen + 2;
8120 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8121
8122 memmove(tde->d_name, de->d_name, namelen + 1);
8123 tde->d_ino = tswapal(ino);
8124 tde->d_off = tswapal(off);
8125 tde->d_reclen = tswap16(treclen);
8126 /* The target_dirent type is in what was formerly a padding
8127 * byte at the end of the structure:
8128 */
8129 *(((char *)tde) + treclen - 1) = type;
8130
8131 de = (struct linux_dirent64 *)((char *)de + reclen);
8132 tde = (struct target_dirent *)((char *)tde + treclen);
8133 len -= reclen;
8134 tlen += treclen;
8135 }
8136 ret = tlen;
8137 }
8138 unlock_user(dirp, arg2, ret);
8139 }
8140#endif
bellard31e31b82003-02-18 22:55:36 +00008141 break;
Chen Gang704eff62015-08-21 05:37:33 +08008142#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008143#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008144 case TARGET_NR_getdents64:
8145 {
aurel326556a832008-10-13 21:08:17 +00008146 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008147 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008148 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8149 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008150 ret = get_errno(sys_getdents64(arg1, dirp, count));
8151 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008152 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008153 int len = ret;
8154 int reclen;
8155 de = dirp;
8156 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008157 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008158 if (reclen > len)
8159 break;
bellard8083a3e2003-03-24 23:12:16 +00008160 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008161 tswap64s((uint64_t *)&de->d_ino);
8162 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008163 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008164 len -= reclen;
8165 }
8166 }
pbrook53a59602006-03-25 19:31:22 +00008167 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008168 }
8169 break;
bellarda541f292004-04-12 20:39:29 +00008170#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008171#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008172 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008173 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008174 break;
thse5febef2007-04-01 18:31:35 +00008175#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008176#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8177# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008178 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008179# endif
8180# ifdef TARGET_NR_ppoll
8181 case TARGET_NR_ppoll:
8182# endif
bellard9de5e442003-03-23 16:49:39 +00008183 {
pbrook53a59602006-03-25 19:31:22 +00008184 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008185 unsigned int nfds = arg2;
8186 int timeout = arg3;
8187 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008188 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008189
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008190 pfd = NULL;
8191 target_pfd = NULL;
8192 if (nfds) {
8193 target_pfd = lock_user(VERIFY_WRITE, arg1,
8194 sizeof(struct target_pollfd) * nfds, 1);
8195 if (!target_pfd) {
8196 goto efault;
8197 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008198
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008199 pfd = alloca(sizeof(struct pollfd) * nfds);
8200 for (i = 0; i < nfds; i++) {
8201 pfd[i].fd = tswap32(target_pfd[i].fd);
8202 pfd[i].events = tswap16(target_pfd[i].events);
8203 }
bellard9de5e442003-03-23 16:49:39 +00008204 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008205
8206# ifdef TARGET_NR_ppoll
8207 if (num == TARGET_NR_ppoll) {
8208 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8209 target_sigset_t *target_set;
8210 sigset_t _set, *set = &_set;
8211
8212 if (arg3) {
8213 if (target_to_host_timespec(timeout_ts, arg3)) {
8214 unlock_user(target_pfd, arg1, 0);
8215 goto efault;
8216 }
8217 } else {
8218 timeout_ts = NULL;
8219 }
8220
8221 if (arg4) {
8222 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
8223 if (!target_set) {
8224 unlock_user(target_pfd, arg1, 0);
8225 goto efault;
8226 }
8227 target_to_host_sigset(set, target_set);
8228 } else {
8229 set = NULL;
8230 }
8231
8232 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
8233
8234 if (!is_error(ret) && arg3) {
8235 host_to_target_timespec(arg3, timeout_ts);
8236 }
8237 if (arg4) {
8238 unlock_user(target_set, arg4, 0);
8239 }
8240 } else
8241# endif
8242 ret = get_errno(poll(pfd, nfds, timeout));
8243
bellard9de5e442003-03-23 16:49:39 +00008244 if (!is_error(ret)) {
8245 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00008246 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00008247 }
8248 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00008249 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00008250 }
8251 break;
thse5febef2007-04-01 18:31:35 +00008252#endif
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00008254 /* NOTE: the flock constant seems to be the same for every
8255 Linux platform */
8256 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008257 break;
8258 case TARGET_NR_readv:
8259 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008260 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
8261 if (vec != NULL) {
8262 ret = get_errno(readv(arg1, vec, arg3));
8263 unlock_iovec(vec, arg2, arg3, 1);
8264 } else {
8265 ret = -host_to_target_errno(errno);
8266 }
bellard31e31b82003-02-18 22:55:36 +00008267 }
8268 break;
8269 case TARGET_NR_writev:
8270 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008271 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8272 if (vec != NULL) {
8273 ret = get_errno(writev(arg1, vec, arg3));
8274 unlock_iovec(vec, arg2, arg3, 0);
8275 } else {
8276 ret = -host_to_target_errno(errno);
8277 }
bellard31e31b82003-02-18 22:55:36 +00008278 }
8279 break;
8280 case TARGET_NR_getsid:
8281 ret = get_errno(getsid(arg1));
8282 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008283#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00008284 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00008285 ret = get_errno(fdatasync(arg1));
8286 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008287#endif
Chen Gang704eff62015-08-21 05:37:33 +08008288#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00008289 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00008290 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00008291 return value. */
ths0da46a62007-10-20 20:23:07 +00008292 ret = -TARGET_ENOTDIR;
8293 break;
Chen Gang704eff62015-08-21 05:37:33 +08008294#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05008295 case TARGET_NR_sched_getaffinity:
8296 {
8297 unsigned int mask_size;
8298 unsigned long *mask;
8299
8300 /*
8301 * sched_getaffinity needs multiples of ulong, so need to take
8302 * care of mismatches between target ulong and host ulong sizes.
8303 */
8304 if (arg2 & (sizeof(abi_ulong) - 1)) {
8305 ret = -TARGET_EINVAL;
8306 break;
8307 }
8308 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8309
8310 mask = alloca(mask_size);
8311 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
8312
8313 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01008314 if (ret > arg2) {
8315 /* More data returned than the caller's buffer will fit.
8316 * This only happens if sizeof(abi_long) < sizeof(long)
8317 * and the caller passed us a buffer holding an odd number
8318 * of abi_longs. If the host kernel is actually using the
8319 * extra 4 bytes then fail EINVAL; otherwise we can just
8320 * ignore them and only copy the interesting part.
8321 */
8322 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
8323 if (numcpus > arg2 * 8) {
8324 ret = -TARGET_EINVAL;
8325 break;
8326 }
8327 ret = arg2;
8328 }
8329
Mike McCormackcd18f052011-04-18 14:43:36 +09008330 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05008331 goto efault;
8332 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05008333 }
8334 }
8335 break;
8336 case TARGET_NR_sched_setaffinity:
8337 {
8338 unsigned int mask_size;
8339 unsigned long *mask;
8340
8341 /*
8342 * sched_setaffinity needs multiples of ulong, so need to take
8343 * care of mismatches between target ulong and host ulong sizes.
8344 */
8345 if (arg2 & (sizeof(abi_ulong) - 1)) {
8346 ret = -TARGET_EINVAL;
8347 break;
8348 }
8349 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8350
8351 mask = alloca(mask_size);
8352 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
8353 goto efault;
8354 }
8355 memcpy(mask, p, arg2);
8356 unlock_user_struct(p, arg2, 0);
8357
8358 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
8359 }
8360 break;
bellard31e31b82003-02-18 22:55:36 +00008361 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00008362 {
pbrook53a59602006-03-25 19:31:22 +00008363 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008364 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00008365
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008366 if (arg2 == 0) {
8367 return -TARGET_EINVAL;
8368 }
bellard579a97f2007-11-11 14:26:47 +00008369 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
8370 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008371 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008372 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00008373 ret = get_errno(sched_setparam(arg1, &schp));
8374 }
8375 break;
bellard31e31b82003-02-18 22:55:36 +00008376 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00008377 {
pbrook53a59602006-03-25 19:31:22 +00008378 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008379 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008380
8381 if (arg2 == 0) {
8382 return -TARGET_EINVAL;
8383 }
bellard5cd43932003-03-29 16:54:36 +00008384 ret = get_errno(sched_getparam(arg1, &schp));
8385 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008386 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
8387 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008388 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008389 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00008390 }
8391 }
8392 break;
bellard31e31b82003-02-18 22:55:36 +00008393 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00008394 {
pbrook53a59602006-03-25 19:31:22 +00008395 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008396 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008397 if (arg3 == 0) {
8398 return -TARGET_EINVAL;
8399 }
bellard579a97f2007-11-11 14:26:47 +00008400 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
8401 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008402 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008403 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00008404 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
8405 }
8406 break;
bellard31e31b82003-02-18 22:55:36 +00008407 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00008408 ret = get_errno(sched_getscheduler(arg1));
8409 break;
bellard31e31b82003-02-18 22:55:36 +00008410 case TARGET_NR_sched_yield:
8411 ret = get_errno(sched_yield());
8412 break;
8413 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00008414 ret = get_errno(sched_get_priority_max(arg1));
8415 break;
bellard31e31b82003-02-18 22:55:36 +00008416 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00008417 ret = get_errno(sched_get_priority_min(arg1));
8418 break;
bellard31e31b82003-02-18 22:55:36 +00008419 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00008420 {
bellard5cd43932003-03-29 16:54:36 +00008421 struct timespec ts;
8422 ret = get_errno(sched_rr_get_interval(arg1, &ts));
8423 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05008424 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00008425 }
8426 }
8427 break;
bellard31e31b82003-02-18 22:55:36 +00008428 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00008429 {
bellard1b6b0292003-03-22 17:31:38 +00008430 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00008431 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00008432 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00008433 if (is_error(ret) && arg2) {
8434 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00008435 }
8436 }
8437 break;
thse5febef2007-04-01 18:31:35 +00008438#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00008439 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00008440 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008441#endif
8442#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00008443 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00008444 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008445#endif
bellard31e31b82003-02-18 22:55:36 +00008446 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00008447 switch (arg1) {
8448 case PR_GET_PDEATHSIG:
8449 {
8450 int deathsig;
8451 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
8452 if (!is_error(ret) && arg2
8453 && put_user_ual(deathsig, arg2)) {
8454 goto efault;
thse5574482007-02-11 20:03:13 +00008455 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00008456 break;
8457 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00008458#ifdef PR_GET_NAME
8459 case PR_GET_NAME:
8460 {
8461 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
8462 if (!name) {
8463 goto efault;
8464 }
8465 ret = get_errno(prctl(arg1, (unsigned long)name,
8466 arg3, arg4, arg5));
8467 unlock_user(name, arg2, 16);
8468 break;
8469 }
8470 case PR_SET_NAME:
8471 {
8472 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
8473 if (!name) {
8474 goto efault;
8475 }
8476 ret = get_errno(prctl(arg1, (unsigned long)name,
8477 arg3, arg4, arg5));
8478 unlock_user(name, arg2, 0);
8479 break;
8480 }
8481#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00008482 default:
8483 /* Most prctl options have no pointer arguments */
8484 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
8485 break;
8486 }
ths39b9aae2007-02-11 18:36:44 +00008487 break;
bellardd2fd1af2007-11-14 18:08:56 +00008488#ifdef TARGET_NR_arch_prctl
8489 case TARGET_NR_arch_prctl:
8490#if defined(TARGET_I386) && !defined(TARGET_ABI32)
8491 ret = do_arch_prctl(cpu_env, arg1, arg2);
8492 break;
8493#else
8494 goto unimplemented;
8495#endif
8496#endif
aurel32f2c7ba12008-03-28 22:32:06 +00008497#ifdef TARGET_NR_pread64
8498 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00008499 if (regpairs_aligned(cpu_env)) {
8500 arg4 = arg5;
8501 arg5 = arg6;
8502 }
aurel32f2c7ba12008-03-28 22:32:06 +00008503 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8504 goto efault;
8505 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
8506 unlock_user(p, arg2, ret);
8507 break;
8508 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00008509 if (regpairs_aligned(cpu_env)) {
8510 arg4 = arg5;
8511 arg5 = arg6;
8512 }
aurel32f2c7ba12008-03-28 22:32:06 +00008513 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8514 goto efault;
8515 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
8516 unlock_user(p, arg2, 0);
8517 break;
8518#endif
bellard31e31b82003-02-18 22:55:36 +00008519 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00008520 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
8521 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008522 ret = get_errno(sys_getcwd1(p, arg2));
8523 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00008524 break;
8525 case TARGET_NR_capget:
8526 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00008527 {
8528 struct target_user_cap_header *target_header;
8529 struct target_user_cap_data *target_data = NULL;
8530 struct __user_cap_header_struct header;
8531 struct __user_cap_data_struct data[2];
8532 struct __user_cap_data_struct *dataptr = NULL;
8533 int i, target_datalen;
8534 int data_items = 1;
8535
8536 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
8537 goto efault;
8538 }
8539 header.version = tswap32(target_header->version);
8540 header.pid = tswap32(target_header->pid);
8541
Peter Maydellec864872014-03-19 16:07:30 +00008542 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008543 /* Version 2 and up takes pointer to two user_data structs */
8544 data_items = 2;
8545 }
8546
8547 target_datalen = sizeof(*target_data) * data_items;
8548
8549 if (arg2) {
8550 if (num == TARGET_NR_capget) {
8551 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8552 } else {
8553 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8554 }
8555 if (!target_data) {
8556 unlock_user_struct(target_header, arg1, 0);
8557 goto efault;
8558 }
8559
8560 if (num == TARGET_NR_capset) {
8561 for (i = 0; i < data_items; i++) {
8562 data[i].effective = tswap32(target_data[i].effective);
8563 data[i].permitted = tswap32(target_data[i].permitted);
8564 data[i].inheritable = tswap32(target_data[i].inheritable);
8565 }
8566 }
8567
8568 dataptr = data;
8569 }
8570
8571 if (num == TARGET_NR_capget) {
8572 ret = get_errno(capget(&header, dataptr));
8573 } else {
8574 ret = get_errno(capset(&header, dataptr));
8575 }
8576
8577 /* The kernel always updates version for both capget and capset */
8578 target_header->version = tswap32(header.version);
8579 unlock_user_struct(target_header, arg1, 1);
8580
8581 if (arg2) {
8582 if (num == TARGET_NR_capget) {
8583 for (i = 0; i < data_items; i++) {
8584 target_data[i].effective = tswap32(data[i].effective);
8585 target_data[i].permitted = tswap32(data[i].permitted);
8586 target_data[i].inheritable = tswap32(data[i].inheritable);
8587 }
8588 unlock_user(target_data, arg2, target_datalen);
8589 } else {
8590 unlock_user(target_data, arg2, 0);
8591 }
8592 }
8593 break;
8594 }
bellard31e31b82003-02-18 22:55:36 +00008595 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01008596 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008597 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008598
8599#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008600 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008601 {
8602 off_t *offp = NULL;
8603 off_t off;
8604 if (arg3) {
8605 ret = get_user_sal(off, arg3);
8606 if (is_error(ret)) {
8607 break;
8608 }
8609 offp = &off;
8610 }
8611 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8612 if (!is_error(ret) && arg3) {
8613 abi_long ret2 = put_user_sal(off, arg3);
8614 if (is_error(ret2)) {
8615 ret = ret2;
8616 }
8617 }
8618 break;
8619 }
8620#ifdef TARGET_NR_sendfile64
8621 case TARGET_NR_sendfile64:
8622 {
8623 off_t *offp = NULL;
8624 off_t off;
8625 if (arg3) {
8626 ret = get_user_s64(off, arg3);
8627 if (is_error(ret)) {
8628 break;
8629 }
8630 offp = &off;
8631 }
8632 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8633 if (!is_error(ret) && arg3) {
8634 abi_long ret2 = put_user_s64(off, arg3);
8635 if (is_error(ret2)) {
8636 ret = ret2;
8637 }
8638 }
8639 break;
8640 }
8641#endif
8642#else
8643 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008644#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008645 case TARGET_NR_sendfile64:
8646#endif
bellard5cd43932003-03-29 16:54:36 +00008647 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008648#endif
8649
bellardebc05482003-09-30 21:08:41 +00008650#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008651 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008652 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008653#endif
8654#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008655 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008656 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008657#endif
bellard048f6b42005-11-26 18:47:20 +00008658#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008659 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008660 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8661 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008662 break;
bellard048f6b42005-11-26 18:47:20 +00008663#endif
bellardebc05482003-09-30 21:08:41 +00008664#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008665 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008666 {
8667 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008668 int resource = target_to_host_resource(arg1);
8669 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008670 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008671 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008672 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8673 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008674 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8675 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008676 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008677 }
8678 break;
8679 }
bellardebc05482003-09-30 21:08:41 +00008680#endif
bellarda315a142005-01-30 22:59:18 +00008681#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008682 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008683 if (!(p = lock_user_string(arg1)))
8684 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008685 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8686 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008687 break;
bellarda315a142005-01-30 22:59:18 +00008688#endif
8689#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008690 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008691 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008692 break;
bellarda315a142005-01-30 22:59:18 +00008693#endif
8694#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008695 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008696 if (!(p = lock_user_string(arg1)))
8697 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008698 ret = get_errno(stat(path(p), &st));
8699 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008700 if (!is_error(ret))
8701 ret = host_to_target_stat64(cpu_env, arg2, &st);
8702 break;
bellarda315a142005-01-30 22:59:18 +00008703#endif
8704#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008705 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008706 if (!(p = lock_user_string(arg1)))
8707 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008708 ret = get_errno(lstat(path(p), &st));
8709 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008710 if (!is_error(ret))
8711 ret = host_to_target_stat64(cpu_env, arg2, &st);
8712 break;
bellarda315a142005-01-30 22:59:18 +00008713#endif
8714#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008715 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008716 ret = get_errno(fstat(arg1, &st));
8717 if (!is_error(ret))
8718 ret = host_to_target_stat64(cpu_env, arg2, &st);
8719 break;
bellardec86b0f2003-04-11 00:15:04 +00008720#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008721#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008722#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008723 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008724#endif
8725#ifdef TARGET_NR_newfstatat
8726 case TARGET_NR_newfstatat:
8727#endif
balrog6a24a772008-09-20 02:23:36 +00008728 if (!(p = lock_user_string(arg2)))
8729 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008730 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008731 if (!is_error(ret))
8732 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008733 break;
bellarda315a142005-01-30 22:59:18 +00008734#endif
Chen Gang704eff62015-08-21 05:37:33 +08008735#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00008736 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008737 if (!(p = lock_user_string(arg1)))
8738 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008739 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8740 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008741 break;
Chen Gang704eff62015-08-21 05:37:33 +08008742#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03008743#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008744 case TARGET_NR_getuid:
8745 ret = get_errno(high2lowuid(getuid()));
8746 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008747#endif
8748#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008749 case TARGET_NR_getgid:
8750 ret = get_errno(high2lowgid(getgid()));
8751 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008752#endif
8753#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008754 case TARGET_NR_geteuid:
8755 ret = get_errno(high2lowuid(geteuid()));
8756 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008757#endif
8758#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008759 case TARGET_NR_getegid:
8760 ret = get_errno(high2lowgid(getegid()));
8761 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008762#endif
bellard67867302003-11-23 17:05:30 +00008763 case TARGET_NR_setreuid:
8764 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8765 break;
8766 case TARGET_NR_setregid:
8767 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8768 break;
8769 case TARGET_NR_getgroups:
8770 {
8771 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008772 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008773 gid_t *grouplist;
8774 int i;
8775
8776 grouplist = alloca(gidsetsize * sizeof(gid_t));
8777 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008778 if (gidsetsize == 0)
8779 break;
bellard67867302003-11-23 17:05:30 +00008780 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008781 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008782 if (!target_grouplist)
8783 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008784 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008785 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008786 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008787 }
8788 }
8789 break;
8790 case TARGET_NR_setgroups:
8791 {
8792 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008793 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008794 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008795 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008796 if (gidsetsize) {
8797 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008798 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008799 if (!target_grouplist) {
8800 ret = -TARGET_EFAULT;
8801 goto fail;
8802 }
8803 for (i = 0; i < gidsetsize; i++) {
8804 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8805 }
8806 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008807 }
bellard67867302003-11-23 17:05:30 +00008808 ret = get_errno(setgroups(gidsetsize, grouplist));
8809 }
8810 break;
8811 case TARGET_NR_fchown:
8812 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8813 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008814#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008815 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008816 if (!(p = lock_user_string(arg2)))
8817 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008818 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8819 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008820 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008821 break;
8822#endif
bellard67867302003-11-23 17:05:30 +00008823#ifdef TARGET_NR_setresuid
8824 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008825 ret = get_errno(setresuid(low2highuid(arg1),
8826 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008827 low2highuid(arg3)));
8828 break;
8829#endif
8830#ifdef TARGET_NR_getresuid
8831 case TARGET_NR_getresuid:
8832 {
pbrook53a59602006-03-25 19:31:22 +00008833 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008834 ret = get_errno(getresuid(&ruid, &euid, &suid));
8835 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008836 if (put_user_id(high2lowuid(ruid), arg1)
8837 || put_user_id(high2lowuid(euid), arg2)
8838 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008839 goto efault;
bellard67867302003-11-23 17:05:30 +00008840 }
8841 }
8842 break;
8843#endif
8844#ifdef TARGET_NR_getresgid
8845 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008846 ret = get_errno(setresgid(low2highgid(arg1),
8847 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008848 low2highgid(arg3)));
8849 break;
8850#endif
8851#ifdef TARGET_NR_getresgid
8852 case TARGET_NR_getresgid:
8853 {
pbrook53a59602006-03-25 19:31:22 +00008854 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008855 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8856 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008857 if (put_user_id(high2lowgid(rgid), arg1)
8858 || put_user_id(high2lowgid(egid), arg2)
8859 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008860 goto efault;
bellard67867302003-11-23 17:05:30 +00008861 }
8862 }
8863 break;
8864#endif
Chen Gang704eff62015-08-21 05:37:33 +08008865#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00008866 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008867 if (!(p = lock_user_string(arg1)))
8868 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008869 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8870 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008871 break;
Chen Gang704eff62015-08-21 05:37:33 +08008872#endif
bellard67867302003-11-23 17:05:30 +00008873 case TARGET_NR_setuid:
8874 ret = get_errno(setuid(low2highuid(arg1)));
8875 break;
8876 case TARGET_NR_setgid:
8877 ret = get_errno(setgid(low2highgid(arg1)));
8878 break;
8879 case TARGET_NR_setfsuid:
8880 ret = get_errno(setfsuid(arg1));
8881 break;
8882 case TARGET_NR_setfsgid:
8883 ret = get_errno(setfsgid(arg1));
8884 break;
bellard67867302003-11-23 17:05:30 +00008885
bellarda315a142005-01-30 22:59:18 +00008886#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008887 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008888 if (!(p = lock_user_string(arg1)))
8889 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008890 ret = get_errno(lchown(p, arg2, arg3));
8891 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008892 break;
bellarda315a142005-01-30 22:59:18 +00008893#endif
8894#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008895 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008896 ret = get_errno(getuid());
8897 break;
bellarda315a142005-01-30 22:59:18 +00008898#endif
aurel3264b4d282008-11-14 17:20:15 +00008899
8900#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8901 /* Alpha specific */
8902 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008903 {
8904 uid_t euid;
8905 euid=geteuid();
8906 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8907 }
aurel3264b4d282008-11-14 17:20:15 +00008908 ret = get_errno(getuid());
8909 break;
8910#endif
8911#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8912 /* Alpha specific */
8913 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008914 {
8915 uid_t egid;
8916 egid=getegid();
8917 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8918 }
aurel3264b4d282008-11-14 17:20:15 +00008919 ret = get_errno(getgid());
8920 break;
8921#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008922#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8923 /* Alpha specific */
8924 case TARGET_NR_osf_getsysinfo:
8925 ret = -TARGET_EOPNOTSUPP;
8926 switch (arg1) {
8927 case TARGET_GSI_IEEE_FP_CONTROL:
8928 {
8929 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8930
8931 /* Copied from linux ieee_fpcr_to_swcr. */
8932 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8933 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8934 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8935 | SWCR_TRAP_ENABLE_DZE
8936 | SWCR_TRAP_ENABLE_OVF);
8937 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8938 | SWCR_TRAP_ENABLE_INE);
8939 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8940 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8941
8942 if (put_user_u64 (swcr, arg2))
8943 goto efault;
8944 ret = 0;
8945 }
8946 break;
8947
8948 /* case GSI_IEEE_STATE_AT_SIGNAL:
8949 -- Not implemented in linux kernel.
8950 case GSI_UACPROC:
8951 -- Retrieves current unaligned access state; not much used.
8952 case GSI_PROC_TYPE:
8953 -- Retrieves implver information; surely not used.
8954 case GSI_GET_HWRPB:
8955 -- Grabs a copy of the HWRPB; surely not used.
8956 */
8957 }
8958 break;
8959#endif
8960#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8961 /* Alpha specific */
8962 case TARGET_NR_osf_setsysinfo:
8963 ret = -TARGET_EOPNOTSUPP;
8964 switch (arg1) {
8965 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008966 {
8967 uint64_t swcr, fpcr, orig_fpcr;
8968
Richard Henderson6e06d512012-06-01 09:08:21 -07008969 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008970 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008971 }
8972 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008973 fpcr = orig_fpcr & FPCR_DYN_MASK;
8974
8975 /* Copied from linux ieee_swcr_to_fpcr. */
8976 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8977 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8978 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8979 | SWCR_TRAP_ENABLE_DZE
8980 | SWCR_TRAP_ENABLE_OVF)) << 48;
8981 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8982 | SWCR_TRAP_ENABLE_INE)) << 57;
8983 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8984 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8985
Richard Henderson6e06d512012-06-01 09:08:21 -07008986 cpu_alpha_store_fpcr(cpu_env, fpcr);
8987 ret = 0;
8988 }
8989 break;
8990
8991 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8992 {
8993 uint64_t exc, fpcr, orig_fpcr;
8994 int si_code;
8995
8996 if (get_user_u64(exc, arg2)) {
8997 goto efault;
8998 }
8999
9000 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9001
9002 /* We only add to the exception status here. */
9003 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9004
9005 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009006 ret = 0;
9007
Richard Henderson6e06d512012-06-01 09:08:21 -07009008 /* Old exceptions are not signaled. */
9009 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009010
Richard Henderson6e06d512012-06-01 09:08:21 -07009011 /* If any exceptions set by this call,
9012 and are unmasked, send a signal. */
9013 si_code = 0;
9014 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9015 si_code = TARGET_FPE_FLTRES;
9016 }
9017 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9018 si_code = TARGET_FPE_FLTUND;
9019 }
9020 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9021 si_code = TARGET_FPE_FLTOVF;
9022 }
9023 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9024 si_code = TARGET_FPE_FLTDIV;
9025 }
9026 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9027 si_code = TARGET_FPE_FLTINV;
9028 }
9029 if (si_code != 0) {
9030 target_siginfo_t info;
9031 info.si_signo = SIGFPE;
9032 info.si_errno = 0;
9033 info.si_code = si_code;
9034 info._sifields._sigfault._addr
9035 = ((CPUArchState *)cpu_env)->pc;
9036 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009037 }
9038 }
9039 break;
9040
9041 /* case SSI_NVPAIRS:
9042 -- Used with SSIN_UACPROC to enable unaligned accesses.
9043 case SSI_IEEE_STATE_AT_SIGNAL:
9044 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9045 -- Not implemented in linux kernel
9046 */
9047 }
9048 break;
9049#endif
9050#ifdef TARGET_NR_osf_sigprocmask
9051 /* Alpha specific. */
9052 case TARGET_NR_osf_sigprocmask:
9053 {
9054 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009055 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009056 sigset_t set, oldset;
9057
9058 switch(arg1) {
9059 case TARGET_SIG_BLOCK:
9060 how = SIG_BLOCK;
9061 break;
9062 case TARGET_SIG_UNBLOCK:
9063 how = SIG_UNBLOCK;
9064 break;
9065 case TARGET_SIG_SETMASK:
9066 how = SIG_SETMASK;
9067 break;
9068 default:
9069 ret = -TARGET_EINVAL;
9070 goto fail;
9071 }
9072 mask = arg2;
9073 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00009074 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009075 host_to_target_old_sigset(&mask, &oldset);
9076 ret = mask;
9077 }
9078 break;
9079#endif
aurel3264b4d282008-11-14 17:20:15 +00009080
bellarda315a142005-01-30 22:59:18 +00009081#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009082 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009083 ret = get_errno(getgid());
9084 break;
bellarda315a142005-01-30 22:59:18 +00009085#endif
9086#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009087 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009088 ret = get_errno(geteuid());
9089 break;
bellarda315a142005-01-30 22:59:18 +00009090#endif
9091#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009092 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009093 ret = get_errno(getegid());
9094 break;
bellarda315a142005-01-30 22:59:18 +00009095#endif
9096#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009097 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009098 ret = get_errno(setreuid(arg1, arg2));
9099 break;
bellarda315a142005-01-30 22:59:18 +00009100#endif
9101#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009102 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009103 ret = get_errno(setregid(arg1, arg2));
9104 break;
bellarda315a142005-01-30 22:59:18 +00009105#endif
9106#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009107 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009108 {
9109 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009110 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009111 gid_t *grouplist;
9112 int i;
9113
9114 grouplist = alloca(gidsetsize * sizeof(gid_t));
9115 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009116 if (gidsetsize == 0)
9117 break;
bellard99c475a2005-01-31 20:45:13 +00009118 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009119 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9120 if (!target_grouplist) {
9121 ret = -TARGET_EFAULT;
9122 goto fail;
9123 }
balroga2155fc2008-09-20 02:12:08 +00009124 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009125 target_grouplist[i] = tswap32(grouplist[i]);
9126 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009127 }
9128 }
9129 break;
bellarda315a142005-01-30 22:59:18 +00009130#endif
9131#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009132 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009133 {
9134 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009135 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009136 gid_t *grouplist;
9137 int i;
ths3b46e622007-09-17 08:09:54 +00009138
bellard99c475a2005-01-31 20:45:13 +00009139 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009140 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9141 if (!target_grouplist) {
9142 ret = -TARGET_EFAULT;
9143 goto fail;
9144 }
bellard99c475a2005-01-31 20:45:13 +00009145 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009146 grouplist[i] = tswap32(target_grouplist[i]);
9147 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009148 ret = get_errno(setgroups(gidsetsize, grouplist));
9149 }
9150 break;
bellarda315a142005-01-30 22:59:18 +00009151#endif
9152#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009153 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009154 ret = get_errno(fchown(arg1, arg2, arg3));
9155 break;
bellarda315a142005-01-30 22:59:18 +00009156#endif
9157#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009158 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009159 ret = get_errno(setresuid(arg1, arg2, arg3));
9160 break;
bellarda315a142005-01-30 22:59:18 +00009161#endif
9162#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009163 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009164 {
pbrook53a59602006-03-25 19:31:22 +00009165 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009166 ret = get_errno(getresuid(&ruid, &euid, &suid));
9167 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009168 if (put_user_u32(ruid, arg1)
9169 || put_user_u32(euid, arg2)
9170 || put_user_u32(suid, arg3))
9171 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009172 }
9173 }
9174 break;
bellarda315a142005-01-30 22:59:18 +00009175#endif
9176#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009177 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009178 ret = get_errno(setresgid(arg1, arg2, arg3));
9179 break;
bellarda315a142005-01-30 22:59:18 +00009180#endif
9181#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009182 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009183 {
pbrook53a59602006-03-25 19:31:22 +00009184 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009185 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9186 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009187 if (put_user_u32(rgid, arg1)
9188 || put_user_u32(egid, arg2)
9189 || put_user_u32(sgid, arg3))
9190 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009191 }
9192 }
9193 break;
bellarda315a142005-01-30 22:59:18 +00009194#endif
9195#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009196 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009197 if (!(p = lock_user_string(arg1)))
9198 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009199 ret = get_errno(chown(p, arg2, arg3));
9200 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009201 break;
bellarda315a142005-01-30 22:59:18 +00009202#endif
9203#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009204 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00009205 ret = get_errno(setuid(arg1));
9206 break;
bellarda315a142005-01-30 22:59:18 +00009207#endif
9208#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009209 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00009210 ret = get_errno(setgid(arg1));
9211 break;
bellarda315a142005-01-30 22:59:18 +00009212#endif
9213#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009214 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009215 ret = get_errno(setfsuid(arg1));
9216 break;
bellarda315a142005-01-30 22:59:18 +00009217#endif
9218#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00009219 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00009220 ret = get_errno(setfsgid(arg1));
9221 break;
bellarda315a142005-01-30 22:59:18 +00009222#endif
bellard67867302003-11-23 17:05:30 +00009223
bellard31e31b82003-02-18 22:55:36 +00009224 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00009225 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00009226#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00009227 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00009228 {
9229 void *a;
9230 ret = -TARGET_EFAULT;
9231 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
9232 goto efault;
9233 if (!(p = lock_user_string(arg3)))
9234 goto mincore_fail;
9235 ret = get_errno(mincore(a, arg2, p));
9236 unlock_user(p, arg3, ret);
9237 mincore_fail:
9238 unlock_user(a, arg1, 0);
9239 }
9240 break;
bellardffa65c32004-01-04 23:57:22 +00009241#endif
aurel32408321b2008-10-01 21:46:32 +00009242#ifdef TARGET_NR_arm_fadvise64_64
9243 case TARGET_NR_arm_fadvise64_64:
9244 {
9245 /*
9246 * arm_fadvise64_64 looks like fadvise64_64 but
9247 * with different argument order
9248 */
9249 abi_long temp;
9250 temp = arg3;
9251 arg3 = arg4;
9252 arg4 = temp;
9253 }
9254#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009255#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00009256#ifdef TARGET_NR_fadvise64_64
9257 case TARGET_NR_fadvise64_64:
9258#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009259#ifdef TARGET_NR_fadvise64
9260 case TARGET_NR_fadvise64:
9261#endif
9262#ifdef TARGET_S390X
9263 switch (arg4) {
9264 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
9265 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
9266 case 6: arg4 = POSIX_FADV_DONTNEED; break;
9267 case 7: arg4 = POSIX_FADV_NOREUSE; break;
9268 default: break;
9269 }
9270#endif
9271 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00009272 break;
9273#endif
bellardffa65c32004-01-04 23:57:22 +00009274#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00009275 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00009276 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08009277 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00009278 This will break MADV_DONTNEED.
9279 This is a hint, so ignoring and returning success is ok. */
9280 ret = get_errno(0);
9281 break;
bellardffa65c32004-01-04 23:57:22 +00009282#endif
blueswir1992f48a2007-10-14 16:27:31 +00009283#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00009284 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00009285 {
thsb1e341e2007-03-20 21:50:52 +00009286 int cmd;
bellard77e46722003-04-29 20:39:06 +00009287 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00009288 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00009289#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00009290 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00009291#endif
bellard77e46722003-04-29 20:39:06 +00009292
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009293 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00009294 if (cmd == -TARGET_EINVAL) {
9295 ret = cmd;
9296 break;
9297 }
thsb1e341e2007-03-20 21:50:52 +00009298
bellard60cd49d2003-03-16 22:53:56 +00009299 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00009300 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00009301#ifdef TARGET_ARM
9302 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009303 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9304 goto efault;
ths58134272007-03-31 18:59:32 +00009305 fl.l_type = tswap16(target_efl->l_type);
9306 fl.l_whence = tswap16(target_efl->l_whence);
9307 fl.l_start = tswap64(target_efl->l_start);
9308 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009309 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00009310 unlock_user_struct(target_efl, arg3, 0);
9311 } else
9312#endif
9313 {
bellard9ee1fa22007-11-11 15:11:19 +00009314 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9315 goto efault;
ths58134272007-03-31 18:59:32 +00009316 fl.l_type = tswap16(target_fl->l_type);
9317 fl.l_whence = tswap16(target_fl->l_whence);
9318 fl.l_start = tswap64(target_fl->l_start);
9319 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009320 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00009321 unlock_user_struct(target_fl, arg3, 0);
9322 }
thsb1e341e2007-03-20 21:50:52 +00009323 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009324 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00009325#ifdef TARGET_ARM
9326 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009327 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
9328 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009329 target_efl->l_type = tswap16(fl.l_type);
9330 target_efl->l_whence = tswap16(fl.l_whence);
9331 target_efl->l_start = tswap64(fl.l_start);
9332 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009333 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009334 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009335 } else
9336#endif
9337 {
bellard9ee1fa22007-11-11 15:11:19 +00009338 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
9339 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009340 target_fl->l_type = tswap16(fl.l_type);
9341 target_fl->l_whence = tswap16(fl.l_whence);
9342 target_fl->l_start = tswap64(fl.l_start);
9343 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009344 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009345 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009346 }
bellard77e46722003-04-29 20:39:06 +00009347 }
9348 break;
9349
thsb1e341e2007-03-20 21:50:52 +00009350 case TARGET_F_SETLK64:
9351 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00009352#ifdef TARGET_ARM
9353 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009354 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9355 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009356 fl.l_type = tswap16(target_efl->l_type);
9357 fl.l_whence = tswap16(target_efl->l_whence);
9358 fl.l_start = tswap64(target_efl->l_start);
9359 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009360 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009361 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009362 } else
9363#endif
9364 {
bellard9ee1fa22007-11-11 15:11:19 +00009365 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9366 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009367 fl.l_type = tswap16(target_fl->l_type);
9368 fl.l_whence = tswap16(target_fl->l_whence);
9369 fl.l_start = tswap64(target_fl->l_start);
9370 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009371 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009372 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009373 }
thsb1e341e2007-03-20 21:50:52 +00009374 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009375 break;
bellard60cd49d2003-03-16 22:53:56 +00009376 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009377 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00009378 break;
9379 }
bellard77e46722003-04-29 20:39:06 +00009380 break;
9381 }
bellard60cd49d2003-03-16 22:53:56 +00009382#endif
ths7d600c82006-12-08 01:32:58 +00009383#ifdef TARGET_NR_cacheflush
9384 case TARGET_NR_cacheflush:
9385 /* self-modifying code is handled automatically, so nothing needed */
9386 ret = 0;
9387 break;
9388#endif
bellardebc05482003-09-30 21:08:41 +00009389#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00009390 case TARGET_NR_security:
9391 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009392#endif
bellardc573ff62004-01-04 15:51:36 +00009393#ifdef TARGET_NR_getpagesize
9394 case TARGET_NR_getpagesize:
9395 ret = TARGET_PAGE_SIZE;
9396 break;
9397#endif
bellard31e31b82003-02-18 22:55:36 +00009398 case TARGET_NR_gettid:
9399 ret = get_errno(gettid());
9400 break;
thse5febef2007-04-01 18:31:35 +00009401#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00009402 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00009403#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03009404 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00009405 arg2 = arg3;
9406 arg3 = arg4;
9407 arg4 = arg5;
9408 }
aurel322054ac92008-10-13 21:08:07 +00009409 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
9410#else
9411 ret = get_errno(readahead(arg1, arg2, arg3));
9412#endif
9413 break;
thse5febef2007-04-01 18:31:35 +00009414#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009415#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00009416#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00009417 case TARGET_NR_listxattr:
9418 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00009419 {
9420 void *p, *b = 0;
9421 if (arg2) {
9422 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9423 if (!b) {
9424 ret = -TARGET_EFAULT;
9425 break;
9426 }
9427 }
9428 p = lock_user_string(arg1);
9429 if (p) {
9430 if (num == TARGET_NR_listxattr) {
9431 ret = get_errno(listxattr(p, b, arg3));
9432 } else {
9433 ret = get_errno(llistxattr(p, b, arg3));
9434 }
9435 } else {
9436 ret = -TARGET_EFAULT;
9437 }
9438 unlock_user(p, arg1, 0);
9439 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03009440 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00009441 }
9442 case TARGET_NR_flistxattr:
9443 {
9444 void *b = 0;
9445 if (arg2) {
9446 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9447 if (!b) {
9448 ret = -TARGET_EFAULT;
9449 break;
9450 }
9451 }
9452 ret = get_errno(flistxattr(arg1, b, arg3));
9453 unlock_user(b, arg2, arg3);
9454 break;
9455 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009456 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009457 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009458 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009459 void *p, *n, *v = 0;
9460 if (arg3) {
9461 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9462 if (!v) {
9463 ret = -TARGET_EFAULT;
9464 break;
9465 }
9466 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009467 p = lock_user_string(arg1);
9468 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009469 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009470 if (num == TARGET_NR_setxattr) {
9471 ret = get_errno(setxattr(p, n, v, arg4, arg5));
9472 } else {
9473 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
9474 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009475 } else {
9476 ret = -TARGET_EFAULT;
9477 }
9478 unlock_user(p, arg1, 0);
9479 unlock_user(n, arg2, 0);
9480 unlock_user(v, arg3, 0);
9481 }
9482 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009483 case TARGET_NR_fsetxattr:
9484 {
9485 void *n, *v = 0;
9486 if (arg3) {
9487 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9488 if (!v) {
9489 ret = -TARGET_EFAULT;
9490 break;
9491 }
9492 }
9493 n = lock_user_string(arg2);
9494 if (n) {
9495 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
9496 } else {
9497 ret = -TARGET_EFAULT;
9498 }
9499 unlock_user(n, arg2, 0);
9500 unlock_user(v, arg3, 0);
9501 }
9502 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009503 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009504 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009505 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009506 void *p, *n, *v = 0;
9507 if (arg3) {
9508 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9509 if (!v) {
9510 ret = -TARGET_EFAULT;
9511 break;
9512 }
9513 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009514 p = lock_user_string(arg1);
9515 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009516 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009517 if (num == TARGET_NR_getxattr) {
9518 ret = get_errno(getxattr(p, n, v, arg4));
9519 } else {
9520 ret = get_errno(lgetxattr(p, n, v, arg4));
9521 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009522 } else {
9523 ret = -TARGET_EFAULT;
9524 }
9525 unlock_user(p, arg1, 0);
9526 unlock_user(n, arg2, 0);
9527 unlock_user(v, arg3, arg4);
9528 }
9529 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009530 case TARGET_NR_fgetxattr:
9531 {
9532 void *n, *v = 0;
9533 if (arg3) {
9534 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9535 if (!v) {
9536 ret = -TARGET_EFAULT;
9537 break;
9538 }
9539 }
9540 n = lock_user_string(arg2);
9541 if (n) {
9542 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9543 } else {
9544 ret = -TARGET_EFAULT;
9545 }
9546 unlock_user(n, arg2, 0);
9547 unlock_user(v, arg3, arg4);
9548 }
9549 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009550 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009551 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009552 {
9553 void *p, *n;
9554 p = lock_user_string(arg1);
9555 n = lock_user_string(arg2);
9556 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009557 if (num == TARGET_NR_removexattr) {
9558 ret = get_errno(removexattr(p, n));
9559 } else {
9560 ret = get_errno(lremovexattr(p, n));
9561 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009562 } else {
9563 ret = -TARGET_EFAULT;
9564 }
9565 unlock_user(p, arg1, 0);
9566 unlock_user(n, arg2, 0);
9567 }
9568 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009569 case TARGET_NR_fremovexattr:
9570 {
9571 void *n;
9572 n = lock_user_string(arg2);
9573 if (n) {
9574 ret = get_errno(fremovexattr(arg1, n));
9575 } else {
9576 ret = -TARGET_EFAULT;
9577 }
9578 unlock_user(n, arg2, 0);
9579 }
9580 break;
bellardebc05482003-09-30 21:08:41 +00009581#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009582#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009583#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009584 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009585#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009586 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009587 ret = 0;
9588 break;
edgar_iglef967792009-01-07 14:19:38 +00009589#elif defined(TARGET_CRIS)
9590 if (arg1 & 0xff)
9591 ret = -TARGET_EINVAL;
9592 else {
9593 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9594 ret = 0;
9595 }
9596 break;
bellard8d18e892007-11-14 15:18:40 +00009597#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9598 ret = do_set_thread_area(cpu_env, arg1);
9599 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009600#elif defined(TARGET_M68K)
9601 {
Andreas Färber0429a972013-08-26 18:14:44 +02009602 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009603 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009604 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009605 break;
9606 }
ths6f5b89a2007-03-02 20:48:00 +00009607#else
9608 goto unimplemented_nowarn;
9609#endif
9610#endif
9611#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009612 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009613#if defined(TARGET_I386) && defined(TARGET_ABI32)
9614 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009615 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009616#elif defined(TARGET_M68K)
9617 {
Andreas Färber0429a972013-08-26 18:14:44 +02009618 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009619 ret = ts->tp_value;
9620 break;
9621 }
bellard8d18e892007-11-14 15:18:40 +00009622#else
bellard5cd43932003-03-29 16:54:36 +00009623 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009624#endif
bellard8d18e892007-11-14 15:18:40 +00009625#endif
bellard48dc41e2006-06-21 18:15:50 +00009626#ifdef TARGET_NR_getdomainname
9627 case TARGET_NR_getdomainname:
9628 goto unimplemented_nowarn;
9629#endif
ths6f5b89a2007-03-02 20:48:00 +00009630
thsb5906f92007-03-19 13:32:45 +00009631#ifdef TARGET_NR_clock_gettime
9632 case TARGET_NR_clock_gettime:
9633 {
9634 struct timespec ts;
9635 ret = get_errno(clock_gettime(arg1, &ts));
9636 if (!is_error(ret)) {
9637 host_to_target_timespec(arg2, &ts);
9638 }
9639 break;
9640 }
9641#endif
9642#ifdef TARGET_NR_clock_getres
9643 case TARGET_NR_clock_getres:
9644 {
9645 struct timespec ts;
9646 ret = get_errno(clock_getres(arg1, &ts));
9647 if (!is_error(ret)) {
9648 host_to_target_timespec(arg2, &ts);
9649 }
9650 break;
9651 }
9652#endif
pbrook63d76512008-05-29 13:43:29 +00009653#ifdef TARGET_NR_clock_nanosleep
9654 case TARGET_NR_clock_nanosleep:
9655 {
9656 struct timespec ts;
9657 target_to_host_timespec(&ts, arg3);
9658 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9659 if (arg4)
9660 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009661
9662#if defined(TARGET_PPC)
9663 /* clock_nanosleep is odd in that it returns positive errno values.
9664 * On PPC, CR0 bit 3 should be set in such a situation. */
9665 if (ret) {
9666 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9667 }
9668#endif
pbrook63d76512008-05-29 13:43:29 +00009669 break;
9670 }
9671#endif
thsb5906f92007-03-19 13:32:45 +00009672
ths6f5b89a2007-03-02 20:48:00 +00009673#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9674 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009675 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9676 break;
ths6f5b89a2007-03-02 20:48:00 +00009677#endif
9678
ths3ae43202007-09-16 21:39:48 +00009679#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009680 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009681 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009682 break;
9683#endif
9684
ths3ae43202007-09-16 21:39:48 +00009685#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009686 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009687 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9688 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009689 break;
9690#endif
9691
ths4f2b1fe2007-06-21 21:57:12 +00009692#ifdef TARGET_NR_set_robust_list
9693 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009694 case TARGET_NR_get_robust_list:
9695 /* The ABI for supporting robust futexes has userspace pass
9696 * the kernel a pointer to a linked list which is updated by
9697 * userspace after the syscall; the list is walked by the kernel
9698 * when the thread exits. Since the linked list in QEMU guest
9699 * memory isn't a valid linked list for the host and we have
9700 * no way to reliably intercept the thread-death event, we can't
9701 * support these. Silently return ENOSYS so that guest userspace
9702 * falls back to a non-robust futex implementation (which should
9703 * be OK except in the corner case of the guest crashing while
9704 * holding a mutex that is shared with another process via
9705 * shared memory).
9706 */
9707 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009708#endif
9709
Peter Maydell1acae9f2013-07-02 14:04:12 +01009710#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009711 case TARGET_NR_utimensat:
9712 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009713 struct timespec *tsp, ts[2];
9714 if (!arg3) {
9715 tsp = NULL;
9716 } else {
9717 target_to_host_timespec(ts, arg3);
9718 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9719 tsp = ts;
9720 }
ths9007f0e2007-09-25 17:50:37 +00009721 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009722 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009723 else {
bellard579a97f2007-11-11 14:26:47 +00009724 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009725 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009726 goto fail;
9727 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009728 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009729 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009730 }
9731 }
9732 break;
9733#endif
pbrookbd0c5662008-05-29 14:34:11 +00009734 case TARGET_NR_futex:
9735 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9736 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009737#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009738 case TARGET_NR_inotify_init:
9739 ret = get_errno(sys_inotify_init());
9740 break;
9741#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009742#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009743#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9744 case TARGET_NR_inotify_init1:
9745 ret = get_errno(sys_inotify_init1(arg1));
9746 break;
9747#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009748#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009749#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009750 case TARGET_NR_inotify_add_watch:
9751 p = lock_user_string(arg2);
9752 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9753 unlock_user(p, arg2, 0);
9754 break;
9755#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009756#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009757 case TARGET_NR_inotify_rm_watch:
9758 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9759 break;
9760#endif
ths9007f0e2007-09-25 17:50:37 +00009761
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009762#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009763 case TARGET_NR_mq_open:
9764 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009765 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009766
9767 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009768 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009769 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009770 attrp = &posix_mq_attr;
9771 } else {
9772 attrp = 0;
9773 }
9774 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009775 unlock_user (p, arg1, 0);
9776 }
9777 break;
9778
9779 case TARGET_NR_mq_unlink:
9780 p = lock_user_string(arg1 - 1);
9781 ret = get_errno(mq_unlink(p));
9782 unlock_user (p, arg1, 0);
9783 break;
9784
9785 case TARGET_NR_mq_timedsend:
9786 {
9787 struct timespec ts;
9788
9789 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9790 if (arg5 != 0) {
9791 target_to_host_timespec(&ts, arg5);
9792 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9793 host_to_target_timespec(arg5, &ts);
9794 }
9795 else
9796 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9797 unlock_user (p, arg2, arg3);
9798 }
9799 break;
9800
9801 case TARGET_NR_mq_timedreceive:
9802 {
9803 struct timespec ts;
9804 unsigned int prio;
9805
9806 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9807 if (arg5 != 0) {
9808 target_to_host_timespec(&ts, arg5);
9809 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9810 host_to_target_timespec(arg5, &ts);
9811 }
9812 else
9813 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9814 unlock_user (p, arg2, arg3);
9815 if (arg4 != 0)
9816 put_user_u32(prio, arg4);
9817 }
9818 break;
9819
9820 /* Not implemented for now... */
9821/* case TARGET_NR_mq_notify: */
9822/* break; */
9823
9824 case TARGET_NR_mq_getsetattr:
9825 {
9826 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9827 ret = 0;
9828 if (arg3 != 0) {
9829 ret = mq_getattr(arg1, &posix_mq_attr_out);
9830 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9831 }
9832 if (arg2 != 0) {
9833 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9834 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9835 }
9836
9837 }
9838 break;
9839#endif
9840
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309841#ifdef CONFIG_SPLICE
9842#ifdef TARGET_NR_tee
9843 case TARGET_NR_tee:
9844 {
9845 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9846 }
9847 break;
9848#endif
9849#ifdef TARGET_NR_splice
9850 case TARGET_NR_splice:
9851 {
9852 loff_t loff_in, loff_out;
9853 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +01009854 if (arg2) {
9855 if (get_user_u64(loff_in, arg2)) {
9856 goto efault;
9857 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309858 ploff_in = &loff_in;
9859 }
Andreas Schwab17644b32015-03-10 17:11:35 +01009860 if (arg4) {
9861 if (get_user_u64(loff_out, arg4)) {
9862 goto efault;
9863 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309864 ploff_out = &loff_out;
9865 }
9866 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +01009867 if (arg2) {
9868 if (put_user_u64(loff_in, arg2)) {
9869 goto efault;
9870 }
9871 }
9872 if (arg4) {
9873 if (put_user_u64(loff_out, arg4)) {
9874 goto efault;
9875 }
9876 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309877 }
9878 break;
9879#endif
9880#ifdef TARGET_NR_vmsplice
9881 case TARGET_NR_vmsplice:
9882 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009883 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9884 if (vec != NULL) {
9885 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9886 unlock_iovec(vec, arg2, arg3, 0);
9887 } else {
9888 ret = -host_to_target_errno(errno);
9889 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309890 }
9891 break;
9892#endif
9893#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009894#ifdef CONFIG_EVENTFD
9895#if defined(TARGET_NR_eventfd)
9896 case TARGET_NR_eventfd:
9897 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +02009898 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009899 break;
9900#endif
9901#if defined(TARGET_NR_eventfd2)
9902 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009903 {
9904 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9905 if (arg2 & TARGET_O_NONBLOCK) {
9906 host_flags |= O_NONBLOCK;
9907 }
9908 if (arg2 & TARGET_O_CLOEXEC) {
9909 host_flags |= O_CLOEXEC;
9910 }
9911 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02009912 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009913 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009914 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009915#endif
9916#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009917#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9918 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009919#if TARGET_ABI_BITS == 32
9920 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9921 target_offset64(arg5, arg6)));
9922#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009923 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009924#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009925 break;
9926#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009927#if defined(CONFIG_SYNC_FILE_RANGE)
9928#if defined(TARGET_NR_sync_file_range)
9929 case TARGET_NR_sync_file_range:
9930#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009931#if defined(TARGET_MIPS)
9932 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9933 target_offset64(arg5, arg6), arg7));
9934#else
Peter Maydellc727f472011-01-06 11:05:10 +00009935 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9936 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009937#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009938#else
9939 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9940#endif
9941 break;
9942#endif
9943#if defined(TARGET_NR_sync_file_range2)
9944 case TARGET_NR_sync_file_range2:
9945 /* This is like sync_file_range but the arguments are reordered */
9946#if TARGET_ABI_BITS == 32
9947 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9948 target_offset64(arg5, arg6), arg2));
9949#else
9950 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9951#endif
9952 break;
9953#endif
9954#endif
Laurent Viviere36800c2015-10-02 14:48:09 +02009955#if defined(TARGET_NR_signalfd4)
9956 case TARGET_NR_signalfd4:
9957 ret = do_signalfd4(arg1, arg2, arg4);
9958 break;
9959#endif
9960#if defined(TARGET_NR_signalfd)
9961 case TARGET_NR_signalfd:
9962 ret = do_signalfd4(arg1, arg2, 0);
9963 break;
9964#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009965#if defined(CONFIG_EPOLL)
9966#if defined(TARGET_NR_epoll_create)
9967 case TARGET_NR_epoll_create:
9968 ret = get_errno(epoll_create(arg1));
9969 break;
9970#endif
9971#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9972 case TARGET_NR_epoll_create1:
9973 ret = get_errno(epoll_create1(arg1));
9974 break;
9975#endif
9976#if defined(TARGET_NR_epoll_ctl)
9977 case TARGET_NR_epoll_ctl:
9978 {
9979 struct epoll_event ep;
9980 struct epoll_event *epp = 0;
9981 if (arg4) {
9982 struct target_epoll_event *target_ep;
9983 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9984 goto efault;
9985 }
9986 ep.events = tswap32(target_ep->events);
9987 /* The epoll_data_t union is just opaque data to the kernel,
9988 * so we transfer all 64 bits across and need not worry what
9989 * actual data type it is.
9990 */
9991 ep.data.u64 = tswap64(target_ep->data.u64);
9992 unlock_user_struct(target_ep, arg4, 0);
9993 epp = &ep;
9994 }
9995 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9996 break;
9997 }
9998#endif
9999
10000#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
10001#define IMPLEMENT_EPOLL_PWAIT
10002#endif
10003#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
10004#if defined(TARGET_NR_epoll_wait)
10005 case TARGET_NR_epoll_wait:
10006#endif
10007#if defined(IMPLEMENT_EPOLL_PWAIT)
10008 case TARGET_NR_epoll_pwait:
10009#endif
10010 {
10011 struct target_epoll_event *target_ep;
10012 struct epoll_event *ep;
10013 int epfd = arg1;
10014 int maxevents = arg3;
10015 int timeout = arg4;
10016
10017 target_ep = lock_user(VERIFY_WRITE, arg2,
10018 maxevents * sizeof(struct target_epoll_event), 1);
10019 if (!target_ep) {
10020 goto efault;
10021 }
10022
10023 ep = alloca(maxevents * sizeof(struct epoll_event));
10024
10025 switch (num) {
10026#if defined(IMPLEMENT_EPOLL_PWAIT)
10027 case TARGET_NR_epoll_pwait:
10028 {
10029 target_sigset_t *target_set;
10030 sigset_t _set, *set = &_set;
10031
10032 if (arg5) {
10033 target_set = lock_user(VERIFY_READ, arg5,
10034 sizeof(target_sigset_t), 1);
10035 if (!target_set) {
10036 unlock_user(target_ep, arg2, 0);
10037 goto efault;
10038 }
10039 target_to_host_sigset(set, target_set);
10040 unlock_user(target_set, arg5, 0);
10041 } else {
10042 set = NULL;
10043 }
10044
10045 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
10046 break;
10047 }
10048#endif
10049#if defined(TARGET_NR_epoll_wait)
10050 case TARGET_NR_epoll_wait:
10051 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
10052 break;
10053#endif
10054 default:
10055 ret = -TARGET_ENOSYS;
10056 }
10057 if (!is_error(ret)) {
10058 int i;
10059 for (i = 0; i < ret; i++) {
10060 target_ep[i].events = tswap32(ep[i].events);
10061 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10062 }
10063 }
10064 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10065 break;
10066 }
10067#endif
10068#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010069#ifdef TARGET_NR_prlimit64
10070 case TARGET_NR_prlimit64:
10071 {
10072 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10073 struct target_rlimit64 *target_rnew, *target_rold;
10074 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010075 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010076 if (arg3) {
10077 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10078 goto efault;
10079 }
10080 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10081 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10082 unlock_user_struct(target_rnew, arg3, 0);
10083 rnewp = &rnew;
10084 }
10085
Felix Janda95018012014-12-02 22:11:17 +010010086 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010087 if (!is_error(ret) && arg4) {
10088 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10089 goto efault;
10090 }
10091 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10092 target_rold->rlim_max = tswap64(rold.rlim_max);
10093 unlock_user_struct(target_rold, arg4, 1);
10094 }
10095 break;
10096 }
10097#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010098#ifdef TARGET_NR_gethostname
10099 case TARGET_NR_gethostname:
10100 {
10101 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10102 if (name) {
10103 ret = get_errno(gethostname(name, arg2));
10104 unlock_user(name, arg1, arg2);
10105 } else {
10106 ret = -TARGET_EFAULT;
10107 }
10108 break;
10109 }
10110#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010111#ifdef TARGET_NR_atomic_cmpxchg_32
10112 case TARGET_NR_atomic_cmpxchg_32:
10113 {
10114 /* should use start_exclusive from main.c */
10115 abi_ulong mem_value;
10116 if (get_user_u32(mem_value, arg6)) {
10117 target_siginfo_t info;
10118 info.si_signo = SIGSEGV;
10119 info.si_errno = 0;
10120 info.si_code = TARGET_SEGV_MAPERR;
10121 info._sifields._sigfault._addr = arg6;
10122 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10123 ret = 0xdeadbeef;
10124
10125 }
10126 if (mem_value == arg2)
10127 put_user_u32(arg1, arg6);
10128 ret = mem_value;
10129 break;
10130 }
10131#endif
10132#ifdef TARGET_NR_atomic_barrier
10133 case TARGET_NR_atomic_barrier:
10134 {
10135 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010136 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010137 break;
10138 }
10139#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010140
10141#ifdef TARGET_NR_timer_create
10142 case TARGET_NR_timer_create:
10143 {
10144 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10145
10146 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010147
10148 int clkid = arg1;
10149 int timer_index = next_free_host_timer();
10150
10151 if (timer_index < 0) {
10152 ret = -TARGET_EAGAIN;
10153 } else {
10154 timer_t *phtimer = g_posix_timers + timer_index;
10155
10156 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010157 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010158 ret = target_to_host_sigevent(phost_sevp, arg2);
10159 if (ret != 0) {
10160 break;
10161 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010162 }
10163
10164 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10165 if (ret) {
10166 phtimer = NULL;
10167 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010168 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010169 goto efault;
10170 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010171 }
10172 }
10173 break;
10174 }
10175#endif
10176
10177#ifdef TARGET_NR_timer_settime
10178 case TARGET_NR_timer_settime:
10179 {
10180 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
10181 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010182 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010183
Alexander Grafaecc8862014-11-10 21:33:03 +010010184 if (timerid < 0) {
10185 ret = timerid;
10186 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010187 ret = -TARGET_EINVAL;
10188 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010189 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010190 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
10191
10192 target_to_host_itimerspec(&hspec_new, arg3);
10193 ret = get_errno(
10194 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
10195 host_to_target_itimerspec(arg2, &hspec_old);
10196 }
10197 break;
10198 }
10199#endif
10200
10201#ifdef TARGET_NR_timer_gettime
10202 case TARGET_NR_timer_gettime:
10203 {
10204 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010205 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010206
Alexander Grafaecc8862014-11-10 21:33:03 +010010207 if (timerid < 0) {
10208 ret = timerid;
10209 } else if (!arg2) {
10210 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010211 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010212 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010213 struct itimerspec hspec;
10214 ret = get_errno(timer_gettime(htimer, &hspec));
10215
10216 if (host_to_target_itimerspec(arg2, &hspec)) {
10217 ret = -TARGET_EFAULT;
10218 }
10219 }
10220 break;
10221 }
10222#endif
10223
10224#ifdef TARGET_NR_timer_getoverrun
10225 case TARGET_NR_timer_getoverrun:
10226 {
10227 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010228 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010229
Alexander Grafaecc8862014-11-10 21:33:03 +010010230 if (timerid < 0) {
10231 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010232 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010233 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010234 ret = get_errno(timer_getoverrun(htimer));
10235 }
Laurent Viviere36800c2015-10-02 14:48:09 +020010236 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010237 break;
10238 }
10239#endif
10240
10241#ifdef TARGET_NR_timer_delete
10242 case TARGET_NR_timer_delete:
10243 {
10244 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010245 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010246
Alexander Grafaecc8862014-11-10 21:33:03 +010010247 if (timerid < 0) {
10248 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010249 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010250 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010251 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020010252 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010253 }
10254 break;
10255 }
10256#endif
10257
Riku Voipio51834342014-06-22 11:25:42 +010010258#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
10259 case TARGET_NR_timerfd_create:
10260 ret = get_errno(timerfd_create(arg1,
10261 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
10262 break;
10263#endif
10264
10265#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
10266 case TARGET_NR_timerfd_gettime:
10267 {
10268 struct itimerspec its_curr;
10269
10270 ret = get_errno(timerfd_gettime(arg1, &its_curr));
10271
10272 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
10273 goto efault;
10274 }
10275 }
10276 break;
10277#endif
10278
10279#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
10280 case TARGET_NR_timerfd_settime:
10281 {
10282 struct itimerspec its_new, its_old, *p_new;
10283
10284 if (arg3) {
10285 if (target_to_host_itimerspec(&its_new, arg3)) {
10286 goto efault;
10287 }
10288 p_new = &its_new;
10289 } else {
10290 p_new = NULL;
10291 }
10292
10293 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
10294
10295 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
10296 goto efault;
10297 }
10298 }
10299 break;
10300#endif
10301
Paul Burtonab31cda2014-06-22 11:25:43 +010010302#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
10303 case TARGET_NR_ioprio_get:
10304 ret = get_errno(ioprio_get(arg1, arg2));
10305 break;
10306#endif
10307
10308#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
10309 case TARGET_NR_ioprio_set:
10310 ret = get_errno(ioprio_set(arg1, arg2, arg3));
10311 break;
10312#endif
10313
Riku Voipio9af5c902014-08-12 15:58:57 +030010314#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
10315 case TARGET_NR_setns:
10316 ret = get_errno(setns(arg1, arg2));
10317 break;
10318#endif
10319#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
10320 case TARGET_NR_unshare:
10321 ret = get_errno(unshare(arg1));
10322 break;
10323#endif
10324
bellard31e31b82003-02-18 22:55:36 +000010325 default:
10326 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000010327 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000010328#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 +000010329 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000010330#endif
ths0da46a62007-10-20 20:23:07 +000010331 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000010332 break;
10333 }
bellard579a97f2007-11-11 14:26:47 +000010334fail:
bellardc573ff62004-01-04 15:51:36 +000010335#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000010336 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000010337#endif
thsb92c47c2007-11-01 00:07:38 +000010338 if(do_strace)
10339 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000010340 return ret;
bellard579a97f2007-11-11 14:26:47 +000010341efault:
10342 ret = -TARGET_EFAULT;
10343 goto fail;
bellard31e31b82003-02-18 22:55:36 +000010344}