blob: 4b0d79110444d4c4de832fe983fb3190f2df7e20 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
Peter Maydelld39594e2016-01-26 18:17:02 +000020#include "qemu/osdep.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020021#include "qemu/cutils.h"
22#include "qemu/path.h"
bellard31e31b82003-02-18 22:55:36 +000023#include <elf.h>
24#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010025#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000026#include <sys/ipc.h>
27#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000029#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010030#include <sys/file.h>
31#include <sys/fsuid.h>
32#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000033#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000036#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000037#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020038#ifdef __ia64__
39int __clone2(int (*fn)(void *), void *child_stack_base,
40 size_t stack_size, int flags, void *arg, ...);
41#endif
bellard31e31b82003-02-18 22:55:36 +000042#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000043#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000044#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000045#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000046#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000047#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000048#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000049#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000050#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000051#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020052#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000053//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000054#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000055#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020056#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000057#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020058#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030059#ifdef CONFIG_TIMERFD
60#include <sys/timerfd.h>
61#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020062#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000063#include <sys/gmon.h>
64#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030065#ifdef CONFIG_EVENTFD
66#include <sys/eventfd.h>
67#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000068#ifdef CONFIG_EPOLL
69#include <sys/epoll.h>
70#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070071#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010072#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000074#ifdef CONFIG_SENDFILE
75#include <sys/sendfile.h>
76#endif
bellard31e31b82003-02-18 22:55:36 +000077
78#define termios host_termios
79#define winsize host_winsize
80#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000081#define sgttyb host_sgttyb /* same as target */
82#define tchars host_tchars /* same as target */
83#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000084
85#include <linux/termios.h>
86#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000087#include <linux/cdrom.h>
88#include <linux/hdreg.h>
89#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000090#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000091#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030092#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000093#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000094#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020096#include <linux/fb.h>
97#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010098#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +000099#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100100#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200101#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100102#include <linux/blkpg.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200103#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200104#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200105#include <linux/rtnetlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200106#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200107#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000108#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200109#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000110
bellard3ef693a2003-03-23 20:17:16 +0000111#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000112
pbrookd865bab2008-06-07 22:12:17 +0000113#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
114 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000115
bellard72f03902003-02-18 23:33:18 +0000116//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100117/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
118 * once. This exercises the codepaths for restart.
119 */
120//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000121
bellard1a9353d2003-03-16 20:28:50 +0000122//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000123#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
124#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000125
bellard70a194b2003-08-11 22:20:16 +0000126#undef _syscall0
127#undef _syscall1
128#undef _syscall2
129#undef _syscall3
130#undef _syscall4
131#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000132#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000133
bellard83fcb512006-06-14 13:37:16 +0000134#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000135static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000136{ \
137 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000138}
139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000162}
163
bellard83fcb512006-06-14 13:37:16 +0000164#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
165 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000166static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000167{ \
168 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000169}
bellard83fcb512006-06-14 13:37:16 +0000170
171
172#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
173 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000174static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
175 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000176{ \
177 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
178}
179
bellard70a194b2003-08-11 22:20:16 +0000180
bellard31e31b82003-02-18 22:55:36 +0000181#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000183#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000184#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000185#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000186#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000187#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000188#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000189#define __NR_sys_inotify_init __NR_inotify_init
190#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
191#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000192
Alexander Graf42a39fb2011-04-15 17:32:45 +0200193#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
194 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000195#define __NR__llseek __NR_lseek
196#endif
197
James Hogana29e5ba2014-03-25 21:51:08 +0000198/* Newer kernel ports have llseek() instead of _llseek() */
199#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
200#define TARGET_NR__llseek TARGET_NR_llseek
201#endif
202
bellard72f03902003-02-18 23:33:18 +0000203#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000204_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000205#else
ths0da46a62007-10-20 20:23:07 +0000206/* This is a replacement for the host gettid() and must return a host
207 errno. */
bellard72f03902003-02-18 23:33:18 +0000208static int gettid(void) {
209 return -ENOSYS;
210}
211#endif
Chen Gang704eff62015-08-21 05:37:33 +0800212#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000213_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100214#endif
215#if !defined(__NR_getdents) || \
216 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000217_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
218#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700219#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000220_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
221 loff_t *, res, uint, wh);
222#endif
223_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
224_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000225#ifdef __NR_exit_group
226_syscall1(int,exit_group,int,error_code)
227#endif
228#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
229_syscall1(int,set_tid_address,int *,tidptr)
230#endif
aurel323b3f24a2009-04-15 16:12:13 +0000231#if defined(TARGET_NR_futex) && defined(__NR_futex)
232_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
233 const struct timespec *,timeout,int *,uaddr2,int,val3)
234#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500235#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
236_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
237 unsigned long *, user_mask_ptr);
238#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
239_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
240 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200241_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
242 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000243_syscall2(int, capget, struct __user_cap_header_struct *, header,
244 struct __user_cap_data_struct *, data);
245_syscall2(int, capset, struct __user_cap_header_struct *, header,
246 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100247#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
248_syscall2(int, ioprio_get, int, which, int, who)
249#endif
250#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
251_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
252#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100253#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
254_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
255#endif
aurel323b3f24a2009-04-15 16:12:13 +0000256
257static bitmask_transtbl fcntl_flags_tbl[] = {
258 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
259 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
260 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
261 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
262 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
263 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
264 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
265 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700266 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000267 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
268 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
269 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
270 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000271#if defined(O_DIRECT)
272 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
273#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700274#if defined(O_NOATIME)
275 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
276#endif
277#if defined(O_CLOEXEC)
278 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
279#endif
280#if defined(O_PATH)
281 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
282#endif
283 /* Don't terminate the list prematurely on 64-bit host+guest. */
284#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
285 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
286#endif
aurel323b3f24a2009-04-15 16:12:13 +0000287 { 0, 0, 0, 0 }
288};
289
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100290typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100291typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200292typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100293 TargetFdDataFunc host_to_target_data;
294 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100295 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200296} TargetFdTrans;
297
298static TargetFdTrans **target_fd_trans;
299
300static unsigned int target_fd_max;
301
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200302static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
303{
304 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
305 return target_fd_trans[fd]->target_to_host_data;
306 }
307 return NULL;
308}
309
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100310static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200311{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100312 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100313 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200314 }
315 return NULL;
316}
317
Laurent Vivier7b36f782015-10-28 21:40:44 +0100318static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
319{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100320 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100321 return target_fd_trans[fd]->target_to_host_addr;
322 }
323 return NULL;
324}
325
Laurent Viviere36800c2015-10-02 14:48:09 +0200326static void fd_trans_register(int fd, TargetFdTrans *trans)
327{
328 unsigned int oldmax;
329
330 if (fd >= target_fd_max) {
331 oldmax = target_fd_max;
332 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100333 target_fd_trans = g_renew(TargetFdTrans *,
334 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200335 memset((void *)(target_fd_trans + oldmax), 0,
336 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
337 }
338 target_fd_trans[fd] = trans;
339}
340
341static void fd_trans_unregister(int fd)
342{
343 if (fd >= 0 && fd < target_fd_max) {
344 target_fd_trans[fd] = NULL;
345 }
346}
347
348static void fd_trans_dup(int oldfd, int newfd)
349{
350 fd_trans_unregister(newfd);
351 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
352 fd_trans_register(newfd, target_fd_trans[oldfd]);
353 }
354}
355
aurel323b3f24a2009-04-15 16:12:13 +0000356static int sys_getcwd1(char *buf, size_t size)
357{
358 if (getcwd(buf, size) == NULL) {
359 /* getcwd() sets errno */
360 return (-1);
361 }
aurel32aaf4ad32009-04-16 14:17:14 +0000362 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000363}
364
Peter Maydell1acae9f2013-07-02 14:04:12 +0100365#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300366#ifdef CONFIG_UTIMENSAT
367static int sys_utimensat(int dirfd, const char *pathname,
368 const struct timespec times[2], int flags)
369{
370 if (pathname == NULL)
371 return futimens(dirfd, times);
372 else
373 return utimensat(dirfd, pathname, times, flags);
374}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100375#elif defined(__NR_utimensat)
376#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000377_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
378 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100379#else
380static int sys_utimensat(int dirfd, const char *pathname,
381 const struct timespec times[2], int flags)
382{
383 errno = ENOSYS;
384 return -1;
385}
ths9007f0e2007-09-25 17:50:37 +0000386#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100387#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000388
389#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000390#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000391
aurel3239b59762008-10-01 21:46:50 +0000392#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000393static int sys_inotify_init(void)
394{
395 return (inotify_init());
396}
aurel3239b59762008-10-01 21:46:50 +0000397#endif
398#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000399static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
400{
401 return (inotify_add_watch(fd, pathname, mask));
402}
aurel3239b59762008-10-01 21:46:50 +0000403#endif
404#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000405static int sys_inotify_rm_watch(int fd, int32_t wd)
406{
aurel328690e422009-04-17 13:50:32 +0000407 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000408}
aurel3239b59762008-10-01 21:46:50 +0000409#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000410#ifdef CONFIG_INOTIFY1
411#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
412static int sys_inotify_init1(int flags)
413{
414 return (inotify_init1(flags));
415}
416#endif
417#endif
aurel323b3f24a2009-04-15 16:12:13 +0000418#else
419/* Userspace can usually survive runtime without inotify */
420#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000421#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000422#undef TARGET_NR_inotify_add_watch
423#undef TARGET_NR_inotify_rm_watch
424#endif /* CONFIG_INOTIFY */
425
Peter Maydell163a05a2011-06-27 17:44:52 +0100426#if defined(TARGET_NR_prlimit64)
427#ifndef __NR_prlimit64
428# define __NR_prlimit64 -1
429#endif
430#define __NR_sys_prlimit64 __NR_prlimit64
431/* The glibc rlimit structure may not be that used by the underlying syscall */
432struct host_rlimit64 {
433 uint64_t rlim_cur;
434 uint64_t rlim_max;
435};
436_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
437 const struct host_rlimit64 *, new_limit,
438 struct host_rlimit64 *, old_limit)
439#endif
440
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100441
442#if defined(TARGET_NR_timer_create)
443/* Maxiumum of 32 active POSIX timers allowed at any one time. */
444static timer_t g_posix_timers[32] = { 0, } ;
445
446static inline int next_free_host_timer(void)
447{
448 int k ;
449 /* FIXME: Does finding the next free slot require a lock? */
450 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
451 if (g_posix_timers[k] == 0) {
452 g_posix_timers[k] = (timer_t) 1;
453 return k;
454 }
455 }
456 return -1;
457}
458#endif
459
Riku Voipio48e515d2011-07-12 15:40:51 +0300460/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000461#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300462static inline int regpairs_aligned(void *cpu_env) {
463 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
464}
465#elif defined(TARGET_MIPS)
466static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000467#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
468/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
469 * of registers which translates to the same as ARM/MIPS, because we start with
470 * r3 as arg1 */
471static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300472#else
473static inline int regpairs_aligned(void *cpu_env) { return 0; }
474#endif
475
thsb92c47c2007-11-01 00:07:38 +0000476#define ERRNO_TABLE_SIZE 1200
477
478/* target_to_host_errno_table[] is initialized from
479 * host_to_target_errno_table[] in syscall_init(). */
480static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
481};
482
ths637947f2007-06-01 12:09:19 +0000483/*
thsfe8f0962007-07-12 10:59:21 +0000484 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000485 * minus the errnos that are not actually generic to all archs.
486 */
thsb92c47c2007-11-01 00:07:38 +0000487static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800488 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000489 [EIDRM] = TARGET_EIDRM,
490 [ECHRNG] = TARGET_ECHRNG,
491 [EL2NSYNC] = TARGET_EL2NSYNC,
492 [EL3HLT] = TARGET_EL3HLT,
493 [EL3RST] = TARGET_EL3RST,
494 [ELNRNG] = TARGET_ELNRNG,
495 [EUNATCH] = TARGET_EUNATCH,
496 [ENOCSI] = TARGET_ENOCSI,
497 [EL2HLT] = TARGET_EL2HLT,
498 [EDEADLK] = TARGET_EDEADLK,
499 [ENOLCK] = TARGET_ENOLCK,
500 [EBADE] = TARGET_EBADE,
501 [EBADR] = TARGET_EBADR,
502 [EXFULL] = TARGET_EXFULL,
503 [ENOANO] = TARGET_ENOANO,
504 [EBADRQC] = TARGET_EBADRQC,
505 [EBADSLT] = TARGET_EBADSLT,
506 [EBFONT] = TARGET_EBFONT,
507 [ENOSTR] = TARGET_ENOSTR,
508 [ENODATA] = TARGET_ENODATA,
509 [ETIME] = TARGET_ETIME,
510 [ENOSR] = TARGET_ENOSR,
511 [ENONET] = TARGET_ENONET,
512 [ENOPKG] = TARGET_ENOPKG,
513 [EREMOTE] = TARGET_EREMOTE,
514 [ENOLINK] = TARGET_ENOLINK,
515 [EADV] = TARGET_EADV,
516 [ESRMNT] = TARGET_ESRMNT,
517 [ECOMM] = TARGET_ECOMM,
518 [EPROTO] = TARGET_EPROTO,
519 [EDOTDOT] = TARGET_EDOTDOT,
520 [EMULTIHOP] = TARGET_EMULTIHOP,
521 [EBADMSG] = TARGET_EBADMSG,
522 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
523 [EOVERFLOW] = TARGET_EOVERFLOW,
524 [ENOTUNIQ] = TARGET_ENOTUNIQ,
525 [EBADFD] = TARGET_EBADFD,
526 [EREMCHG] = TARGET_EREMCHG,
527 [ELIBACC] = TARGET_ELIBACC,
528 [ELIBBAD] = TARGET_ELIBBAD,
529 [ELIBSCN] = TARGET_ELIBSCN,
530 [ELIBMAX] = TARGET_ELIBMAX,
531 [ELIBEXEC] = TARGET_ELIBEXEC,
532 [EILSEQ] = TARGET_EILSEQ,
533 [ENOSYS] = TARGET_ENOSYS,
534 [ELOOP] = TARGET_ELOOP,
535 [ERESTART] = TARGET_ERESTART,
536 [ESTRPIPE] = TARGET_ESTRPIPE,
537 [ENOTEMPTY] = TARGET_ENOTEMPTY,
538 [EUSERS] = TARGET_EUSERS,
539 [ENOTSOCK] = TARGET_ENOTSOCK,
540 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
541 [EMSGSIZE] = TARGET_EMSGSIZE,
542 [EPROTOTYPE] = TARGET_EPROTOTYPE,
543 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
544 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
545 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
546 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
547 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
548 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
549 [EADDRINUSE] = TARGET_EADDRINUSE,
550 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
551 [ENETDOWN] = TARGET_ENETDOWN,
552 [ENETUNREACH] = TARGET_ENETUNREACH,
553 [ENETRESET] = TARGET_ENETRESET,
554 [ECONNABORTED] = TARGET_ECONNABORTED,
555 [ECONNRESET] = TARGET_ECONNRESET,
556 [ENOBUFS] = TARGET_ENOBUFS,
557 [EISCONN] = TARGET_EISCONN,
558 [ENOTCONN] = TARGET_ENOTCONN,
559 [EUCLEAN] = TARGET_EUCLEAN,
560 [ENOTNAM] = TARGET_ENOTNAM,
561 [ENAVAIL] = TARGET_ENAVAIL,
562 [EISNAM] = TARGET_EISNAM,
563 [EREMOTEIO] = TARGET_EREMOTEIO,
564 [ESHUTDOWN] = TARGET_ESHUTDOWN,
565 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
566 [ETIMEDOUT] = TARGET_ETIMEDOUT,
567 [ECONNREFUSED] = TARGET_ECONNREFUSED,
568 [EHOSTDOWN] = TARGET_EHOSTDOWN,
569 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
570 [EALREADY] = TARGET_EALREADY,
571 [EINPROGRESS] = TARGET_EINPROGRESS,
572 [ESTALE] = TARGET_ESTALE,
573 [ECANCELED] = TARGET_ECANCELED,
574 [ENOMEDIUM] = TARGET_ENOMEDIUM,
575 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000576#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000577 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000578#endif
579#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000580 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000581#endif
582#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000583 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000584#endif
585#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000586 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000587#endif
588#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000589 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000590#endif
591#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000592 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000593#endif
thsb92c47c2007-11-01 00:07:38 +0000594};
ths637947f2007-06-01 12:09:19 +0000595
596static inline int host_to_target_errno(int err)
597{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100598 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
599 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000600 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100601 }
ths637947f2007-06-01 12:09:19 +0000602 return err;
603}
604
thsb92c47c2007-11-01 00:07:38 +0000605static inline int target_to_host_errno(int err)
606{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100607 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
608 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000609 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100610 }
thsb92c47c2007-11-01 00:07:38 +0000611 return err;
612}
613
blueswir1992f48a2007-10-14 16:27:31 +0000614static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000615{
616 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000617 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000618 else
619 return ret;
620}
621
blueswir1992f48a2007-10-14 16:27:31 +0000622static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000623{
blueswir1992f48a2007-10-14 16:27:31 +0000624 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000625}
626
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100627const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000628{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100629 if (err == TARGET_ERESTARTSYS) {
630 return "To be restarted";
631 }
632 if (err == TARGET_QEMU_ESIGRETURN) {
633 return "Successful exit from sigreturn";
634 }
635
Alexander Graf962b2892011-11-21 12:04:07 +0100636 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
637 return NULL;
638 }
thsb92c47c2007-11-01 00:07:38 +0000639 return strerror(target_to_host_errno(err));
640}
641
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100642#define safe_syscall0(type, name) \
643static type safe_##name(void) \
644{ \
645 return safe_syscall(__NR_##name); \
646}
647
648#define safe_syscall1(type, name, type1, arg1) \
649static type safe_##name(type1 arg1) \
650{ \
651 return safe_syscall(__NR_##name, arg1); \
652}
653
654#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
655static type safe_##name(type1 arg1, type2 arg2) \
656{ \
657 return safe_syscall(__NR_##name, arg1, arg2); \
658}
659
660#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
661static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
662{ \
663 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
664}
665
666#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
667 type4, arg4) \
668static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
669{ \
670 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
671}
672
673#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
674 type4, arg4, type5, arg5) \
675static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
676 type5 arg5) \
677{ \
678 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
679}
680
681#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
682 type4, arg4, type5, arg5, type6, arg6) \
683static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
684 type5 arg5, type6 arg6) \
685{ \
686 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
687}
688
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100689safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
690safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100691safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
692 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100693safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
694 struct rusage *, rusage)
695safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
696 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100697safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100698safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
699 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100700safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
701 struct timespec *, tsp, const sigset_t *, sigmask,
702 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100703safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
704 int, maxevents, int, timeout, const sigset_t *, sigmask,
705 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100706safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
707 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100708safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100709safe_syscall2(int, kill, pid_t, pid, int, sig)
710safe_syscall2(int, tkill, int, tid, int, sig)
711safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100712safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
713safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100714safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
715 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100716safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
717 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
718safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
719 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
720safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
721safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100722safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100723safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
724 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100725safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
726 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100727safe_syscall2(int, nanosleep, const struct timespec *, req,
728 struct timespec *, rem)
729#ifdef TARGET_NR_clock_nanosleep
730safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
731 const struct timespec *, req, struct timespec *, rem)
732#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100733#ifdef __NR_msgsnd
734safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
735 int, flags)
736safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
737 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100738safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
739 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100740#else
741/* This host kernel architecture uses a single ipc syscall; fake up
742 * wrappers for the sub-operations to hide this implementation detail.
743 * Annoyingly we can't include linux/ipc.h to get the constant definitions
744 * for the call parameter because some structs in there conflict with the
745 * sys/ipc.h ones. So we just define them here, and rely on them being
746 * the same for all host architectures.
747 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100748#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100749#define Q_MSGSND 11
750#define Q_MSGRCV 12
751#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
752
753safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
754 void *, ptr, long, fifth)
755static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
756{
757 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
758}
759static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
760{
761 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
762}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100763static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
764 const struct timespec *timeout)
765{
766 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
767 (long)timeout);
768}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100769#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100770#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
771safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
772 size_t, len, unsigned, prio, const struct timespec *, timeout)
773safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
774 size_t, len, unsigned *, prio, const struct timespec *, timeout)
775#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100776/* We do ioctl like this rather than via safe_syscall3 to preserve the
777 * "third argument might be integer or pointer or not present" behaviour of
778 * the libc function.
779 */
780#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100781/* Similarly for fcntl. Note that callers must always:
782 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
783 * use the flock64 struct rather than unsuffixed flock
784 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
785 */
786#ifdef __NR_fcntl64
787#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
788#else
789#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
790#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100791
Paul Burton8289d112014-06-22 11:25:33 +0100792static inline int host_to_target_sock_type(int host_type)
793{
794 int target_type;
795
796 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
797 case SOCK_DGRAM:
798 target_type = TARGET_SOCK_DGRAM;
799 break;
800 case SOCK_STREAM:
801 target_type = TARGET_SOCK_STREAM;
802 break;
803 default:
804 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
805 break;
806 }
807
808#if defined(SOCK_CLOEXEC)
809 if (host_type & SOCK_CLOEXEC) {
810 target_type |= TARGET_SOCK_CLOEXEC;
811 }
812#endif
813
814#if defined(SOCK_NONBLOCK)
815 if (host_type & SOCK_NONBLOCK) {
816 target_type |= TARGET_SOCK_NONBLOCK;
817 }
818#endif
819
820 return target_type;
821}
822
blueswir1992f48a2007-10-14 16:27:31 +0000823static abi_ulong target_brk;
824static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000825static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000826
blueswir1992f48a2007-10-14 16:27:31 +0000827void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000828{
blueswir14c1de732007-07-07 20:45:44 +0000829 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000830 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000831}
832
vincent4d1de872011-06-14 21:56:33 +0000833//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
834#define DEBUGF_BRK(message, args...)
835
ths0da46a62007-10-20 20:23:07 +0000836/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000837abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000838{
blueswir1992f48a2007-10-14 16:27:31 +0000839 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000840 int new_alloc_size;
841
Paul Brook3a0c6c42012-02-09 19:04:27 +0000842 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000843
vincent4d1de872011-06-14 21:56:33 +0000844 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000845 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000846 return target_brk;
847 }
848 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000849 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
850 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000851 return target_brk;
852 }
bellard31e31b82003-02-18 22:55:36 +0000853
vincent4d1de872011-06-14 21:56:33 +0000854 /* If the new brk is less than the highest page reserved to the
855 * target heap allocation, set it and we're almost done... */
856 if (new_brk <= brk_page) {
857 /* Heap contents are initialized to zero, as for anonymous
858 * mapped pages. */
859 if (new_brk > target_brk) {
860 memset(g2h(target_brk), 0, new_brk - target_brk);
861 }
bellard31e31b82003-02-18 22:55:36 +0000862 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000863 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000864 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000865 }
866
Peter Maydell00faf082011-04-18 16:34:24 +0100867 /* We need to allocate more memory after the brk... Note that
868 * we don't use MAP_FIXED because that will map over the top of
869 * any existing mapping (like the one with the host libc or qemu
870 * itself); instead we treat "mapped but at wrong address" as
871 * a failure and unmap again.
872 */
vincent4d1de872011-06-14 21:56:33 +0000873 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000874 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000875 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100876 MAP_ANON|MAP_PRIVATE, 0, 0));
877
878 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200879 /* Heap contents are initialized to zero, as for anonymous
880 * mapped pages. Technically the new pages are already
881 * initialized to zero since they *are* anonymous mapped
882 * pages, however we have to take care with the contents that
883 * come from the remaining part of the previous page: it may
884 * contains garbage data due to a previous heap usage (grown
885 * then shrunken). */
886 memset(g2h(target_brk), 0, brk_page - target_brk);
887
Peter Maydell00faf082011-04-18 16:34:24 +0100888 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000889 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000890 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
891 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100892 return target_brk;
893 } else if (mapped_addr != -1) {
894 /* Mapped but at wrong address, meaning there wasn't actually
895 * enough space for this brk.
896 */
897 target_munmap(mapped_addr, new_alloc_size);
898 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000899 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000900 }
901 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000902 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100903 }
balrog7ab240a2008-04-26 12:17:34 +0000904
Richard Henderson7dd46c02010-05-03 10:07:49 -0700905#if defined(TARGET_ALPHA)
906 /* We (partially) emulate OSF/1 on Alpha, which requires we
907 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100908 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700909#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100910 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000911 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000912}
913
ths26edcf42007-12-09 02:25:24 +0000914static inline abi_long copy_from_user_fdset(fd_set *fds,
915 abi_ulong target_fds_addr,
916 int n)
bellard31e31b82003-02-18 22:55:36 +0000917{
ths26edcf42007-12-09 02:25:24 +0000918 int i, nw, j, k;
919 abi_ulong b, *target_fds;
920
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200921 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000922 if (!(target_fds = lock_user(VERIFY_READ,
923 target_fds_addr,
924 sizeof(abi_ulong) * nw,
925 1)))
926 return -TARGET_EFAULT;
927
928 FD_ZERO(fds);
929 k = 0;
930 for (i = 0; i < nw; i++) {
931 /* grab the abi_ulong */
932 __get_user(b, &target_fds[i]);
933 for (j = 0; j < TARGET_ABI_BITS; j++) {
934 /* check the bit inside the abi_ulong */
935 if ((b >> j) & 1)
936 FD_SET(k, fds);
937 k++;
bellard31e31b82003-02-18 22:55:36 +0000938 }
bellard31e31b82003-02-18 22:55:36 +0000939 }
ths26edcf42007-12-09 02:25:24 +0000940
941 unlock_user(target_fds, target_fds_addr, 0);
942
943 return 0;
bellard31e31b82003-02-18 22:55:36 +0000944}
945
Mike Frysinger055e0902011-06-03 17:01:49 -0400946static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
947 abi_ulong target_fds_addr,
948 int n)
949{
950 if (target_fds_addr) {
951 if (copy_from_user_fdset(fds, target_fds_addr, n))
952 return -TARGET_EFAULT;
953 *fds_ptr = fds;
954 } else {
955 *fds_ptr = NULL;
956 }
957 return 0;
958}
959
ths26edcf42007-12-09 02:25:24 +0000960static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
961 const fd_set *fds,
962 int n)
bellard31e31b82003-02-18 22:55:36 +0000963{
bellard31e31b82003-02-18 22:55:36 +0000964 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000965 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000966 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000967
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200968 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000969 if (!(target_fds = lock_user(VERIFY_WRITE,
970 target_fds_addr,
971 sizeof(abi_ulong) * nw,
972 0)))
973 return -TARGET_EFAULT;
974
975 k = 0;
976 for (i = 0; i < nw; i++) {
977 v = 0;
978 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000979 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000980 k++;
bellard31e31b82003-02-18 22:55:36 +0000981 }
ths26edcf42007-12-09 02:25:24 +0000982 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000983 }
ths26edcf42007-12-09 02:25:24 +0000984
985 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
986
987 return 0;
bellard31e31b82003-02-18 22:55:36 +0000988}
989
bellardc596ed12003-07-13 17:32:31 +0000990#if defined(__alpha__)
991#define HOST_HZ 1024
992#else
993#define HOST_HZ 100
994#endif
995
blueswir1992f48a2007-10-14 16:27:31 +0000996static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000997{
998#if HOST_HZ == TARGET_HZ
999 return ticks;
1000#else
1001 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1002#endif
1003}
1004
bellard579a97f2007-11-11 14:26:47 +00001005static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1006 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001007{
pbrook53a59602006-03-25 19:31:22 +00001008 struct target_rusage *target_rusage;
1009
bellard579a97f2007-11-11 14:26:47 +00001010 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1011 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001012 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1013 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1014 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1015 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1016 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1017 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1018 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1019 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1020 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1021 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1022 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1023 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1024 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1025 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1026 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1027 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1028 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1029 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001030 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001031
1032 return 0;
bellardb4091862003-05-16 15:39:34 +00001033}
1034
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001035static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001036{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001037 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001038 rlim_t result;
1039
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001040 target_rlim_swap = tswapal(target_rlim);
1041 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1042 return RLIM_INFINITY;
1043
1044 result = target_rlim_swap;
1045 if (target_rlim_swap != (rlim_t)result)
1046 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001047
1048 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001049}
1050
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001051static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001052{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001053 abi_ulong target_rlim_swap;
1054 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001055
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001056 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001057 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001058 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001059 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001060 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001061
1062 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001063}
1064
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001065static inline int target_to_host_resource(int code)
1066{
1067 switch (code) {
1068 case TARGET_RLIMIT_AS:
1069 return RLIMIT_AS;
1070 case TARGET_RLIMIT_CORE:
1071 return RLIMIT_CORE;
1072 case TARGET_RLIMIT_CPU:
1073 return RLIMIT_CPU;
1074 case TARGET_RLIMIT_DATA:
1075 return RLIMIT_DATA;
1076 case TARGET_RLIMIT_FSIZE:
1077 return RLIMIT_FSIZE;
1078 case TARGET_RLIMIT_LOCKS:
1079 return RLIMIT_LOCKS;
1080 case TARGET_RLIMIT_MEMLOCK:
1081 return RLIMIT_MEMLOCK;
1082 case TARGET_RLIMIT_MSGQUEUE:
1083 return RLIMIT_MSGQUEUE;
1084 case TARGET_RLIMIT_NICE:
1085 return RLIMIT_NICE;
1086 case TARGET_RLIMIT_NOFILE:
1087 return RLIMIT_NOFILE;
1088 case TARGET_RLIMIT_NPROC:
1089 return RLIMIT_NPROC;
1090 case TARGET_RLIMIT_RSS:
1091 return RLIMIT_RSS;
1092 case TARGET_RLIMIT_RTPRIO:
1093 return RLIMIT_RTPRIO;
1094 case TARGET_RLIMIT_SIGPENDING:
1095 return RLIMIT_SIGPENDING;
1096 case TARGET_RLIMIT_STACK:
1097 return RLIMIT_STACK;
1098 default:
1099 return code;
1100 }
1101}
1102
ths788f5ec2007-12-09 02:37:05 +00001103static inline abi_long copy_from_user_timeval(struct timeval *tv,
1104 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001105{
pbrook53a59602006-03-25 19:31:22 +00001106 struct target_timeval *target_tv;
1107
ths788f5ec2007-12-09 02:37:05 +00001108 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001109 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001110
1111 __get_user(tv->tv_sec, &target_tv->tv_sec);
1112 __get_user(tv->tv_usec, &target_tv->tv_usec);
1113
1114 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001115
1116 return 0;
bellard31e31b82003-02-18 22:55:36 +00001117}
1118
ths788f5ec2007-12-09 02:37:05 +00001119static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1120 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001121{
pbrook53a59602006-03-25 19:31:22 +00001122 struct target_timeval *target_tv;
1123
ths788f5ec2007-12-09 02:37:05 +00001124 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001125 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001126
1127 __put_user(tv->tv_sec, &target_tv->tv_sec);
1128 __put_user(tv->tv_usec, &target_tv->tv_usec);
1129
1130 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001131
1132 return 0;
bellard31e31b82003-02-18 22:55:36 +00001133}
1134
Paul Burtonef4467e2014-06-22 11:25:40 +01001135static inline abi_long copy_from_user_timezone(struct timezone *tz,
1136 abi_ulong target_tz_addr)
1137{
1138 struct target_timezone *target_tz;
1139
1140 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1141 return -TARGET_EFAULT;
1142 }
1143
1144 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1145 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1146
1147 unlock_user_struct(target_tz, target_tz_addr, 0);
1148
1149 return 0;
1150}
1151
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001152#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1153#include <mqueue.h>
1154
aurel3224e10032009-04-15 16:11:43 +00001155static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1156 abi_ulong target_mq_attr_addr)
1157{
1158 struct target_mq_attr *target_mq_attr;
1159
1160 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1161 target_mq_attr_addr, 1))
1162 return -TARGET_EFAULT;
1163
1164 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1165 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1166 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1167 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1168
1169 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1170
1171 return 0;
1172}
1173
1174static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1175 const struct mq_attr *attr)
1176{
1177 struct target_mq_attr *target_mq_attr;
1178
1179 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1180 target_mq_attr_addr, 0))
1181 return -TARGET_EFAULT;
1182
1183 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1184 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1185 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1186 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1187
1188 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1189
1190 return 0;
1191}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001192#endif
bellard31e31b82003-02-18 22:55:36 +00001193
Mike Frysinger055e0902011-06-03 17:01:49 -04001194#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001195/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001196static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001197 abi_ulong rfd_addr, abi_ulong wfd_addr,
1198 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001199{
1200 fd_set rfds, wfds, efds;
1201 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001202 struct timeval tv;
1203 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001204 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001205
Mike Frysinger055e0902011-06-03 17:01:49 -04001206 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1207 if (ret) {
1208 return ret;
pbrook53a59602006-03-25 19:31:22 +00001209 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001210 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1211 if (ret) {
1212 return ret;
pbrook53a59602006-03-25 19:31:22 +00001213 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001214 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1215 if (ret) {
1216 return ret;
pbrook53a59602006-03-25 19:31:22 +00001217 }
ths3b46e622007-09-17 08:09:54 +00001218
ths26edcf42007-12-09 02:25:24 +00001219 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001220 if (copy_from_user_timeval(&tv, target_tv_addr))
1221 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001222 ts.tv_sec = tv.tv_sec;
1223 ts.tv_nsec = tv.tv_usec * 1000;
1224 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001225 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001226 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001227 }
ths26edcf42007-12-09 02:25:24 +00001228
Peter Maydell6df9d382016-05-12 18:47:51 +01001229 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1230 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001231
ths26edcf42007-12-09 02:25:24 +00001232 if (!is_error(ret)) {
1233 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1234 return -TARGET_EFAULT;
1235 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1236 return -TARGET_EFAULT;
1237 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1238 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001239
Peter Maydell6df9d382016-05-12 18:47:51 +01001240 if (target_tv_addr) {
1241 tv.tv_sec = ts.tv_sec;
1242 tv.tv_usec = ts.tv_nsec / 1000;
1243 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1244 return -TARGET_EFAULT;
1245 }
1246 }
bellard31e31b82003-02-18 22:55:36 +00001247 }
bellard579a97f2007-11-11 14:26:47 +00001248
bellard31e31b82003-02-18 22:55:36 +00001249 return ret;
1250}
Mike Frysinger055e0902011-06-03 17:01:49 -04001251#endif
bellard31e31b82003-02-18 22:55:36 +00001252
Riku Voipio099d6b02009-05-05 12:10:04 +03001253static abi_long do_pipe2(int host_pipe[], int flags)
1254{
1255#ifdef CONFIG_PIPE2
1256 return pipe2(host_pipe, flags);
1257#else
1258 return -ENOSYS;
1259#endif
1260}
1261
Richard Hendersonfb41a662010-05-03 10:07:52 -07001262static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1263 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001264{
1265 int host_pipe[2];
1266 abi_long ret;
1267 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1268
1269 if (is_error(ret))
1270 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001271
1272 /* Several targets have special calling conventions for the original
1273 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1274 if (!is_pipe2) {
1275#if defined(TARGET_ALPHA)
1276 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1277 return host_pipe[0];
1278#elif defined(TARGET_MIPS)
1279 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1280 return host_pipe[0];
1281#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001282 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001283 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001284#elif defined(TARGET_SPARC)
1285 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1286 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001287#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001288 }
1289
Riku Voipio099d6b02009-05-05 12:10:04 +03001290 if (put_user_s32(host_pipe[0], pipedes)
1291 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1292 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001293 return get_errno(ret);
1294}
1295
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001296static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1297 abi_ulong target_addr,
1298 socklen_t len)
1299{
1300 struct target_ip_mreqn *target_smreqn;
1301
1302 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1303 if (!target_smreqn)
1304 return -TARGET_EFAULT;
1305 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1306 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1307 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001308 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001309 unlock_user(target_smreqn, target_addr, 0);
1310
1311 return 0;
1312}
1313
Laurent Vivier7b36f782015-10-28 21:40:44 +01001314static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001315 abi_ulong target_addr,
1316 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001317{
aurel32607175e2009-04-15 16:11:59 +00001318 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1319 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001320 struct target_sockaddr *target_saddr;
1321
Laurent Vivier7b36f782015-10-28 21:40:44 +01001322 if (fd_trans_target_to_host_addr(fd)) {
1323 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1324 }
1325
bellard579a97f2007-11-11 14:26:47 +00001326 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1327 if (!target_saddr)
1328 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001329
1330 sa_family = tswap16(target_saddr->sa_family);
1331
1332 /* Oops. The caller might send a incomplete sun_path; sun_path
1333 * must be terminated by \0 (see the manual page), but
1334 * unfortunately it is quite common to specify sockaddr_un
1335 * length as "strlen(x->sun_path)" while it should be
1336 * "strlen(...) + 1". We'll fix that here if needed.
1337 * Linux kernel has a similar feature.
1338 */
1339
1340 if (sa_family == AF_UNIX) {
1341 if (len < unix_maxlen && len > 0) {
1342 char *cp = (char*)target_saddr;
1343
1344 if ( cp[len-1] && !cp[len] )
1345 len++;
1346 }
1347 if (len > unix_maxlen)
1348 len = unix_maxlen;
1349 }
1350
pbrook53a59602006-03-25 19:31:22 +00001351 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001352 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001353 if (sa_family == AF_NETLINK) {
1354 struct sockaddr_nl *nladdr;
1355
1356 nladdr = (struct sockaddr_nl *)addr;
1357 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1358 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1359 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001360 struct target_sockaddr_ll *lladdr;
1361
1362 lladdr = (struct target_sockaddr_ll *)addr;
1363 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1364 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1365 }
pbrook53a59602006-03-25 19:31:22 +00001366 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001367
1368 return 0;
bellard7854b052003-03-29 17:22:23 +00001369}
1370
bellard579a97f2007-11-11 14:26:47 +00001371static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1372 struct sockaddr *addr,
1373 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001374{
pbrook53a59602006-03-25 19:31:22 +00001375 struct target_sockaddr *target_saddr;
1376
bellard579a97f2007-11-11 14:26:47 +00001377 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1378 if (!target_saddr)
1379 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001380 memcpy(target_saddr, addr, len);
1381 target_saddr->sa_family = tswap16(addr->sa_family);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001382 if (addr->sa_family == AF_NETLINK) {
1383 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1384 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1385 target_nl->nl_groups = tswap32(target_nl->nl_groups);
1386 }
pbrook53a59602006-03-25 19:31:22 +00001387 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001388
1389 return 0;
bellard7854b052003-03-29 17:22:23 +00001390}
1391
bellard5a4a8982007-11-11 17:39:18 +00001392static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1393 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001394{
1395 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001396 abi_long msg_controllen;
1397 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001398 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001399 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001400
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001401 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001402 if (msg_controllen < sizeof (struct target_cmsghdr))
1403 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001404 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001405 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001406 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001407 if (!target_cmsg)
1408 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001409
1410 while (cmsg && target_cmsg) {
1411 void *data = CMSG_DATA(cmsg);
1412 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1413
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001414 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001415 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1416
1417 space += CMSG_SPACE(len);
1418 if (space > msgh->msg_controllen) {
1419 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001420 /* This is a QEMU bug, since we allocated the payload
1421 * area ourselves (unlike overflow in host-to-target
1422 * conversion, which is just the guest giving us a buffer
1423 * that's too small). It can't happen for the payload types
1424 * we currently support; if it becomes an issue in future
1425 * we would need to improve our allocation strategy to
1426 * something more intelligent than "twice the size of the
1427 * target buffer we're reading from".
1428 */
bellard31febb72005-12-18 20:03:27 +00001429 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001430 break;
1431 }
1432
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001433 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1434 cmsg->cmsg_level = SOL_SOCKET;
1435 } else {
1436 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1437 }
bellard7854b052003-03-29 17:22:23 +00001438 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1439 cmsg->cmsg_len = CMSG_LEN(len);
1440
Alex Suykov30b8b682014-12-23 07:52:58 +02001441 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001442 int *fd = (int *)data;
1443 int *target_fd = (int *)target_data;
1444 int i, numfds = len / sizeof(int);
1445
Peter Maydell876e23c2015-05-26 19:46:32 +01001446 for (i = 0; i < numfds; i++) {
1447 __get_user(fd[i], target_fd + i);
1448 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001449 } else if (cmsg->cmsg_level == SOL_SOCKET
1450 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1451 struct ucred *cred = (struct ucred *)data;
1452 struct target_ucred *target_cred =
1453 (struct target_ucred *)target_data;
1454
Peter Maydell876e23c2015-05-26 19:46:32 +01001455 __get_user(cred->pid, &target_cred->pid);
1456 __get_user(cred->uid, &target_cred->uid);
1457 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001458 } else {
1459 gemu_log("Unsupported ancillary data: %d/%d\n",
1460 cmsg->cmsg_level, cmsg->cmsg_type);
1461 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001462 }
1463
1464 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001465 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1466 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001467 }
bellard5a4a8982007-11-11 17:39:18 +00001468 unlock_user(target_cmsg, target_cmsg_addr, 0);
1469 the_end:
bellard7854b052003-03-29 17:22:23 +00001470 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001471 return 0;
bellard7854b052003-03-29 17:22:23 +00001472}
1473
bellard5a4a8982007-11-11 17:39:18 +00001474static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1475 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001476{
1477 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001478 abi_long msg_controllen;
1479 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001480 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001481 socklen_t space = 0;
1482
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001483 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001484 if (msg_controllen < sizeof (struct target_cmsghdr))
1485 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001486 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001487 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001488 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001489 if (!target_cmsg)
1490 return -TARGET_EFAULT;
1491
bellard7854b052003-03-29 17:22:23 +00001492 while (cmsg && target_cmsg) {
1493 void *data = CMSG_DATA(cmsg);
1494 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1495
1496 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001497 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001498
Peter Maydellc2aeb252015-05-26 19:46:31 +01001499 /* We never copy a half-header but may copy half-data;
1500 * this is Linux's behaviour in put_cmsg(). Note that
1501 * truncation here is a guest problem (which we report
1502 * to the guest via the CTRUNC bit), unlike truncation
1503 * in target_to_host_cmsg, which is a QEMU bug.
1504 */
1505 if (msg_controllen < sizeof(struct cmsghdr)) {
1506 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001507 break;
1508 }
1509
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001510 if (cmsg->cmsg_level == SOL_SOCKET) {
1511 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1512 } else {
1513 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1514 }
bellard7854b052003-03-29 17:22:23 +00001515 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001516
Peter Maydellc2aeb252015-05-26 19:46:31 +01001517 tgt_len = TARGET_CMSG_LEN(len);
1518
1519 /* Payload types which need a different size of payload on
1520 * the target must adjust tgt_len here.
1521 */
1522 switch (cmsg->cmsg_level) {
1523 case SOL_SOCKET:
1524 switch (cmsg->cmsg_type) {
1525 case SO_TIMESTAMP:
1526 tgt_len = sizeof(struct target_timeval);
1527 break;
1528 default:
1529 break;
1530 }
1531 default:
1532 break;
1533 }
1534
1535 if (msg_controllen < tgt_len) {
1536 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1537 tgt_len = msg_controllen;
1538 }
1539
1540 /* We must now copy-and-convert len bytes of payload
1541 * into tgt_len bytes of destination space. Bear in mind
1542 * that in both source and destination we may be dealing
1543 * with a truncated value!
1544 */
Huw Davies52b65492014-04-17 14:02:47 +01001545 switch (cmsg->cmsg_level) {
1546 case SOL_SOCKET:
1547 switch (cmsg->cmsg_type) {
1548 case SCM_RIGHTS:
1549 {
1550 int *fd = (int *)data;
1551 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001552 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001553
Peter Maydell876e23c2015-05-26 19:46:32 +01001554 for (i = 0; i < numfds; i++) {
1555 __put_user(fd[i], target_fd + i);
1556 }
Huw Davies52b65492014-04-17 14:02:47 +01001557 break;
1558 }
1559 case SO_TIMESTAMP:
1560 {
1561 struct timeval *tv = (struct timeval *)data;
1562 struct target_timeval *target_tv =
1563 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001564
Peter Maydellc2aeb252015-05-26 19:46:31 +01001565 if (len != sizeof(struct timeval) ||
1566 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001567 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001568 }
Huw Davies52b65492014-04-17 14:02:47 +01001569
1570 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001571 __put_user(tv->tv_sec, &target_tv->tv_sec);
1572 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001573 break;
1574 }
Huw Davies4bc29752014-04-17 14:02:48 +01001575 case SCM_CREDENTIALS:
1576 {
1577 struct ucred *cred = (struct ucred *)data;
1578 struct target_ucred *target_cred =
1579 (struct target_ucred *)target_data;
1580
1581 __put_user(cred->pid, &target_cred->pid);
1582 __put_user(cred->uid, &target_cred->uid);
1583 __put_user(cred->gid, &target_cred->gid);
1584 break;
1585 }
Huw Davies52b65492014-04-17 14:02:47 +01001586 default:
1587 goto unimplemented;
1588 }
1589 break;
1590
1591 default:
1592 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001593 gemu_log("Unsupported ancillary data: %d/%d\n",
1594 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001595 memcpy(target_data, data, MIN(len, tgt_len));
1596 if (tgt_len > len) {
1597 memset(target_data + len, 0, tgt_len - len);
1598 }
bellard7854b052003-03-29 17:22:23 +00001599 }
1600
Peter Maydellc2aeb252015-05-26 19:46:31 +01001601 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001602 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001603 if (msg_controllen < tgt_space) {
1604 tgt_space = msg_controllen;
1605 }
1606 msg_controllen -= tgt_space;
1607 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001608 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001609 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1610 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001611 }
bellard5a4a8982007-11-11 17:39:18 +00001612 unlock_user(target_cmsg, target_cmsg_addr, space);
1613 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001614 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001615 return 0;
bellard7854b052003-03-29 17:22:23 +00001616}
1617
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001618static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1619{
1620 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1621 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1622 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1623 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1624 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1625}
1626
1627static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1628 size_t len,
1629 abi_long (*host_to_target_nlmsg)
1630 (struct nlmsghdr *))
1631{
1632 uint32_t nlmsg_len;
1633 abi_long ret;
1634
1635 while (len > sizeof(struct nlmsghdr)) {
1636
1637 nlmsg_len = nlh->nlmsg_len;
1638 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1639 nlmsg_len > len) {
1640 break;
1641 }
1642
1643 switch (nlh->nlmsg_type) {
1644 case NLMSG_DONE:
1645 tswap_nlmsghdr(nlh);
1646 return 0;
1647 case NLMSG_NOOP:
1648 break;
1649 case NLMSG_ERROR:
1650 {
1651 struct nlmsgerr *e = NLMSG_DATA(nlh);
1652 e->error = tswap32(e->error);
1653 tswap_nlmsghdr(&e->msg);
1654 tswap_nlmsghdr(nlh);
1655 return 0;
1656 }
1657 default:
1658 ret = host_to_target_nlmsg(nlh);
1659 if (ret < 0) {
1660 tswap_nlmsghdr(nlh);
1661 return ret;
1662 }
1663 break;
1664 }
1665 tswap_nlmsghdr(nlh);
1666 len -= NLMSG_ALIGN(nlmsg_len);
1667 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1668 }
1669 return 0;
1670}
1671
1672static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1673 size_t len,
1674 abi_long (*target_to_host_nlmsg)
1675 (struct nlmsghdr *))
1676{
1677 int ret;
1678
1679 while (len > sizeof(struct nlmsghdr)) {
1680 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1681 tswap32(nlh->nlmsg_len) > len) {
1682 break;
1683 }
1684 tswap_nlmsghdr(nlh);
1685 switch (nlh->nlmsg_type) {
1686 case NLMSG_DONE:
1687 return 0;
1688 case NLMSG_NOOP:
1689 break;
1690 case NLMSG_ERROR:
1691 {
1692 struct nlmsgerr *e = NLMSG_DATA(nlh);
1693 e->error = tswap32(e->error);
1694 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02001695 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001696 }
1697 default:
1698 ret = target_to_host_nlmsg(nlh);
1699 if (ret < 0) {
1700 return ret;
1701 }
1702 }
1703 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1704 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1705 }
1706 return 0;
1707}
1708
Laurent Vivier575b22b2016-06-02 22:14:15 +02001709#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001710static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1711 size_t len,
1712 abi_long (*host_to_target_rtattr)
1713 (struct rtattr *))
1714{
1715 unsigned short rta_len;
1716 abi_long ret;
1717
1718 while (len > sizeof(struct rtattr)) {
1719 rta_len = rtattr->rta_len;
1720 if (rta_len < sizeof(struct rtattr) ||
1721 rta_len > len) {
1722 break;
1723 }
1724 ret = host_to_target_rtattr(rtattr);
1725 rtattr->rta_len = tswap16(rtattr->rta_len);
1726 rtattr->rta_type = tswap16(rtattr->rta_type);
1727 if (ret < 0) {
1728 return ret;
1729 }
1730 len -= RTA_ALIGN(rta_len);
1731 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1732 }
1733 return 0;
1734}
1735
1736static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
1737{
1738 uint32_t *u32;
1739 struct rtnl_link_stats *st;
1740 struct rtnl_link_stats64 *st64;
1741 struct rtnl_link_ifmap *map;
1742
1743 switch (rtattr->rta_type) {
1744 /* binary stream */
1745 case IFLA_ADDRESS:
1746 case IFLA_BROADCAST:
1747 /* string */
1748 case IFLA_IFNAME:
1749 case IFLA_QDISC:
1750 break;
1751 /* uin8_t */
1752 case IFLA_OPERSTATE:
1753 case IFLA_LINKMODE:
1754 case IFLA_CARRIER:
1755 case IFLA_PROTO_DOWN:
1756 break;
1757 /* uint32_t */
1758 case IFLA_MTU:
1759 case IFLA_LINK:
1760 case IFLA_WEIGHT:
1761 case IFLA_TXQLEN:
1762 case IFLA_CARRIER_CHANGES:
1763 case IFLA_NUM_RX_QUEUES:
1764 case IFLA_NUM_TX_QUEUES:
1765 case IFLA_PROMISCUITY:
1766 case IFLA_EXT_MASK:
1767 case IFLA_LINK_NETNSID:
1768 case IFLA_GROUP:
1769 case IFLA_MASTER:
1770 case IFLA_NUM_VF:
1771 u32 = RTA_DATA(rtattr);
1772 *u32 = tswap32(*u32);
1773 break;
1774 /* struct rtnl_link_stats */
1775 case IFLA_STATS:
1776 st = RTA_DATA(rtattr);
1777 st->rx_packets = tswap32(st->rx_packets);
1778 st->tx_packets = tswap32(st->tx_packets);
1779 st->rx_bytes = tswap32(st->rx_bytes);
1780 st->tx_bytes = tswap32(st->tx_bytes);
1781 st->rx_errors = tswap32(st->rx_errors);
1782 st->tx_errors = tswap32(st->tx_errors);
1783 st->rx_dropped = tswap32(st->rx_dropped);
1784 st->tx_dropped = tswap32(st->tx_dropped);
1785 st->multicast = tswap32(st->multicast);
1786 st->collisions = tswap32(st->collisions);
1787
1788 /* detailed rx_errors: */
1789 st->rx_length_errors = tswap32(st->rx_length_errors);
1790 st->rx_over_errors = tswap32(st->rx_over_errors);
1791 st->rx_crc_errors = tswap32(st->rx_crc_errors);
1792 st->rx_frame_errors = tswap32(st->rx_frame_errors);
1793 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
1794 st->rx_missed_errors = tswap32(st->rx_missed_errors);
1795
1796 /* detailed tx_errors */
1797 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
1798 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
1799 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
1800 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
1801 st->tx_window_errors = tswap32(st->tx_window_errors);
1802
1803 /* for cslip etc */
1804 st->rx_compressed = tswap32(st->rx_compressed);
1805 st->tx_compressed = tswap32(st->tx_compressed);
1806 break;
1807 /* struct rtnl_link_stats64 */
1808 case IFLA_STATS64:
1809 st64 = RTA_DATA(rtattr);
1810 st64->rx_packets = tswap64(st64->rx_packets);
1811 st64->tx_packets = tswap64(st64->tx_packets);
1812 st64->rx_bytes = tswap64(st64->rx_bytes);
1813 st64->tx_bytes = tswap64(st64->tx_bytes);
1814 st64->rx_errors = tswap64(st64->rx_errors);
1815 st64->tx_errors = tswap64(st64->tx_errors);
1816 st64->rx_dropped = tswap64(st64->rx_dropped);
1817 st64->tx_dropped = tswap64(st64->tx_dropped);
1818 st64->multicast = tswap64(st64->multicast);
1819 st64->collisions = tswap64(st64->collisions);
1820
1821 /* detailed rx_errors: */
1822 st64->rx_length_errors = tswap64(st64->rx_length_errors);
1823 st64->rx_over_errors = tswap64(st64->rx_over_errors);
1824 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
1825 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
1826 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
1827 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
1828
1829 /* detailed tx_errors */
1830 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
1831 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
1832 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
1833 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
1834 st64->tx_window_errors = tswap64(st64->tx_window_errors);
1835
1836 /* for cslip etc */
1837 st64->rx_compressed = tswap64(st64->rx_compressed);
1838 st64->tx_compressed = tswap64(st64->tx_compressed);
1839 break;
1840 /* struct rtnl_link_ifmap */
1841 case IFLA_MAP:
1842 map = RTA_DATA(rtattr);
1843 map->mem_start = tswap64(map->mem_start);
1844 map->mem_end = tswap64(map->mem_end);
1845 map->base_addr = tswap64(map->base_addr);
1846 map->irq = tswap16(map->irq);
1847 break;
1848 /* nested */
1849 case IFLA_AF_SPEC:
1850 case IFLA_LINKINFO:
1851 /* FIXME: implement nested type */
1852 gemu_log("Unimplemented nested type %d\n", rtattr->rta_type);
1853 break;
1854 default:
1855 gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type);
1856 break;
1857 }
1858 return 0;
1859}
1860
1861static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
1862{
1863 uint32_t *u32;
1864 struct ifa_cacheinfo *ci;
1865
1866 switch (rtattr->rta_type) {
1867 /* binary: depends on family type */
1868 case IFA_ADDRESS:
1869 case IFA_LOCAL:
1870 break;
1871 /* string */
1872 case IFA_LABEL:
1873 break;
1874 /* u32 */
1875 case IFA_FLAGS:
1876 case IFA_BROADCAST:
1877 u32 = RTA_DATA(rtattr);
1878 *u32 = tswap32(*u32);
1879 break;
1880 /* struct ifa_cacheinfo */
1881 case IFA_CACHEINFO:
1882 ci = RTA_DATA(rtattr);
1883 ci->ifa_prefered = tswap32(ci->ifa_prefered);
1884 ci->ifa_valid = tswap32(ci->ifa_valid);
1885 ci->cstamp = tswap32(ci->cstamp);
1886 ci->tstamp = tswap32(ci->tstamp);
1887 break;
1888 default:
1889 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
1890 break;
1891 }
1892 return 0;
1893}
1894
1895static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
1896{
1897 uint32_t *u32;
1898 switch (rtattr->rta_type) {
1899 /* binary: depends on family type */
1900 case RTA_GATEWAY:
1901 case RTA_DST:
1902 case RTA_PREFSRC:
1903 break;
1904 /* u32 */
1905 case RTA_PRIORITY:
1906 case RTA_TABLE:
1907 case RTA_OIF:
1908 u32 = RTA_DATA(rtattr);
1909 *u32 = tswap32(*u32);
1910 break;
1911 default:
1912 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
1913 break;
1914 }
1915 return 0;
1916}
1917
1918static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
1919 uint32_t rtattr_len)
1920{
1921 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1922 host_to_target_data_link_rtattr);
1923}
1924
1925static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
1926 uint32_t rtattr_len)
1927{
1928 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1929 host_to_target_data_addr_rtattr);
1930}
1931
1932static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
1933 uint32_t rtattr_len)
1934{
1935 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1936 host_to_target_data_route_rtattr);
1937}
1938
1939static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
1940{
1941 uint32_t nlmsg_len;
1942 struct ifinfomsg *ifi;
1943 struct ifaddrmsg *ifa;
1944 struct rtmsg *rtm;
1945
1946 nlmsg_len = nlh->nlmsg_len;
1947 switch (nlh->nlmsg_type) {
1948 case RTM_NEWLINK:
1949 case RTM_DELLINK:
1950 case RTM_GETLINK:
1951 ifi = NLMSG_DATA(nlh);
1952 ifi->ifi_type = tswap16(ifi->ifi_type);
1953 ifi->ifi_index = tswap32(ifi->ifi_index);
1954 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1955 ifi->ifi_change = tswap32(ifi->ifi_change);
1956 host_to_target_link_rtattr(IFLA_RTA(ifi),
1957 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1958 break;
1959 case RTM_NEWADDR:
1960 case RTM_DELADDR:
1961 case RTM_GETADDR:
1962 ifa = NLMSG_DATA(nlh);
1963 ifa->ifa_index = tswap32(ifa->ifa_index);
1964 host_to_target_addr_rtattr(IFA_RTA(ifa),
1965 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1966 break;
1967 case RTM_NEWROUTE:
1968 case RTM_DELROUTE:
1969 case RTM_GETROUTE:
1970 rtm = NLMSG_DATA(nlh);
1971 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1972 host_to_target_route_rtattr(RTM_RTA(rtm),
1973 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1974 break;
1975 default:
1976 return -TARGET_EINVAL;
1977 }
1978 return 0;
1979}
1980
1981static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1982 size_t len)
1983{
1984 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1985}
1986
1987static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1988 size_t len,
1989 abi_long (*target_to_host_rtattr)
1990 (struct rtattr *))
1991{
1992 abi_long ret;
1993
1994 while (len >= sizeof(struct rtattr)) {
1995 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
1996 tswap16(rtattr->rta_len) > len) {
1997 break;
1998 }
1999 rtattr->rta_len = tswap16(rtattr->rta_len);
2000 rtattr->rta_type = tswap16(rtattr->rta_type);
2001 ret = target_to_host_rtattr(rtattr);
2002 if (ret < 0) {
2003 return ret;
2004 }
2005 len -= RTA_ALIGN(rtattr->rta_len);
2006 rtattr = (struct rtattr *)(((char *)rtattr) +
2007 RTA_ALIGN(rtattr->rta_len));
2008 }
2009 return 0;
2010}
2011
2012static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2013{
2014 switch (rtattr->rta_type) {
2015 default:
2016 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
2017 break;
2018 }
2019 return 0;
2020}
2021
2022static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2023{
2024 switch (rtattr->rta_type) {
2025 /* binary: depends on family type */
2026 case IFA_LOCAL:
2027 case IFA_ADDRESS:
2028 break;
2029 default:
2030 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2031 break;
2032 }
2033 return 0;
2034}
2035
2036static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2037{
2038 uint32_t *u32;
2039 switch (rtattr->rta_type) {
2040 /* binary: depends on family type */
2041 case RTA_DST:
2042 case RTA_SRC:
2043 case RTA_GATEWAY:
2044 break;
2045 /* u32 */
2046 case RTA_OIF:
2047 u32 = RTA_DATA(rtattr);
2048 *u32 = tswap32(*u32);
2049 break;
2050 default:
2051 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2052 break;
2053 }
2054 return 0;
2055}
2056
2057static void target_to_host_link_rtattr(struct rtattr *rtattr,
2058 uint32_t rtattr_len)
2059{
2060 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2061 target_to_host_data_link_rtattr);
2062}
2063
2064static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2065 uint32_t rtattr_len)
2066{
2067 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2068 target_to_host_data_addr_rtattr);
2069}
2070
2071static void target_to_host_route_rtattr(struct rtattr *rtattr,
2072 uint32_t rtattr_len)
2073{
2074 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2075 target_to_host_data_route_rtattr);
2076}
2077
2078static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2079{
2080 struct ifinfomsg *ifi;
2081 struct ifaddrmsg *ifa;
2082 struct rtmsg *rtm;
2083
2084 switch (nlh->nlmsg_type) {
2085 case RTM_GETLINK:
2086 break;
2087 case RTM_NEWLINK:
2088 case RTM_DELLINK:
2089 ifi = NLMSG_DATA(nlh);
2090 ifi->ifi_type = tswap16(ifi->ifi_type);
2091 ifi->ifi_index = tswap32(ifi->ifi_index);
2092 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2093 ifi->ifi_change = tswap32(ifi->ifi_change);
2094 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2095 NLMSG_LENGTH(sizeof(*ifi)));
2096 break;
2097 case RTM_GETADDR:
2098 case RTM_NEWADDR:
2099 case RTM_DELADDR:
2100 ifa = NLMSG_DATA(nlh);
2101 ifa->ifa_index = tswap32(ifa->ifa_index);
2102 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2103 NLMSG_LENGTH(sizeof(*ifa)));
2104 break;
2105 case RTM_GETROUTE:
2106 break;
2107 case RTM_NEWROUTE:
2108 case RTM_DELROUTE:
2109 rtm = NLMSG_DATA(nlh);
2110 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2111 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2112 NLMSG_LENGTH(sizeof(*rtm)));
2113 break;
2114 default:
2115 return -TARGET_EOPNOTSUPP;
2116 }
2117 return 0;
2118}
2119
2120static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2121{
2122 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2123}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002124#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002125
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002126static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2127{
2128 switch (nlh->nlmsg_type) {
2129 default:
2130 gemu_log("Unknown host audit message type %d\n",
2131 nlh->nlmsg_type);
2132 return -TARGET_EINVAL;
2133 }
2134 return 0;
2135}
2136
2137static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2138 size_t len)
2139{
2140 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2141}
2142
2143static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2144{
2145 switch (nlh->nlmsg_type) {
2146 case AUDIT_USER:
2147 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2148 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2149 break;
2150 default:
2151 gemu_log("Unknown target audit message type %d\n",
2152 nlh->nlmsg_type);
2153 return -TARGET_EINVAL;
2154 }
2155
2156 return 0;
2157}
2158
2159static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2160{
2161 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2162}
2163
ths0da46a62007-10-20 20:23:07 +00002164/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002165static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002166 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002167{
blueswir1992f48a2007-10-14 16:27:31 +00002168 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002169 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002170 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002171 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002172
bellard8853f862004-02-22 14:57:26 +00002173 switch(level) {
2174 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002175 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002176 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002177 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002178
bellard2f619692007-11-16 10:46:05 +00002179 if (get_user_u32(val, optval_addr))
2180 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002181 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2182 break;
2183 case SOL_IP:
2184 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002185 case IP_TOS:
2186 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002187 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002188 case IP_ROUTER_ALERT:
2189 case IP_RECVOPTS:
2190 case IP_RETOPTS:
2191 case IP_PKTINFO:
2192 case IP_MTU_DISCOVER:
2193 case IP_RECVERR:
2194 case IP_RECVTOS:
2195#ifdef IP_FREEBIND
2196 case IP_FREEBIND:
2197#endif
2198 case IP_MULTICAST_TTL:
2199 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002200 val = 0;
2201 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002202 if (get_user_u32(val, optval_addr))
2203 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002204 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002205 if (get_user_u8(val, optval_addr))
2206 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002207 }
2208 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2209 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002210 case IP_ADD_MEMBERSHIP:
2211 case IP_DROP_MEMBERSHIP:
2212 if (optlen < sizeof (struct target_ip_mreq) ||
2213 optlen > sizeof (struct target_ip_mreqn))
2214 return -TARGET_EINVAL;
2215
2216 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2217 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2218 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2219 break;
2220
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002221 case IP_BLOCK_SOURCE:
2222 case IP_UNBLOCK_SOURCE:
2223 case IP_ADD_SOURCE_MEMBERSHIP:
2224 case IP_DROP_SOURCE_MEMBERSHIP:
2225 if (optlen != sizeof (struct target_ip_mreq_source))
2226 return -TARGET_EINVAL;
2227
2228 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2229 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2230 unlock_user (ip_mreq_source, optval_addr, 0);
2231 break;
2232
bellard8853f862004-02-22 14:57:26 +00002233 default:
2234 goto unimplemented;
2235 }
2236 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002237 case SOL_IPV6:
2238 switch (optname) {
2239 case IPV6_MTU_DISCOVER:
2240 case IPV6_MTU:
2241 case IPV6_V6ONLY:
2242 case IPV6_RECVPKTINFO:
2243 val = 0;
2244 if (optlen < sizeof(uint32_t)) {
2245 return -TARGET_EINVAL;
2246 }
2247 if (get_user_u32(val, optval_addr)) {
2248 return -TARGET_EFAULT;
2249 }
2250 ret = get_errno(setsockopt(sockfd, level, optname,
2251 &val, sizeof(val)));
2252 break;
2253 default:
2254 goto unimplemented;
2255 }
2256 break;
Jing Huang920394d2012-07-24 13:59:23 +00002257 case SOL_RAW:
2258 switch (optname) {
2259 case ICMP_FILTER:
2260 /* struct icmp_filter takes an u32 value */
2261 if (optlen < sizeof(uint32_t)) {
2262 return -TARGET_EINVAL;
2263 }
2264
2265 if (get_user_u32(val, optval_addr)) {
2266 return -TARGET_EFAULT;
2267 }
2268 ret = get_errno(setsockopt(sockfd, level, optname,
2269 &val, sizeof(val)));
2270 break;
2271
2272 default:
2273 goto unimplemented;
2274 }
2275 break;
bellard3532fa72006-06-24 15:06:03 +00002276 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002277 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002278 case TARGET_SO_RCVTIMEO:
2279 {
2280 struct timeval tv;
2281
2282 optname = SO_RCVTIMEO;
2283
2284set_timeout:
2285 if (optlen != sizeof(struct target_timeval)) {
2286 return -TARGET_EINVAL;
2287 }
2288
2289 if (copy_from_user_timeval(&tv, optval_addr)) {
2290 return -TARGET_EFAULT;
2291 }
2292
2293 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2294 &tv, sizeof(tv)));
2295 return ret;
2296 }
2297 case TARGET_SO_SNDTIMEO:
2298 optname = SO_SNDTIMEO;
2299 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002300 case TARGET_SO_ATTACH_FILTER:
2301 {
2302 struct target_sock_fprog *tfprog;
2303 struct target_sock_filter *tfilter;
2304 struct sock_fprog fprog;
2305 struct sock_filter *filter;
2306 int i;
2307
2308 if (optlen != sizeof(*tfprog)) {
2309 return -TARGET_EINVAL;
2310 }
2311 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2312 return -TARGET_EFAULT;
2313 }
2314 if (!lock_user_struct(VERIFY_READ, tfilter,
2315 tswapal(tfprog->filter), 0)) {
2316 unlock_user_struct(tfprog, optval_addr, 1);
2317 return -TARGET_EFAULT;
2318 }
2319
2320 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302321 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002322 if (filter == NULL) {
2323 unlock_user_struct(tfilter, tfprog->filter, 1);
2324 unlock_user_struct(tfprog, optval_addr, 1);
2325 return -TARGET_ENOMEM;
2326 }
2327 for (i = 0; i < fprog.len; i++) {
2328 filter[i].code = tswap16(tfilter[i].code);
2329 filter[i].jt = tfilter[i].jt;
2330 filter[i].jf = tfilter[i].jf;
2331 filter[i].k = tswap32(tfilter[i].k);
2332 }
2333 fprog.filter = filter;
2334
2335 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2336 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302337 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002338
2339 unlock_user_struct(tfilter, tfprog->filter, 1);
2340 unlock_user_struct(tfprog, optval_addr, 1);
2341 return ret;
2342 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002343 case TARGET_SO_BINDTODEVICE:
2344 {
2345 char *dev_ifname, *addr_ifname;
2346
2347 if (optlen > IFNAMSIZ - 1) {
2348 optlen = IFNAMSIZ - 1;
2349 }
2350 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2351 if (!dev_ifname) {
2352 return -TARGET_EFAULT;
2353 }
2354 optname = SO_BINDTODEVICE;
2355 addr_ifname = alloca(IFNAMSIZ);
2356 memcpy(addr_ifname, dev_ifname, optlen);
2357 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002358 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2359 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002360 unlock_user (dev_ifname, optval_addr, 0);
2361 return ret;
2362 }
bellard8853f862004-02-22 14:57:26 +00002363 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002364 case TARGET_SO_DEBUG:
2365 optname = SO_DEBUG;
2366 break;
2367 case TARGET_SO_REUSEADDR:
2368 optname = SO_REUSEADDR;
2369 break;
2370 case TARGET_SO_TYPE:
2371 optname = SO_TYPE;
2372 break;
2373 case TARGET_SO_ERROR:
2374 optname = SO_ERROR;
2375 break;
2376 case TARGET_SO_DONTROUTE:
2377 optname = SO_DONTROUTE;
2378 break;
2379 case TARGET_SO_BROADCAST:
2380 optname = SO_BROADCAST;
2381 break;
2382 case TARGET_SO_SNDBUF:
2383 optname = SO_SNDBUF;
2384 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002385 case TARGET_SO_SNDBUFFORCE:
2386 optname = SO_SNDBUFFORCE;
2387 break;
bellard3532fa72006-06-24 15:06:03 +00002388 case TARGET_SO_RCVBUF:
2389 optname = SO_RCVBUF;
2390 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002391 case TARGET_SO_RCVBUFFORCE:
2392 optname = SO_RCVBUFFORCE;
2393 break;
bellard3532fa72006-06-24 15:06:03 +00002394 case TARGET_SO_KEEPALIVE:
2395 optname = SO_KEEPALIVE;
2396 break;
2397 case TARGET_SO_OOBINLINE:
2398 optname = SO_OOBINLINE;
2399 break;
2400 case TARGET_SO_NO_CHECK:
2401 optname = SO_NO_CHECK;
2402 break;
2403 case TARGET_SO_PRIORITY:
2404 optname = SO_PRIORITY;
2405 break;
bellard5e83e8e2005-03-01 22:32:06 +00002406#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002407 case TARGET_SO_BSDCOMPAT:
2408 optname = SO_BSDCOMPAT;
2409 break;
bellard5e83e8e2005-03-01 22:32:06 +00002410#endif
bellard3532fa72006-06-24 15:06:03 +00002411 case TARGET_SO_PASSCRED:
2412 optname = SO_PASSCRED;
2413 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002414 case TARGET_SO_PASSSEC:
2415 optname = SO_PASSSEC;
2416 break;
bellard3532fa72006-06-24 15:06:03 +00002417 case TARGET_SO_TIMESTAMP:
2418 optname = SO_TIMESTAMP;
2419 break;
2420 case TARGET_SO_RCVLOWAT:
2421 optname = SO_RCVLOWAT;
2422 break;
bellard8853f862004-02-22 14:57:26 +00002423 break;
2424 default:
2425 goto unimplemented;
2426 }
bellard3532fa72006-06-24 15:06:03 +00002427 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002428 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002429
bellard2f619692007-11-16 10:46:05 +00002430 if (get_user_u32(val, optval_addr))
2431 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002432 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002433 break;
bellard7854b052003-03-29 17:22:23 +00002434 default:
bellard8853f862004-02-22 14:57:26 +00002435 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002436 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002437 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002438 }
bellard8853f862004-02-22 14:57:26 +00002439 return ret;
bellard7854b052003-03-29 17:22:23 +00002440}
2441
ths0da46a62007-10-20 20:23:07 +00002442/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002443static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002444 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002445{
blueswir1992f48a2007-10-14 16:27:31 +00002446 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002447 int len, val;
2448 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002449
2450 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002451 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002452 level = SOL_SOCKET;
2453 switch (optname) {
2454 /* These don't just return a single integer */
2455 case TARGET_SO_LINGER:
2456 case TARGET_SO_RCVTIMEO:
2457 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002458 case TARGET_SO_PEERNAME:
2459 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002460 case TARGET_SO_PEERCRED: {
2461 struct ucred cr;
2462 socklen_t crlen;
2463 struct target_ucred *tcr;
2464
2465 if (get_user_u32(len, optlen)) {
2466 return -TARGET_EFAULT;
2467 }
2468 if (len < 0) {
2469 return -TARGET_EINVAL;
2470 }
2471
2472 crlen = sizeof(cr);
2473 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2474 &cr, &crlen));
2475 if (ret < 0) {
2476 return ret;
2477 }
2478 if (len > crlen) {
2479 len = crlen;
2480 }
2481 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2482 return -TARGET_EFAULT;
2483 }
2484 __put_user(cr.pid, &tcr->pid);
2485 __put_user(cr.uid, &tcr->uid);
2486 __put_user(cr.gid, &tcr->gid);
2487 unlock_user_struct(tcr, optval_addr, 1);
2488 if (put_user_u32(len, optlen)) {
2489 return -TARGET_EFAULT;
2490 }
2491 break;
2492 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002493 /* Options with 'int' argument. */
2494 case TARGET_SO_DEBUG:
2495 optname = SO_DEBUG;
2496 goto int_case;
2497 case TARGET_SO_REUSEADDR:
2498 optname = SO_REUSEADDR;
2499 goto int_case;
2500 case TARGET_SO_TYPE:
2501 optname = SO_TYPE;
2502 goto int_case;
2503 case TARGET_SO_ERROR:
2504 optname = SO_ERROR;
2505 goto int_case;
2506 case TARGET_SO_DONTROUTE:
2507 optname = SO_DONTROUTE;
2508 goto int_case;
2509 case TARGET_SO_BROADCAST:
2510 optname = SO_BROADCAST;
2511 goto int_case;
2512 case TARGET_SO_SNDBUF:
2513 optname = SO_SNDBUF;
2514 goto int_case;
2515 case TARGET_SO_RCVBUF:
2516 optname = SO_RCVBUF;
2517 goto int_case;
2518 case TARGET_SO_KEEPALIVE:
2519 optname = SO_KEEPALIVE;
2520 goto int_case;
2521 case TARGET_SO_OOBINLINE:
2522 optname = SO_OOBINLINE;
2523 goto int_case;
2524 case TARGET_SO_NO_CHECK:
2525 optname = SO_NO_CHECK;
2526 goto int_case;
2527 case TARGET_SO_PRIORITY:
2528 optname = SO_PRIORITY;
2529 goto int_case;
2530#ifdef SO_BSDCOMPAT
2531 case TARGET_SO_BSDCOMPAT:
2532 optname = SO_BSDCOMPAT;
2533 goto int_case;
2534#endif
2535 case TARGET_SO_PASSCRED:
2536 optname = SO_PASSCRED;
2537 goto int_case;
2538 case TARGET_SO_TIMESTAMP:
2539 optname = SO_TIMESTAMP;
2540 goto int_case;
2541 case TARGET_SO_RCVLOWAT:
2542 optname = SO_RCVLOWAT;
2543 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002544 case TARGET_SO_ACCEPTCONN:
2545 optname = SO_ACCEPTCONN;
2546 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002547 default:
bellard2efbe912005-07-23 15:10:20 +00002548 goto int_case;
2549 }
2550 break;
2551 case SOL_TCP:
2552 /* TCP options all take an 'int' value. */
2553 int_case:
bellard2f619692007-11-16 10:46:05 +00002554 if (get_user_u32(len, optlen))
2555 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002556 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002557 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002558 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002559 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2560 if (ret < 0)
2561 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002562 if (optname == SO_TYPE) {
2563 val = host_to_target_sock_type(val);
2564 }
bellard2efbe912005-07-23 15:10:20 +00002565 if (len > lv)
2566 len = lv;
bellard2f619692007-11-16 10:46:05 +00002567 if (len == 4) {
2568 if (put_user_u32(val, optval_addr))
2569 return -TARGET_EFAULT;
2570 } else {
2571 if (put_user_u8(val, optval_addr))
2572 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002573 }
bellard2f619692007-11-16 10:46:05 +00002574 if (put_user_u32(len, optlen))
2575 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002576 break;
2577 case SOL_IP:
2578 switch(optname) {
2579 case IP_TOS:
2580 case IP_TTL:
2581 case IP_HDRINCL:
2582 case IP_ROUTER_ALERT:
2583 case IP_RECVOPTS:
2584 case IP_RETOPTS:
2585 case IP_PKTINFO:
2586 case IP_MTU_DISCOVER:
2587 case IP_RECVERR:
2588 case IP_RECVTOS:
2589#ifdef IP_FREEBIND
2590 case IP_FREEBIND:
2591#endif
2592 case IP_MULTICAST_TTL:
2593 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002594 if (get_user_u32(len, optlen))
2595 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002596 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002597 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002598 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002599 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2600 if (ret < 0)
2601 return ret;
bellard2efbe912005-07-23 15:10:20 +00002602 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002603 len = 1;
bellard2f619692007-11-16 10:46:05 +00002604 if (put_user_u32(len, optlen)
2605 || put_user_u8(val, optval_addr))
2606 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002607 } else {
bellard2efbe912005-07-23 15:10:20 +00002608 if (len > sizeof(int))
2609 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002610 if (put_user_u32(len, optlen)
2611 || put_user_u32(val, optval_addr))
2612 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002613 }
bellard8853f862004-02-22 14:57:26 +00002614 break;
bellard2efbe912005-07-23 15:10:20 +00002615 default:
thsc02f4992007-12-18 02:39:59 +00002616 ret = -TARGET_ENOPROTOOPT;
2617 break;
bellard8853f862004-02-22 14:57:26 +00002618 }
2619 break;
2620 default:
2621 unimplemented:
2622 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2623 level, optname);
thsc02f4992007-12-18 02:39:59 +00002624 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002625 break;
2626 }
2627 return ret;
bellard7854b052003-03-29 17:22:23 +00002628}
2629
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002630static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2631 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002632{
2633 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002634 struct iovec *vec;
2635 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002636 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002637 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002638 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002639
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002640 if (count == 0) {
2641 errno = 0;
2642 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002643 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002644 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002645 errno = EINVAL;
2646 return NULL;
2647 }
2648
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302649 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002650 if (vec == NULL) {
2651 errno = ENOMEM;
2652 return NULL;
2653 }
2654
2655 target_vec = lock_user(VERIFY_READ, target_addr,
2656 count * sizeof(struct target_iovec), 1);
2657 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002658 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002659 goto fail2;
2660 }
2661
2662 /* ??? If host page size > target page size, this will result in a
2663 value larger than what we can actually support. */
2664 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2665 total_len = 0;
2666
2667 for (i = 0; i < count; i++) {
2668 abi_ulong base = tswapal(target_vec[i].iov_base);
2669 abi_long len = tswapal(target_vec[i].iov_len);
2670
2671 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002672 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002673 goto fail;
2674 } else if (len == 0) {
2675 /* Zero length pointer is ignored. */
2676 vec[i].iov_base = 0;
2677 } else {
2678 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002679 /* If the first buffer pointer is bad, this is a fault. But
2680 * subsequent bad buffers will result in a partial write; this
2681 * is realized by filling the vector with null pointers and
2682 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002683 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002684 if (i == 0) {
2685 err = EFAULT;
2686 goto fail;
2687 } else {
2688 bad_address = true;
2689 }
2690 }
2691 if (bad_address) {
2692 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002693 }
2694 if (len > max_len - total_len) {
2695 len = max_len - total_len;
2696 }
2697 }
2698 vec[i].iov_len = len;
2699 total_len += len;
2700 }
2701
2702 unlock_user(target_vec, target_addr, 0);
2703 return vec;
2704
2705 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002706 while (--i >= 0) {
2707 if (tswapal(target_vec[i].iov_len) > 0) {
2708 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2709 }
2710 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002711 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002712 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302713 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002714 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002715 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002716}
2717
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002718static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2719 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002720{
2721 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002722 int i;
2723
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002724 target_vec = lock_user(VERIFY_READ, target_addr,
2725 count * sizeof(struct target_iovec), 1);
2726 if (target_vec) {
2727 for (i = 0; i < count; i++) {
2728 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002729 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002730 if (len < 0) {
2731 break;
2732 }
balrogd732dcb2008-10-28 10:21:03 +00002733 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2734 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002735 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002736 }
bellard579a97f2007-11-11 14:26:47 +00002737
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302738 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002739}
2740
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002741static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002742{
2743 int host_type = 0;
2744 int target_type = *type;
2745
2746 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2747 case TARGET_SOCK_DGRAM:
2748 host_type = SOCK_DGRAM;
2749 break;
2750 case TARGET_SOCK_STREAM:
2751 host_type = SOCK_STREAM;
2752 break;
2753 default:
2754 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2755 break;
2756 }
2757 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002758#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002759 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002760#else
2761 return -TARGET_EINVAL;
2762#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002763 }
2764 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002765#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002766 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002767#elif !defined(O_NONBLOCK)
2768 return -TARGET_EINVAL;
2769#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002770 }
2771 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002772 return 0;
2773}
2774
2775/* Try to emulate socket type flags after socket creation. */
2776static int sock_flags_fixup(int fd, int target_type)
2777{
2778#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2779 if (target_type & TARGET_SOCK_NONBLOCK) {
2780 int flags = fcntl(fd, F_GETFL);
2781 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2782 close(fd);
2783 return -TARGET_EINVAL;
2784 }
2785 }
2786#endif
2787 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002788}
2789
Laurent Vivier0cf22722015-10-28 21:40:45 +01002790static abi_long packet_target_to_host_sockaddr(void *host_addr,
2791 abi_ulong target_addr,
2792 socklen_t len)
2793{
2794 struct sockaddr *addr = host_addr;
2795 struct target_sockaddr *target_saddr;
2796
2797 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2798 if (!target_saddr) {
2799 return -TARGET_EFAULT;
2800 }
2801
2802 memcpy(addr, target_saddr, len);
2803 addr->sa_family = tswap16(target_saddr->sa_family);
2804 /* spkt_protocol is big-endian */
2805
2806 unlock_user(target_saddr, target_addr, 0);
2807 return 0;
2808}
2809
2810static TargetFdTrans target_packet_trans = {
2811 .target_to_host_addr = packet_target_to_host_sockaddr,
2812};
2813
Laurent Vivier575b22b2016-06-02 22:14:15 +02002814#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002815static abi_long netlink_route_target_to_host(void *buf, size_t len)
2816{
2817 return target_to_host_nlmsg_route(buf, len);
2818}
2819
2820static abi_long netlink_route_host_to_target(void *buf, size_t len)
2821{
2822 return host_to_target_nlmsg_route(buf, len);
2823}
2824
2825static TargetFdTrans target_netlink_route_trans = {
2826 .target_to_host_data = netlink_route_target_to_host,
2827 .host_to_target_data = netlink_route_host_to_target,
2828};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002829#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002830
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002831static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2832{
2833 return target_to_host_nlmsg_audit(buf, len);
2834}
2835
2836static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2837{
2838 return host_to_target_nlmsg_audit(buf, len);
2839}
2840
2841static TargetFdTrans target_netlink_audit_trans = {
2842 .target_to_host_data = netlink_audit_target_to_host,
2843 .host_to_target_data = netlink_audit_host_to_target,
2844};
2845
ths0da46a62007-10-20 20:23:07 +00002846/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002847static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002848{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002849 int target_type = type;
2850 int ret;
2851
2852 ret = target_to_host_sock_type(&type);
2853 if (ret) {
2854 return ret;
2855 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002856
Laurent Vivier575b22b2016-06-02 22:14:15 +02002857 if (domain == PF_NETLINK && !(
2858#ifdef CONFIG_RTNETLINK
2859 protocol == NETLINK_ROUTE ||
2860#endif
2861 protocol == NETLINK_KOBJECT_UEVENT ||
2862 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002863 return -EPFNOSUPPORT;
2864 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002865
2866 if (domain == AF_PACKET ||
2867 (domain == AF_INET && type == SOCK_PACKET)) {
2868 protocol = tswap16(protocol);
2869 }
2870
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002871 ret = get_errno(socket(domain, type, protocol));
2872 if (ret >= 0) {
2873 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002874 if (type == SOCK_PACKET) {
2875 /* Manage an obsolete case :
2876 * if socket type is SOCK_PACKET, bind by name
2877 */
2878 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002879 } else if (domain == PF_NETLINK) {
2880 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002881#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002882 case NETLINK_ROUTE:
2883 fd_trans_register(ret, &target_netlink_route_trans);
2884 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002885#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002886 case NETLINK_KOBJECT_UEVENT:
2887 /* nothing to do: messages are strings */
2888 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002889 case NETLINK_AUDIT:
2890 fd_trans_register(ret, &target_netlink_audit_trans);
2891 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002892 default:
2893 g_assert_not_reached();
2894 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002895 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002896 }
2897 return ret;
bellard3532fa72006-06-24 15:06:03 +00002898}
2899
ths0da46a62007-10-20 20:23:07 +00002900/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002901static abi_long do_bind(int sockfd, abi_ulong target_addr,
2902 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002903{
aurel328f7aeaf2009-01-30 19:47:57 +00002904 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002905 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002906
Blue Swirl38724252010-09-18 05:53:14 +00002907 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002908 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002909 }
aurel328f7aeaf2009-01-30 19:47:57 +00002910
aurel32607175e2009-04-15 16:11:59 +00002911 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002912
Laurent Vivier7b36f782015-10-28 21:40:44 +01002913 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002914 if (ret)
2915 return ret;
2916
bellard3532fa72006-06-24 15:06:03 +00002917 return get_errno(bind(sockfd, addr, addrlen));
2918}
2919
ths0da46a62007-10-20 20:23:07 +00002920/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002921static abi_long do_connect(int sockfd, abi_ulong target_addr,
2922 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002923{
aurel328f7aeaf2009-01-30 19:47:57 +00002924 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002925 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002926
Blue Swirl38724252010-09-18 05:53:14 +00002927 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002928 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002929 }
aurel328f7aeaf2009-01-30 19:47:57 +00002930
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002931 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002932
Laurent Vivier7b36f782015-10-28 21:40:44 +01002933 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002934 if (ret)
2935 return ret;
2936
Peter Maydell2a3c7612016-06-06 19:58:03 +01002937 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002938}
2939
Alexander Graff19e00d2014-03-02 19:36:42 +00002940/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2941static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2942 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002943{
balrog6de645c2008-10-28 10:26:29 +00002944 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002945 struct msghdr msg;
2946 int count;
2947 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002948 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002949
bellard3532fa72006-06-24 15:06:03 +00002950 if (msgp->msg_name) {
2951 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002952 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002953 ret = target_to_host_sockaddr(fd, msg.msg_name,
2954 tswapal(msgp->msg_name),
2955 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002956 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002957 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002958 }
bellard3532fa72006-06-24 15:06:03 +00002959 } else {
2960 msg.msg_name = NULL;
2961 msg.msg_namelen = 0;
2962 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002963 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002964 msg.msg_control = alloca(msg.msg_controllen);
2965 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002966
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002967 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002968 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002969 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2970 target_vec, count, send);
2971 if (vec == NULL) {
2972 ret = -host_to_target_errno(errno);
2973 goto out2;
2974 }
bellard3532fa72006-06-24 15:06:03 +00002975 msg.msg_iovlen = count;
2976 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002977
bellard3532fa72006-06-24 15:06:03 +00002978 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002979 if (fd_trans_target_to_host_data(fd)) {
2980 ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base,
2981 msg.msg_iov->iov_len);
2982 } else {
2983 ret = target_to_host_cmsg(&msg, msgp);
2984 }
2985 if (ret == 0) {
Peter Maydell66687532016-06-06 19:58:04 +01002986 ret = get_errno(safe_sendmsg(fd, &msg, flags));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002987 }
bellard3532fa72006-06-24 15:06:03 +00002988 } else {
Peter Maydell66687532016-06-06 19:58:04 +01002989 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002990 if (!is_error(ret)) {
2991 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002992 if (fd_trans_host_to_target_data(fd)) {
2993 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02002994 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002995 } else {
2996 ret = host_to_target_cmsg(msgp, &msg);
2997 }
Jing Huangca619062012-07-24 13:58:02 +00002998 if (!is_error(ret)) {
2999 msgp->msg_namelen = tswap32(msg.msg_namelen);
3000 if (msg.msg_name != NULL) {
3001 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3002 msg.msg_name, msg.msg_namelen);
3003 if (ret) {
3004 goto out;
3005 }
3006 }
3007
balrog6de645c2008-10-28 10:26:29 +00003008 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003009 }
balrog6de645c2008-10-28 10:26:29 +00003010 }
bellard3532fa72006-06-24 15:06:03 +00003011 }
Jing Huangca619062012-07-24 13:58:02 +00003012
3013out:
bellard3532fa72006-06-24 15:06:03 +00003014 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003015out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003016 return ret;
3017}
3018
3019static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3020 int flags, int send)
3021{
3022 abi_long ret;
3023 struct target_msghdr *msgp;
3024
3025 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3026 msgp,
3027 target_msg,
3028 send ? 1 : 0)) {
3029 return -TARGET_EFAULT;
3030 }
3031 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003032 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003033 return ret;
3034}
3035
Alexander Graff19e00d2014-03-02 19:36:42 +00003036/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3037 * so it might not have this *mmsg-specific flag either.
3038 */
3039#ifndef MSG_WAITFORONE
3040#define MSG_WAITFORONE 0x10000
3041#endif
3042
3043static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3044 unsigned int vlen, unsigned int flags,
3045 int send)
3046{
3047 struct target_mmsghdr *mmsgp;
3048 abi_long ret = 0;
3049 int i;
3050
3051 if (vlen > UIO_MAXIOV) {
3052 vlen = UIO_MAXIOV;
3053 }
3054
3055 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3056 if (!mmsgp) {
3057 return -TARGET_EFAULT;
3058 }
3059
3060 for (i = 0; i < vlen; i++) {
3061 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3062 if (is_error(ret)) {
3063 break;
3064 }
3065 mmsgp[i].msg_len = tswap32(ret);
3066 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3067 if (flags & MSG_WAITFORONE) {
3068 flags |= MSG_DONTWAIT;
3069 }
3070 }
3071
3072 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3073
3074 /* Return number of datagrams sent if we sent any at all;
3075 * otherwise return the error.
3076 */
3077 if (i) {
3078 return i;
3079 }
3080 return ret;
3081}
Alexander Graff19e00d2014-03-02 19:36:42 +00003082
Peter Maydella94b4982013-02-08 04:35:04 +00003083/* do_accept4() Must return target values and target errnos. */
3084static abi_long do_accept4(int fd, abi_ulong target_addr,
3085 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003086{
bellard2f619692007-11-16 10:46:05 +00003087 socklen_t addrlen;
3088 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003089 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003090 int host_flags;
3091
3092 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003093
Peter Maydella94b4982013-02-08 04:35:04 +00003094 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003095 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003096 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003097
3098 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003099 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003100 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003101
Blue Swirl38724252010-09-18 05:53:14 +00003102 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003103 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003104 }
aurel328f7aeaf2009-01-30 19:47:57 +00003105
Arnaud Patard917507b2009-06-19 10:44:45 +03003106 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3107 return -TARGET_EINVAL;
3108
bellard2f619692007-11-16 10:46:05 +00003109 addr = alloca(addrlen);
3110
Peter Maydellff6dc132016-06-06 19:58:13 +01003111 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003112 if (!is_error(ret)) {
3113 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003114 if (put_user_u32(addrlen, target_addrlen_addr))
3115 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003116 }
3117 return ret;
3118}
3119
ths0da46a62007-10-20 20:23:07 +00003120/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003121static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003122 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003123{
bellard2f619692007-11-16 10:46:05 +00003124 socklen_t addrlen;
3125 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003126 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003127
bellard2f619692007-11-16 10:46:05 +00003128 if (get_user_u32(addrlen, target_addrlen_addr))
3129 return -TARGET_EFAULT;
3130
Blue Swirl38724252010-09-18 05:53:14 +00003131 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003132 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003133 }
aurel328f7aeaf2009-01-30 19:47:57 +00003134
Arnaud Patard917507b2009-06-19 10:44:45 +03003135 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3136 return -TARGET_EFAULT;
3137
bellard2f619692007-11-16 10:46:05 +00003138 addr = alloca(addrlen);
3139
pbrook1be9e1d2006-11-19 15:26:04 +00003140 ret = get_errno(getpeername(fd, addr, &addrlen));
3141 if (!is_error(ret)) {
3142 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003143 if (put_user_u32(addrlen, target_addrlen_addr))
3144 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003145 }
3146 return ret;
3147}
3148
ths0da46a62007-10-20 20:23:07 +00003149/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003150static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003151 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003152{
bellard2f619692007-11-16 10:46:05 +00003153 socklen_t addrlen;
3154 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003155 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003156
bellard2f619692007-11-16 10:46:05 +00003157 if (get_user_u32(addrlen, target_addrlen_addr))
3158 return -TARGET_EFAULT;
3159
Blue Swirl38724252010-09-18 05:53:14 +00003160 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003161 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003162 }
aurel328f7aeaf2009-01-30 19:47:57 +00003163
Arnaud Patard917507b2009-06-19 10:44:45 +03003164 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3165 return -TARGET_EFAULT;
3166
bellard2f619692007-11-16 10:46:05 +00003167 addr = alloca(addrlen);
3168
pbrook1be9e1d2006-11-19 15:26:04 +00003169 ret = get_errno(getsockname(fd, addr, &addrlen));
3170 if (!is_error(ret)) {
3171 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003172 if (put_user_u32(addrlen, target_addrlen_addr))
3173 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003174 }
3175 return ret;
3176}
3177
ths0da46a62007-10-20 20:23:07 +00003178/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003179static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003180 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003181{
3182 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003183 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003184
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003185 target_to_host_sock_type(&type);
3186
pbrook1be9e1d2006-11-19 15:26:04 +00003187 ret = get_errno(socketpair(domain, type, protocol, tab));
3188 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003189 if (put_user_s32(tab[0], target_tab_addr)
3190 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3191 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003192 }
3193 return ret;
3194}
3195
ths0da46a62007-10-20 20:23:07 +00003196/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003197static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3198 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003199{
3200 void *addr;
3201 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003202 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003203
Blue Swirl38724252010-09-18 05:53:14 +00003204 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003205 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003206 }
aurel328f7aeaf2009-01-30 19:47:57 +00003207
bellard579a97f2007-11-11 14:26:47 +00003208 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3209 if (!host_msg)
3210 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003211 if (fd_trans_target_to_host_data(fd)) {
3212 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3213 if (ret < 0) {
3214 unlock_user(host_msg, msg, 0);
3215 return ret;
3216 }
3217 }
pbrook1be9e1d2006-11-19 15:26:04 +00003218 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003219 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003220 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003221 if (ret) {
3222 unlock_user(host_msg, msg, 0);
3223 return ret;
3224 }
Peter Maydell66687532016-06-06 19:58:04 +01003225 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003226 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003227 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003228 }
3229 unlock_user(host_msg, msg, 0);
3230 return ret;
3231}
3232
ths0da46a62007-10-20 20:23:07 +00003233/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003234static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3235 abi_ulong target_addr,
3236 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003237{
3238 socklen_t addrlen;
3239 void *addr;
3240 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003241 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003242
bellard579a97f2007-11-11 14:26:47 +00003243 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3244 if (!host_msg)
3245 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003246 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003247 if (get_user_u32(addrlen, target_addrlen)) {
3248 ret = -TARGET_EFAULT;
3249 goto fail;
3250 }
Blue Swirl38724252010-09-18 05:53:14 +00003251 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003252 ret = -TARGET_EINVAL;
3253 goto fail;
3254 }
pbrook1be9e1d2006-11-19 15:26:04 +00003255 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003256 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3257 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003258 } else {
3259 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003260 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003261 }
3262 if (!is_error(ret)) {
3263 if (target_addr) {
3264 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003265 if (put_user_u32(addrlen, target_addrlen)) {
3266 ret = -TARGET_EFAULT;
3267 goto fail;
3268 }
pbrook1be9e1d2006-11-19 15:26:04 +00003269 }
3270 unlock_user(host_msg, msg, len);
3271 } else {
bellard2f619692007-11-16 10:46:05 +00003272fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003273 unlock_user(host_msg, msg, 0);
3274 }
3275 return ret;
3276}
3277
j_mayer32407102007-09-26 23:01:49 +00003278#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003279/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003280static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003281{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003282 static const unsigned ac[] = { /* number of arguments per call */
3283 [SOCKOP_socket] = 3, /* domain, type, protocol */
3284 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3285 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3286 [SOCKOP_listen] = 2, /* sockfd, backlog */
3287 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3288 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3289 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3290 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3291 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3292 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3293 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3294 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3295 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3296 [SOCKOP_shutdown] = 2, /* sockfd, how */
3297 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3298 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003299 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3300 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003301 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3302 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3303 };
3304 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003305
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003306 /* first, collect the arguments in a[] according to ac[] */
3307 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3308 unsigned i;
3309 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3310 for (i = 0; i < ac[num]; ++i) {
3311 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003312 return -TARGET_EFAULT;
3313 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003314 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003315 }
bellard2f619692007-11-16 10:46:05 +00003316
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003317 /* now when we have the args, actually handle the call */
3318 switch (num) {
3319 case SOCKOP_socket: /* domain, type, protocol */
3320 return do_socket(a[0], a[1], a[2]);
3321 case SOCKOP_bind: /* sockfd, addr, addrlen */
3322 return do_bind(a[0], a[1], a[2]);
3323 case SOCKOP_connect: /* sockfd, addr, addrlen */
3324 return do_connect(a[0], a[1], a[2]);
3325 case SOCKOP_listen: /* sockfd, backlog */
3326 return get_errno(listen(a[0], a[1]));
3327 case SOCKOP_accept: /* sockfd, addr, addrlen */
3328 return do_accept4(a[0], a[1], a[2], 0);
3329 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3330 return do_accept4(a[0], a[1], a[2], a[3]);
3331 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3332 return do_getsockname(a[0], a[1], a[2]);
3333 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3334 return do_getpeername(a[0], a[1], a[2]);
3335 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3336 return do_socketpair(a[0], a[1], a[2], a[3]);
3337 case SOCKOP_send: /* sockfd, msg, len, flags */
3338 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3339 case SOCKOP_recv: /* sockfd, msg, len, flags */
3340 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3341 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3342 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3343 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3344 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3345 case SOCKOP_shutdown: /* sockfd, how */
3346 return get_errno(shutdown(a[0], a[1]));
3347 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3348 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3349 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3350 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003351 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3352 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3353 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3354 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003355 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3356 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3357 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3358 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003359 default:
3360 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003361 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003362 }
bellard31e31b82003-02-18 22:55:36 +00003363}
j_mayer32407102007-09-26 23:01:49 +00003364#endif
bellard31e31b82003-02-18 22:55:36 +00003365
bellard8853f862004-02-22 14:57:26 +00003366#define N_SHM_REGIONS 32
3367
3368static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003369 abi_ulong start;
3370 abi_ulong size;
3371 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003372} shm_regions[N_SHM_REGIONS];
3373
ths3eb6b042007-06-03 14:26:27 +00003374struct target_semid_ds
3375{
3376 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003377 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003378#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003379 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003380#endif
blueswir1992f48a2007-10-14 16:27:31 +00003381 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003382#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003383 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003384#endif
blueswir1992f48a2007-10-14 16:27:31 +00003385 abi_ulong sem_nsems;
3386 abi_ulong __unused3;
3387 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003388};
3389
bellard579a97f2007-11-11 14:26:47 +00003390static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3391 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003392{
3393 struct target_ipc_perm *target_ip;
3394 struct target_semid_ds *target_sd;
3395
bellard579a97f2007-11-11 14:26:47 +00003396 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3397 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003398 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003399 host_ip->__key = tswap32(target_ip->__key);
3400 host_ip->uid = tswap32(target_ip->uid);
3401 host_ip->gid = tswap32(target_ip->gid);
3402 host_ip->cuid = tswap32(target_ip->cuid);
3403 host_ip->cgid = tswap32(target_ip->cgid);
3404#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3405 host_ip->mode = tswap32(target_ip->mode);
3406#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003407 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003408#endif
3409#if defined(TARGET_PPC)
3410 host_ip->__seq = tswap32(target_ip->__seq);
3411#else
3412 host_ip->__seq = tswap16(target_ip->__seq);
3413#endif
ths3eb6b042007-06-03 14:26:27 +00003414 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003415 return 0;
ths3eb6b042007-06-03 14:26:27 +00003416}
3417
bellard579a97f2007-11-11 14:26:47 +00003418static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3419 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003420{
3421 struct target_ipc_perm *target_ip;
3422 struct target_semid_ds *target_sd;
3423
bellard579a97f2007-11-11 14:26:47 +00003424 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3425 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003426 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003427 target_ip->__key = tswap32(host_ip->__key);
3428 target_ip->uid = tswap32(host_ip->uid);
3429 target_ip->gid = tswap32(host_ip->gid);
3430 target_ip->cuid = tswap32(host_ip->cuid);
3431 target_ip->cgid = tswap32(host_ip->cgid);
3432#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3433 target_ip->mode = tswap32(host_ip->mode);
3434#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003435 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003436#endif
3437#if defined(TARGET_PPC)
3438 target_ip->__seq = tswap32(host_ip->__seq);
3439#else
3440 target_ip->__seq = tswap16(host_ip->__seq);
3441#endif
ths3eb6b042007-06-03 14:26:27 +00003442 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003443 return 0;
ths3eb6b042007-06-03 14:26:27 +00003444}
3445
bellard579a97f2007-11-11 14:26:47 +00003446static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3447 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003448{
3449 struct target_semid_ds *target_sd;
3450
bellard579a97f2007-11-11 14:26:47 +00003451 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3452 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003453 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3454 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003455 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3456 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3457 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003458 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003459 return 0;
ths3eb6b042007-06-03 14:26:27 +00003460}
3461
bellard579a97f2007-11-11 14:26:47 +00003462static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3463 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003464{
3465 struct target_semid_ds *target_sd;
3466
bellard579a97f2007-11-11 14:26:47 +00003467 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3468 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003469 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003470 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003471 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3472 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3473 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003474 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003475 return 0;
ths3eb6b042007-06-03 14:26:27 +00003476}
3477
aurel32e5289082009-04-18 16:16:12 +00003478struct target_seminfo {
3479 int semmap;
3480 int semmni;
3481 int semmns;
3482 int semmnu;
3483 int semmsl;
3484 int semopm;
3485 int semume;
3486 int semusz;
3487 int semvmx;
3488 int semaem;
3489};
3490
3491static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3492 struct seminfo *host_seminfo)
3493{
3494 struct target_seminfo *target_seminfo;
3495 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3496 return -TARGET_EFAULT;
3497 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3498 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3499 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3500 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3501 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3502 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3503 __put_user(host_seminfo->semume, &target_seminfo->semume);
3504 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3505 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3506 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3507 unlock_user_struct(target_seminfo, target_addr, 1);
3508 return 0;
3509}
3510
thsfa294812007-02-02 22:05:00 +00003511union semun {
3512 int val;
ths3eb6b042007-06-03 14:26:27 +00003513 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003514 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003515 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003516};
3517
ths3eb6b042007-06-03 14:26:27 +00003518union target_semun {
3519 int val;
aurel32e5289082009-04-18 16:16:12 +00003520 abi_ulong buf;
3521 abi_ulong array;
3522 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003523};
3524
aurel32e5289082009-04-18 16:16:12 +00003525static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3526 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003527{
aurel32e5289082009-04-18 16:16:12 +00003528 int nsems;
3529 unsigned short *array;
3530 union semun semun;
3531 struct semid_ds semid_ds;
3532 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003533
aurel32e5289082009-04-18 16:16:12 +00003534 semun.buf = &semid_ds;
3535
3536 ret = semctl(semid, 0, IPC_STAT, semun);
3537 if (ret == -1)
3538 return get_errno(ret);
3539
3540 nsems = semid_ds.sem_nsems;
3541
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303542 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003543 if (!*host_array) {
3544 return -TARGET_ENOMEM;
3545 }
aurel32e5289082009-04-18 16:16:12 +00003546 array = lock_user(VERIFY_READ, target_addr,
3547 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003548 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303549 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003550 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003551 }
aurel32e5289082009-04-18 16:16:12 +00003552
3553 for(i=0; i<nsems; i++) {
3554 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003555 }
aurel32e5289082009-04-18 16:16:12 +00003556 unlock_user(array, target_addr, 0);
3557
bellard579a97f2007-11-11 14:26:47 +00003558 return 0;
ths3eb6b042007-06-03 14:26:27 +00003559}
3560
aurel32e5289082009-04-18 16:16:12 +00003561static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3562 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003563{
aurel32e5289082009-04-18 16:16:12 +00003564 int nsems;
3565 unsigned short *array;
3566 union semun semun;
3567 struct semid_ds semid_ds;
3568 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003569
aurel32e5289082009-04-18 16:16:12 +00003570 semun.buf = &semid_ds;
3571
3572 ret = semctl(semid, 0, IPC_STAT, semun);
3573 if (ret == -1)
3574 return get_errno(ret);
3575
3576 nsems = semid_ds.sem_nsems;
3577
3578 array = lock_user(VERIFY_WRITE, target_addr,
3579 nsems*sizeof(unsigned short), 0);
3580 if (!array)
3581 return -TARGET_EFAULT;
3582
3583 for(i=0; i<nsems; i++) {
3584 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003585 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303586 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003587 unlock_user(array, target_addr, 1);
3588
bellard579a97f2007-11-11 14:26:47 +00003589 return 0;
ths3eb6b042007-06-03 14:26:27 +00003590}
3591
aurel32e5289082009-04-18 16:16:12 +00003592static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003593 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003594{
Stefan Weild1c002b2015-02-08 15:40:58 +01003595 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003596 union semun arg;
3597 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303598 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003599 struct seminfo seminfo;
3600 abi_long ret = -TARGET_EINVAL;
3601 abi_long err;
3602 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003603
3604 switch( cmd ) {
3605 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003606 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003607 /* In 64 bit cross-endian situations, we will erroneously pick up
3608 * the wrong half of the union for the "val" element. To rectify
3609 * this, the entire 8-byte structure is byteswapped, followed by
3610 * a swap of the 4 byte val field. In other cases, the data is
3611 * already in proper host byte order. */
3612 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3613 target_su.buf = tswapal(target_su.buf);
3614 arg.val = tswap32(target_su.val);
3615 } else {
3616 arg.val = target_su.val;
3617 }
aurel32e5289082009-04-18 16:16:12 +00003618 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003619 break;
3620 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003621 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003622 err = target_to_host_semarray(semid, &array, target_su.array);
3623 if (err)
3624 return err;
3625 arg.array = array;
3626 ret = get_errno(semctl(semid, semnum, cmd, arg));
3627 err = host_to_target_semarray(semid, target_su.array, &array);
3628 if (err)
3629 return err;
ths3eb6b042007-06-03 14:26:27 +00003630 break;
3631 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003632 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003633 case SEM_STAT:
3634 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3635 if (err)
3636 return err;
3637 arg.buf = &dsarg;
3638 ret = get_errno(semctl(semid, semnum, cmd, arg));
3639 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3640 if (err)
3641 return err;
ths3eb6b042007-06-03 14:26:27 +00003642 break;
aurel32e5289082009-04-18 16:16:12 +00003643 case IPC_INFO:
3644 case SEM_INFO:
3645 arg.__buf = &seminfo;
3646 ret = get_errno(semctl(semid, semnum, cmd, arg));
3647 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3648 if (err)
3649 return err;
3650 break;
3651 case IPC_RMID:
3652 case GETPID:
3653 case GETNCNT:
3654 case GETZCNT:
3655 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3656 break;
ths3eb6b042007-06-03 14:26:27 +00003657 }
3658
3659 return ret;
3660}
3661
aurel32e5289082009-04-18 16:16:12 +00003662struct target_sembuf {
3663 unsigned short sem_num;
3664 short sem_op;
3665 short sem_flg;
3666};
3667
3668static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3669 abi_ulong target_addr,
3670 unsigned nsops)
3671{
3672 struct target_sembuf *target_sembuf;
3673 int i;
3674
3675 target_sembuf = lock_user(VERIFY_READ, target_addr,
3676 nsops*sizeof(struct target_sembuf), 1);
3677 if (!target_sembuf)
3678 return -TARGET_EFAULT;
3679
3680 for(i=0; i<nsops; i++) {
3681 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3682 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3683 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3684 }
3685
3686 unlock_user(target_sembuf, target_addr, 0);
3687
3688 return 0;
3689}
3690
3691static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3692{
3693 struct sembuf sops[nsops];
3694
3695 if (target_to_host_sembuf(sops, ptr, nsops))
3696 return -TARGET_EFAULT;
3697
Peter Maydellffb7ee72016-06-06 19:58:12 +01003698 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00003699}
3700
ths1bc012f2007-06-03 14:27:49 +00003701struct target_msqid_ds
3702{
aurel321c54ff92008-10-13 21:08:44 +00003703 struct target_ipc_perm msg_perm;
3704 abi_ulong msg_stime;
3705#if TARGET_ABI_BITS == 32
3706 abi_ulong __unused1;
3707#endif
3708 abi_ulong msg_rtime;
3709#if TARGET_ABI_BITS == 32
3710 abi_ulong __unused2;
3711#endif
3712 abi_ulong msg_ctime;
3713#if TARGET_ABI_BITS == 32
3714 abi_ulong __unused3;
3715#endif
3716 abi_ulong __msg_cbytes;
3717 abi_ulong msg_qnum;
3718 abi_ulong msg_qbytes;
3719 abi_ulong msg_lspid;
3720 abi_ulong msg_lrpid;
3721 abi_ulong __unused4;
3722 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003723};
3724
bellard579a97f2007-11-11 14:26:47 +00003725static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3726 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003727{
3728 struct target_msqid_ds *target_md;
3729
bellard579a97f2007-11-11 14:26:47 +00003730 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3731 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003732 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3733 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003734 host_md->msg_stime = tswapal(target_md->msg_stime);
3735 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3736 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3737 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3738 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3739 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3740 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3741 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003742 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003743 return 0;
ths1bc012f2007-06-03 14:27:49 +00003744}
3745
bellard579a97f2007-11-11 14:26:47 +00003746static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3747 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003748{
3749 struct target_msqid_ds *target_md;
3750
bellard579a97f2007-11-11 14:26:47 +00003751 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3752 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003753 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3754 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003755 target_md->msg_stime = tswapal(host_md->msg_stime);
3756 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3757 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3758 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3759 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3760 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3761 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3762 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003763 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003764 return 0;
ths1bc012f2007-06-03 14:27:49 +00003765}
3766
aurel321c54ff92008-10-13 21:08:44 +00003767struct target_msginfo {
3768 int msgpool;
3769 int msgmap;
3770 int msgmax;
3771 int msgmnb;
3772 int msgmni;
3773 int msgssz;
3774 int msgtql;
3775 unsigned short int msgseg;
3776};
3777
3778static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3779 struct msginfo *host_msginfo)
3780{
3781 struct target_msginfo *target_msginfo;
3782 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3783 return -TARGET_EFAULT;
3784 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3785 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3786 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3787 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3788 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3789 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3790 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3791 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3792 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003793 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003794}
3795
3796static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003797{
3798 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003799 struct msginfo msginfo;
3800 abi_long ret = -TARGET_EINVAL;
3801
3802 cmd &= 0xff;
3803
3804 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003805 case IPC_STAT:
3806 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003807 case MSG_STAT:
3808 if (target_to_host_msqid_ds(&dsarg,ptr))
3809 return -TARGET_EFAULT;
3810 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3811 if (host_to_target_msqid_ds(ptr,&dsarg))
3812 return -TARGET_EFAULT;
3813 break;
3814 case IPC_RMID:
3815 ret = get_errno(msgctl(msgid, cmd, NULL));
3816 break;
3817 case IPC_INFO:
3818 case MSG_INFO:
3819 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3820 if (host_to_target_msginfo(ptr, &msginfo))
3821 return -TARGET_EFAULT;
3822 break;
ths1bc012f2007-06-03 14:27:49 +00003823 }
aurel321c54ff92008-10-13 21:08:44 +00003824
ths1bc012f2007-06-03 14:27:49 +00003825 return ret;
3826}
3827
3828struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003829 abi_long mtype;
3830 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003831};
3832
blueswir1992f48a2007-10-14 16:27:31 +00003833static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003834 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003835{
3836 struct target_msgbuf *target_mb;
3837 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003838 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003839
Tom Mustaedcc5f92014-08-12 13:53:37 -05003840 if (msgsz < 0) {
3841 return -TARGET_EINVAL;
3842 }
3843
bellard579a97f2007-11-11 14:26:47 +00003844 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3845 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303846 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003847 if (!host_mb) {
3848 unlock_user_struct(target_mb, msgp, 0);
3849 return -TARGET_ENOMEM;
3850 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003851 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003852 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01003853 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303854 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003855 unlock_user_struct(target_mb, msgp, 0);
3856
3857 return ret;
3858}
3859
blueswir1992f48a2007-10-14 16:27:31 +00003860static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003861 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003862 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003863{
3864 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003865 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003866 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003867 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003868
Peter Maydell99874f62016-05-20 19:00:56 +01003869 if (msgsz < 0) {
3870 return -TARGET_EINVAL;
3871 }
3872
bellard579a97f2007-11-11 14:26:47 +00003873 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3874 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003875
Peter Maydell415d8472016-05-20 19:00:57 +01003876 host_mb = g_try_malloc(msgsz + sizeof(long));
3877 if (!host_mb) {
3878 ret = -TARGET_ENOMEM;
3879 goto end;
3880 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01003881 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003882
bellard579a97f2007-11-11 14:26:47 +00003883 if (ret > 0) {
3884 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3885 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3886 if (!target_mtext) {
3887 ret = -TARGET_EFAULT;
3888 goto end;
3889 }
aurel321c54ff92008-10-13 21:08:44 +00003890 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003891 unlock_user(target_mtext, target_mtext_addr, ret);
3892 }
aurel321c54ff92008-10-13 21:08:44 +00003893
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003894 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003895
bellard579a97f2007-11-11 14:26:47 +00003896end:
3897 if (target_mb)
3898 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003899 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003900 return ret;
3901}
3902
Riku Voipio88a8c982009-04-03 10:42:00 +03003903static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3904 abi_ulong target_addr)
3905{
3906 struct target_shmid_ds *target_sd;
3907
3908 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3909 return -TARGET_EFAULT;
3910 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3911 return -TARGET_EFAULT;
3912 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3913 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3914 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3915 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3916 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3917 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3918 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3919 unlock_user_struct(target_sd, target_addr, 0);
3920 return 0;
3921}
3922
3923static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3924 struct shmid_ds *host_sd)
3925{
3926 struct target_shmid_ds *target_sd;
3927
3928 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3929 return -TARGET_EFAULT;
3930 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3931 return -TARGET_EFAULT;
3932 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3933 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3934 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3935 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3936 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3937 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3938 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3939 unlock_user_struct(target_sd, target_addr, 1);
3940 return 0;
3941}
3942
3943struct target_shminfo {
3944 abi_ulong shmmax;
3945 abi_ulong shmmin;
3946 abi_ulong shmmni;
3947 abi_ulong shmseg;
3948 abi_ulong shmall;
3949};
3950
3951static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3952 struct shminfo *host_shminfo)
3953{
3954 struct target_shminfo *target_shminfo;
3955 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3956 return -TARGET_EFAULT;
3957 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3958 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3959 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3960 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3961 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3962 unlock_user_struct(target_shminfo, target_addr, 1);
3963 return 0;
3964}
3965
3966struct target_shm_info {
3967 int used_ids;
3968 abi_ulong shm_tot;
3969 abi_ulong shm_rss;
3970 abi_ulong shm_swp;
3971 abi_ulong swap_attempts;
3972 abi_ulong swap_successes;
3973};
3974
3975static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3976 struct shm_info *host_shm_info)
3977{
3978 struct target_shm_info *target_shm_info;
3979 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3980 return -TARGET_EFAULT;
3981 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3982 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3983 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3984 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3985 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3986 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3987 unlock_user_struct(target_shm_info, target_addr, 1);
3988 return 0;
3989}
3990
3991static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3992{
3993 struct shmid_ds dsarg;
3994 struct shminfo shminfo;
3995 struct shm_info shm_info;
3996 abi_long ret = -TARGET_EINVAL;
3997
3998 cmd &= 0xff;
3999
4000 switch(cmd) {
4001 case IPC_STAT:
4002 case IPC_SET:
4003 case SHM_STAT:
4004 if (target_to_host_shmid_ds(&dsarg, buf))
4005 return -TARGET_EFAULT;
4006 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4007 if (host_to_target_shmid_ds(buf, &dsarg))
4008 return -TARGET_EFAULT;
4009 break;
4010 case IPC_INFO:
4011 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4012 if (host_to_target_shminfo(buf, &shminfo))
4013 return -TARGET_EFAULT;
4014 break;
4015 case SHM_INFO:
4016 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4017 if (host_to_target_shm_info(buf, &shm_info))
4018 return -TARGET_EFAULT;
4019 break;
4020 case IPC_RMID:
4021 case SHM_LOCK:
4022 case SHM_UNLOCK:
4023 ret = get_errno(shmctl(shmid, cmd, NULL));
4024 break;
4025 }
4026
4027 return ret;
4028}
4029
4030static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4031{
4032 abi_long raddr;
4033 void *host_raddr;
4034 struct shmid_ds shm_info;
4035 int i,ret;
4036
4037 /* find out the length of the shared memory segment */
4038 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4039 if (is_error(ret)) {
4040 /* can't get length, bail out */
4041 return ret;
4042 }
4043
4044 mmap_lock();
4045
4046 if (shmaddr)
4047 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4048 else {
4049 abi_ulong mmap_start;
4050
4051 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4052
4053 if (mmap_start == -1) {
4054 errno = ENOMEM;
4055 host_raddr = (void *)-1;
4056 } else
4057 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4058 }
4059
4060 if (host_raddr == (void *)-1) {
4061 mmap_unlock();
4062 return get_errno((long)host_raddr);
4063 }
4064 raddr=h2g((unsigned long)host_raddr);
4065
4066 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4067 PAGE_VALID | PAGE_READ |
4068 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4069
4070 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004071 if (!shm_regions[i].in_use) {
4072 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004073 shm_regions[i].start = raddr;
4074 shm_regions[i].size = shm_info.shm_segsz;
4075 break;
4076 }
4077 }
4078
4079 mmap_unlock();
4080 return raddr;
4081
4082}
4083
4084static inline abi_long do_shmdt(abi_ulong shmaddr)
4085{
4086 int i;
4087
4088 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004089 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4090 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004091 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004092 break;
4093 }
4094 }
4095
4096 return get_errno(shmdt(g2h(shmaddr)));
4097}
4098
aurel321c54ff92008-10-13 21:08:44 +00004099#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004100/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004101/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004102static abi_long do_ipc(unsigned int call, abi_long first,
4103 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004104 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004105{
4106 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004107 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004108
4109 version = call >> 16;
4110 call &= 0xffff;
4111
4112 switch (call) {
thsfa294812007-02-02 22:05:00 +00004113 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004114 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004115 break;
4116
4117 case IPCOP_semget:
4118 ret = get_errno(semget(first, second, third));
4119 break;
4120
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004121 case IPCOP_semctl: {
4122 /* The semun argument to semctl is passed by value, so dereference the
4123 * ptr argument. */
4124 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004125 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004126 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004127 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004128 }
thsd96372e2007-02-02 22:05:44 +00004129
aurel321c54ff92008-10-13 21:08:44 +00004130 case IPCOP_msgget:
4131 ret = get_errno(msgget(first, second));
4132 break;
thsd96372e2007-02-02 22:05:44 +00004133
aurel321c54ff92008-10-13 21:08:44 +00004134 case IPCOP_msgsnd:
4135 ret = do_msgsnd(first, ptr, second, third);
4136 break;
thsd96372e2007-02-02 22:05:44 +00004137
aurel321c54ff92008-10-13 21:08:44 +00004138 case IPCOP_msgctl:
4139 ret = do_msgctl(first, second, ptr);
4140 break;
thsd96372e2007-02-02 22:05:44 +00004141
aurel321c54ff92008-10-13 21:08:44 +00004142 case IPCOP_msgrcv:
4143 switch (version) {
4144 case 0:
4145 {
4146 struct target_ipc_kludge {
4147 abi_long msgp;
4148 abi_long msgtyp;
4149 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004150
aurel321c54ff92008-10-13 21:08:44 +00004151 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4152 ret = -TARGET_EFAULT;
4153 break;
ths1bc012f2007-06-03 14:27:49 +00004154 }
aurel321c54ff92008-10-13 21:08:44 +00004155
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004156 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004157
4158 unlock_user_struct(tmp, ptr, 0);
4159 break;
4160 }
4161 default:
4162 ret = do_msgrcv(first, ptr, second, fifth, third);
4163 }
4164 break;
thsd96372e2007-02-02 22:05:44 +00004165
bellard8853f862004-02-22 14:57:26 +00004166 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004167 switch (version) {
4168 default:
bellard5a4a8982007-11-11 17:39:18 +00004169 {
4170 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004171 raddr = do_shmat(first, ptr, second);
4172 if (is_error(raddr))
4173 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004174 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004175 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004176 break;
4177 }
4178 case 1:
4179 ret = -TARGET_EINVAL;
4180 break;
bellard5a4a8982007-11-11 17:39:18 +00004181 }
bellard8853f862004-02-22 14:57:26 +00004182 break;
4183 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004184 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004185 break;
4186
4187 case IPCOP_shmget:
4188 /* IPC_* flag values are the same on all linux platforms */
4189 ret = get_errno(shmget(first, second, third));
4190 break;
4191
4192 /* IPC_* and SHM_* command values are the same on all linux platforms */
4193 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004194 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004195 break;
4196 default:
j_mayer32407102007-09-26 23:01:49 +00004197 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004198 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004199 break;
4200 }
4201 return ret;
4202}
j_mayer32407102007-09-26 23:01:49 +00004203#endif
bellard8853f862004-02-22 14:57:26 +00004204
bellard31e31b82003-02-18 22:55:36 +00004205/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004206
Blue Swirl001faf32009-05-13 17:53:17 +00004207#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004208#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4209enum {
4210#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004211STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004212};
4213#undef STRUCT
4214#undef STRUCT_SPECIAL
4215
Blue Swirl001faf32009-05-13 17:53:17 +00004216#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004217#define STRUCT_SPECIAL(name)
4218#include "syscall_types.h"
4219#undef STRUCT
4220#undef STRUCT_SPECIAL
4221
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004222typedef struct IOCTLEntry IOCTLEntry;
4223
4224typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004225 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004226
4227struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004228 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004229 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004230 const char *name;
4231 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004232 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004233 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004234};
bellard31e31b82003-02-18 22:55:36 +00004235
4236#define IOC_R 0x0001
4237#define IOC_W 0x0002
4238#define IOC_RW (IOC_R | IOC_W)
4239
4240#define MAX_STRUCT_SIZE 4096
4241
Peter Maydelldace20d2011-01-10 13:11:24 +00004242#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004243/* So fiemap access checks don't overflow on 32 bit systems.
4244 * This is very slightly smaller than the limit imposed by
4245 * the underlying kernel.
4246 */
4247#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4248 / sizeof(struct fiemap_extent))
4249
4250static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004251 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004252{
4253 /* The parameter for this ioctl is a struct fiemap followed
4254 * by an array of struct fiemap_extent whose size is set
4255 * in fiemap->fm_extent_count. The array is filled in by the
4256 * ioctl.
4257 */
4258 int target_size_in, target_size_out;
4259 struct fiemap *fm;
4260 const argtype *arg_type = ie->arg_type;
4261 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4262 void *argptr, *p;
4263 abi_long ret;
4264 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4265 uint32_t outbufsz;
4266 int free_fm = 0;
4267
4268 assert(arg_type[0] == TYPE_PTR);
4269 assert(ie->access == IOC_RW);
4270 arg_type++;
4271 target_size_in = thunk_type_size(arg_type, 0);
4272 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4273 if (!argptr) {
4274 return -TARGET_EFAULT;
4275 }
4276 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4277 unlock_user(argptr, arg, 0);
4278 fm = (struct fiemap *)buf_temp;
4279 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4280 return -TARGET_EINVAL;
4281 }
4282
4283 outbufsz = sizeof (*fm) +
4284 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4285
4286 if (outbufsz > MAX_STRUCT_SIZE) {
4287 /* We can't fit all the extents into the fixed size buffer.
4288 * Allocate one that is large enough and use it instead.
4289 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304290 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004291 if (!fm) {
4292 return -TARGET_ENOMEM;
4293 }
4294 memcpy(fm, buf_temp, sizeof(struct fiemap));
4295 free_fm = 1;
4296 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004297 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004298 if (!is_error(ret)) {
4299 target_size_out = target_size_in;
4300 /* An extent_count of 0 means we were only counting the extents
4301 * so there are no structs to copy
4302 */
4303 if (fm->fm_extent_count != 0) {
4304 target_size_out += fm->fm_mapped_extents * extent_size;
4305 }
4306 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4307 if (!argptr) {
4308 ret = -TARGET_EFAULT;
4309 } else {
4310 /* Convert the struct fiemap */
4311 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4312 if (fm->fm_extent_count != 0) {
4313 p = argptr + target_size_in;
4314 /* ...and then all the struct fiemap_extents */
4315 for (i = 0; i < fm->fm_mapped_extents; i++) {
4316 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4317 THUNK_TARGET);
4318 p += extent_size;
4319 }
4320 }
4321 unlock_user(argptr, arg, target_size_out);
4322 }
4323 }
4324 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304325 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004326 }
4327 return ret;
4328}
Peter Maydelldace20d2011-01-10 13:11:24 +00004329#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004330
Laurent Vivier059c2f22011-03-30 00:12:12 +02004331static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004332 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004333{
4334 const argtype *arg_type = ie->arg_type;
4335 int target_size;
4336 void *argptr;
4337 int ret;
4338 struct ifconf *host_ifconf;
4339 uint32_t outbufsz;
4340 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4341 int target_ifreq_size;
4342 int nb_ifreq;
4343 int free_buf = 0;
4344 int i;
4345 int target_ifc_len;
4346 abi_long target_ifc_buf;
4347 int host_ifc_len;
4348 char *host_ifc_buf;
4349
4350 assert(arg_type[0] == TYPE_PTR);
4351 assert(ie->access == IOC_RW);
4352
4353 arg_type++;
4354 target_size = thunk_type_size(arg_type, 0);
4355
4356 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4357 if (!argptr)
4358 return -TARGET_EFAULT;
4359 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4360 unlock_user(argptr, arg, 0);
4361
4362 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4363 target_ifc_len = host_ifconf->ifc_len;
4364 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4365
4366 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4367 nb_ifreq = target_ifc_len / target_ifreq_size;
4368 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4369
4370 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4371 if (outbufsz > MAX_STRUCT_SIZE) {
4372 /* We can't fit all the extents into the fixed size buffer.
4373 * Allocate one that is large enough and use it instead.
4374 */
4375 host_ifconf = malloc(outbufsz);
4376 if (!host_ifconf) {
4377 return -TARGET_ENOMEM;
4378 }
4379 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4380 free_buf = 1;
4381 }
4382 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4383
4384 host_ifconf->ifc_len = host_ifc_len;
4385 host_ifconf->ifc_buf = host_ifc_buf;
4386
Peter Maydell49ca6f32016-06-06 19:58:14 +01004387 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004388 if (!is_error(ret)) {
4389 /* convert host ifc_len to target ifc_len */
4390
4391 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4392 target_ifc_len = nb_ifreq * target_ifreq_size;
4393 host_ifconf->ifc_len = target_ifc_len;
4394
4395 /* restore target ifc_buf */
4396
4397 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4398
4399 /* copy struct ifconf to target user */
4400
4401 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4402 if (!argptr)
4403 return -TARGET_EFAULT;
4404 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4405 unlock_user(argptr, arg, target_size);
4406
4407 /* copy ifreq[] to target user */
4408
4409 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4410 for (i = 0; i < nb_ifreq ; i++) {
4411 thunk_convert(argptr + i * target_ifreq_size,
4412 host_ifc_buf + i * sizeof(struct ifreq),
4413 ifreq_arg_type, THUNK_TARGET);
4414 }
4415 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4416 }
4417
4418 if (free_buf) {
4419 free(host_ifconf);
4420 }
4421
4422 return ret;
4423}
4424
Alexander Graf56e904e2012-01-31 18:42:06 +01004425static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004426 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004427{
4428 void *argptr;
4429 struct dm_ioctl *host_dm;
4430 abi_long guest_data;
4431 uint32_t guest_data_size;
4432 int target_size;
4433 const argtype *arg_type = ie->arg_type;
4434 abi_long ret;
4435 void *big_buf = NULL;
4436 char *host_data;
4437
4438 arg_type++;
4439 target_size = thunk_type_size(arg_type, 0);
4440 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4441 if (!argptr) {
4442 ret = -TARGET_EFAULT;
4443 goto out;
4444 }
4445 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4446 unlock_user(argptr, arg, 0);
4447
4448 /* buf_temp is too small, so fetch things into a bigger buffer */
4449 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4450 memcpy(big_buf, buf_temp, target_size);
4451 buf_temp = big_buf;
4452 host_dm = big_buf;
4453
4454 guest_data = arg + host_dm->data_start;
4455 if ((guest_data - arg) < 0) {
4456 ret = -EINVAL;
4457 goto out;
4458 }
4459 guest_data_size = host_dm->data_size - host_dm->data_start;
4460 host_data = (char*)host_dm + host_dm->data_start;
4461
4462 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4463 switch (ie->host_cmd) {
4464 case DM_REMOVE_ALL:
4465 case DM_LIST_DEVICES:
4466 case DM_DEV_CREATE:
4467 case DM_DEV_REMOVE:
4468 case DM_DEV_SUSPEND:
4469 case DM_DEV_STATUS:
4470 case DM_DEV_WAIT:
4471 case DM_TABLE_STATUS:
4472 case DM_TABLE_CLEAR:
4473 case DM_TABLE_DEPS:
4474 case DM_LIST_VERSIONS:
4475 /* no input data */
4476 break;
4477 case DM_DEV_RENAME:
4478 case DM_DEV_SET_GEOMETRY:
4479 /* data contains only strings */
4480 memcpy(host_data, argptr, guest_data_size);
4481 break;
4482 case DM_TARGET_MSG:
4483 memcpy(host_data, argptr, guest_data_size);
4484 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4485 break;
4486 case DM_TABLE_LOAD:
4487 {
4488 void *gspec = argptr;
4489 void *cur_data = host_data;
4490 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4491 int spec_size = thunk_type_size(arg_type, 0);
4492 int i;
4493
4494 for (i = 0; i < host_dm->target_count; i++) {
4495 struct dm_target_spec *spec = cur_data;
4496 uint32_t next;
4497 int slen;
4498
4499 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4500 slen = strlen((char*)gspec + spec_size) + 1;
4501 next = spec->next;
4502 spec->next = sizeof(*spec) + slen;
4503 strcpy((char*)&spec[1], gspec + spec_size);
4504 gspec += next;
4505 cur_data += spec->next;
4506 }
4507 break;
4508 }
4509 default:
4510 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004511 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004512 goto out;
4513 }
4514 unlock_user(argptr, guest_data, 0);
4515
Peter Maydell49ca6f32016-06-06 19:58:14 +01004516 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01004517 if (!is_error(ret)) {
4518 guest_data = arg + host_dm->data_start;
4519 guest_data_size = host_dm->data_size - host_dm->data_start;
4520 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4521 switch (ie->host_cmd) {
4522 case DM_REMOVE_ALL:
4523 case DM_DEV_CREATE:
4524 case DM_DEV_REMOVE:
4525 case DM_DEV_RENAME:
4526 case DM_DEV_SUSPEND:
4527 case DM_DEV_STATUS:
4528 case DM_TABLE_LOAD:
4529 case DM_TABLE_CLEAR:
4530 case DM_TARGET_MSG:
4531 case DM_DEV_SET_GEOMETRY:
4532 /* no return data */
4533 break;
4534 case DM_LIST_DEVICES:
4535 {
4536 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4537 uint32_t remaining_data = guest_data_size;
4538 void *cur_data = argptr;
4539 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4540 int nl_size = 12; /* can't use thunk_size due to alignment */
4541
4542 while (1) {
4543 uint32_t next = nl->next;
4544 if (next) {
4545 nl->next = nl_size + (strlen(nl->name) + 1);
4546 }
4547 if (remaining_data < nl->next) {
4548 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4549 break;
4550 }
4551 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4552 strcpy(cur_data + nl_size, nl->name);
4553 cur_data += nl->next;
4554 remaining_data -= nl->next;
4555 if (!next) {
4556 break;
4557 }
4558 nl = (void*)nl + next;
4559 }
4560 break;
4561 }
4562 case DM_DEV_WAIT:
4563 case DM_TABLE_STATUS:
4564 {
4565 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4566 void *cur_data = argptr;
4567 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4568 int spec_size = thunk_type_size(arg_type, 0);
4569 int i;
4570
4571 for (i = 0; i < host_dm->target_count; i++) {
4572 uint32_t next = spec->next;
4573 int slen = strlen((char*)&spec[1]) + 1;
4574 spec->next = (cur_data - argptr) + spec_size + slen;
4575 if (guest_data_size < spec->next) {
4576 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4577 break;
4578 }
4579 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4580 strcpy(cur_data + spec_size, (char*)&spec[1]);
4581 cur_data = argptr + spec->next;
4582 spec = (void*)host_dm + host_dm->data_start + next;
4583 }
4584 break;
4585 }
4586 case DM_TABLE_DEPS:
4587 {
4588 void *hdata = (void*)host_dm + host_dm->data_start;
4589 int count = *(uint32_t*)hdata;
4590 uint64_t *hdev = hdata + 8;
4591 uint64_t *gdev = argptr + 8;
4592 int i;
4593
4594 *(uint32_t*)argptr = tswap32(count);
4595 for (i = 0; i < count; i++) {
4596 *gdev = tswap64(*hdev);
4597 gdev++;
4598 hdev++;
4599 }
4600 break;
4601 }
4602 case DM_LIST_VERSIONS:
4603 {
4604 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4605 uint32_t remaining_data = guest_data_size;
4606 void *cur_data = argptr;
4607 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4608 int vers_size = thunk_type_size(arg_type, 0);
4609
4610 while (1) {
4611 uint32_t next = vers->next;
4612 if (next) {
4613 vers->next = vers_size + (strlen(vers->name) + 1);
4614 }
4615 if (remaining_data < vers->next) {
4616 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4617 break;
4618 }
4619 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4620 strcpy(cur_data + vers_size, vers->name);
4621 cur_data += vers->next;
4622 remaining_data -= vers->next;
4623 if (!next) {
4624 break;
4625 }
4626 vers = (void*)vers + next;
4627 }
4628 break;
4629 }
4630 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004631 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004632 ret = -TARGET_EINVAL;
4633 goto out;
4634 }
4635 unlock_user(argptr, guest_data, guest_data_size);
4636
4637 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4638 if (!argptr) {
4639 ret = -TARGET_EFAULT;
4640 goto out;
4641 }
4642 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4643 unlock_user(argptr, arg, target_size);
4644 }
4645out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004646 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004647 return ret;
4648}
4649
Alexander Grafa59b5e32014-08-22 13:15:50 +02004650static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004651 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004652{
4653 void *argptr;
4654 int target_size;
4655 const argtype *arg_type = ie->arg_type;
4656 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4657 abi_long ret;
4658
4659 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4660 struct blkpg_partition host_part;
4661
4662 /* Read and convert blkpg */
4663 arg_type++;
4664 target_size = thunk_type_size(arg_type, 0);
4665 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4666 if (!argptr) {
4667 ret = -TARGET_EFAULT;
4668 goto out;
4669 }
4670 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4671 unlock_user(argptr, arg, 0);
4672
4673 switch (host_blkpg->op) {
4674 case BLKPG_ADD_PARTITION:
4675 case BLKPG_DEL_PARTITION:
4676 /* payload is struct blkpg_partition */
4677 break;
4678 default:
4679 /* Unknown opcode */
4680 ret = -TARGET_EINVAL;
4681 goto out;
4682 }
4683
4684 /* Read and convert blkpg->data */
4685 arg = (abi_long)(uintptr_t)host_blkpg->data;
4686 target_size = thunk_type_size(part_arg_type, 0);
4687 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4688 if (!argptr) {
4689 ret = -TARGET_EFAULT;
4690 goto out;
4691 }
4692 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4693 unlock_user(argptr, arg, 0);
4694
4695 /* Swizzle the data pointer to our local copy and call! */
4696 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01004697 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02004698
4699out:
4700 return ret;
4701}
4702
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004703static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004704 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004705{
4706 const argtype *arg_type = ie->arg_type;
4707 const StructEntry *se;
4708 const argtype *field_types;
4709 const int *dst_offsets, *src_offsets;
4710 int target_size;
4711 void *argptr;
4712 abi_ulong *target_rt_dev_ptr;
4713 unsigned long *host_rt_dev_ptr;
4714 abi_long ret;
4715 int i;
4716
4717 assert(ie->access == IOC_W);
4718 assert(*arg_type == TYPE_PTR);
4719 arg_type++;
4720 assert(*arg_type == TYPE_STRUCT);
4721 target_size = thunk_type_size(arg_type, 0);
4722 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4723 if (!argptr) {
4724 return -TARGET_EFAULT;
4725 }
4726 arg_type++;
4727 assert(*arg_type == (int)STRUCT_rtentry);
4728 se = struct_entries + *arg_type++;
4729 assert(se->convert[0] == NULL);
4730 /* convert struct here to be able to catch rt_dev string */
4731 field_types = se->field_types;
4732 dst_offsets = se->field_offsets[THUNK_HOST];
4733 src_offsets = se->field_offsets[THUNK_TARGET];
4734 for (i = 0; i < se->nb_fields; i++) {
4735 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4736 assert(*field_types == TYPE_PTRVOID);
4737 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4738 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4739 if (*target_rt_dev_ptr != 0) {
4740 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4741 tswapal(*target_rt_dev_ptr));
4742 if (!*host_rt_dev_ptr) {
4743 unlock_user(argptr, arg, 0);
4744 return -TARGET_EFAULT;
4745 }
4746 } else {
4747 *host_rt_dev_ptr = 0;
4748 }
4749 field_types++;
4750 continue;
4751 }
4752 field_types = thunk_convert(buf_temp + dst_offsets[i],
4753 argptr + src_offsets[i],
4754 field_types, THUNK_HOST);
4755 }
4756 unlock_user(argptr, arg, 0);
4757
Peter Maydell49ca6f32016-06-06 19:58:14 +01004758 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004759 if (*host_rt_dev_ptr != 0) {
4760 unlock_user((void *)*host_rt_dev_ptr,
4761 *target_rt_dev_ptr, 0);
4762 }
4763 return ret;
4764}
4765
Paul Burtonca56f5b2014-06-22 11:25:47 +01004766static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004767 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004768{
4769 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004770 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01004771}
4772
blueswir19f106a72008-10-05 10:52:52 +00004773static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004774#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004775 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4776#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4777 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004778#include "ioctls.h"
4779 { 0, 0, },
4780};
4781
pbrook53a59602006-03-25 19:31:22 +00004782/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004783/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004784static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004785{
4786 const IOCTLEntry *ie;
4787 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004788 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004789 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004790 int target_size;
4791 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004792
4793 ie = ioctl_entries;
4794 for(;;) {
4795 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004796 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004797 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004798 }
4799 if (ie->target_cmd == cmd)
4800 break;
4801 ie++;
4802 }
4803 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004804#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004805 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004806#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004807 if (ie->do_ioctl) {
4808 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4809 }
4810
bellard31e31b82003-02-18 22:55:36 +00004811 switch(arg_type[0]) {
4812 case TYPE_NULL:
4813 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01004814 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00004815 break;
4816 case TYPE_PTRVOID:
4817 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004818 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00004819 break;
4820 case TYPE_PTR:
4821 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004822 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004823 switch(ie->access) {
4824 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004825 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004826 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004827 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4828 if (!argptr)
4829 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004830 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4831 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004832 }
4833 break;
4834 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004835 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4836 if (!argptr)
4837 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004838 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4839 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004840 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004841 break;
4842 default:
4843 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004844 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4845 if (!argptr)
4846 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004847 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4848 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004849 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004850 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004851 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4852 if (!argptr)
4853 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004854 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4855 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004856 }
4857 break;
4858 }
4859 break;
4860 default:
j_mayer32407102007-09-26 23:01:49 +00004861 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4862 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004863 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004864 break;
4865 }
4866 return ret;
4867}
4868
blueswir1b39bc502008-10-05 10:51:10 +00004869static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004870 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4871 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4872 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4873 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4874 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4875 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4876 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4877 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4878 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4879 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4880 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4881 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4882 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4883 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4884 { 0, 0, 0, 0 }
4885};
4886
blueswir1b39bc502008-10-05 10:51:10 +00004887static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004888 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4889 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4890 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4891 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4892 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4893 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4894 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4895 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4896 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4897 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4898 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4899 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4900 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4901 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4902 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4903 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4904 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4905 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4906 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4907 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4908 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4909 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4910 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4911 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4912 { 0, 0, 0, 0 }
4913};
4914
blueswir1b39bc502008-10-05 10:51:10 +00004915static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004916 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4917 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4918 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4919 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4920 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4921 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4922 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4923 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4924 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4925 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4926 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4927 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4928 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4929 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4930 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4931 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4932 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4933 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4934 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4935 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4936 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4937 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4938 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4939 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4940 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4941 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4942 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4943 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4944 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4945 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4946 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4947 { 0, 0, 0, 0 }
4948};
4949
blueswir1b39bc502008-10-05 10:51:10 +00004950static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004951 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4952 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4953 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4954 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4955 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4956 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4957 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4958 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4959 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4960 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4961 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4962 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4963 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4964 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4965 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4966 { 0, 0, 0, 0 }
4967};
4968
4969static void target_to_host_termios (void *dst, const void *src)
4970{
4971 struct host_termios *host = dst;
4972 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004973
ths5fafdf22007-09-16 21:08:06 +00004974 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004975 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004976 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004977 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004978 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004979 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004980 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004981 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4982 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004983
Arnaud Patard44607122009-04-21 17:39:08 +03004984 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004985 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4986 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004987 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004988 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004989 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004990 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004991 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004992 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004993 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004994 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4995 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004996 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4997 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4998 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4999 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5000 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005001 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005002}
ths3b46e622007-09-17 08:09:54 +00005003
bellard31e31b82003-02-18 22:55:36 +00005004static void host_to_target_termios (void *dst, const void *src)
5005{
5006 struct target_termios *target = dst;
5007 const struct host_termios *host = src;
5008
ths5fafdf22007-09-16 21:08:06 +00005009 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005010 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005011 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005012 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005013 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005014 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005015 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005016 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5017 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005018
Arnaud Patard44607122009-04-21 17:39:08 +03005019 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005020 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5021 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5022 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5023 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5024 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5025 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5026 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5027 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5028 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5029 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5030 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5031 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5032 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5033 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5034 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5035 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5036 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5037}
5038
blueswir18e853dc2008-10-05 10:49:32 +00005039static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005040 .convert = { host_to_target_termios, target_to_host_termios },
5041 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5042 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5043};
5044
bellard5286db72003-06-05 00:57:30 +00005045static bitmask_transtbl mmap_flags_tbl[] = {
5046 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5047 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5048 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5049 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5050 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5051 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5052 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5053 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005054 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5055 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005056 { 0, 0, 0, 0 }
5057};
5058
bellard2ab83ea2003-06-15 19:56:46 +00005059#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005060
5061/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005062static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005063
bellard03acab62007-11-11 14:57:14 +00005064static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005065{
5066 int size;
pbrook53a59602006-03-25 19:31:22 +00005067 void *p;
bellard6dbad632003-03-16 18:05:05 +00005068
5069 if (!ldt_table)
5070 return 0;
5071 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5072 if (size > bytecount)
5073 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005074 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5075 if (!p)
bellard03acab62007-11-11 14:57:14 +00005076 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005077 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005078 memcpy(p, ldt_table, size);
5079 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005080 return size;
5081}
5082
5083/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005084static abi_long write_ldt(CPUX86State *env,
5085 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005086{
5087 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005088 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005089 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005090 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005091 uint32_t *lp, entry_1, entry_2;
5092
5093 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005094 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005095 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005096 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005097 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005098 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005099 ldt_info.limit = tswap32(target_ldt_info->limit);
5100 ldt_info.flags = tswap32(target_ldt_info->flags);
5101 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005102
bellard6dbad632003-03-16 18:05:05 +00005103 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005104 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005105 seg_32bit = ldt_info.flags & 1;
5106 contents = (ldt_info.flags >> 1) & 3;
5107 read_exec_only = (ldt_info.flags >> 3) & 1;
5108 limit_in_pages = (ldt_info.flags >> 4) & 1;
5109 seg_not_present = (ldt_info.flags >> 5) & 1;
5110 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005111#ifdef TARGET_ABI32
5112 lm = 0;
5113#else
5114 lm = (ldt_info.flags >> 7) & 1;
5115#endif
bellard6dbad632003-03-16 18:05:05 +00005116 if (contents == 3) {
5117 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005118 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005119 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005120 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005121 }
5122 /* allocate the LDT */
5123 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005124 env->ldt.base = target_mmap(0,
5125 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5126 PROT_READ|PROT_WRITE,
5127 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5128 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005129 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005130 memset(g2h(env->ldt.base), 0,
5131 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005132 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005133 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005134 }
5135
5136 /* NOTE: same code as Linux kernel */
5137 /* Allow LDTs to be cleared by the user. */
5138 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5139 if (oldmode ||
5140 (contents == 0 &&
5141 read_exec_only == 1 &&
5142 seg_32bit == 0 &&
5143 limit_in_pages == 0 &&
5144 seg_not_present == 1 &&
5145 useable == 0 )) {
5146 entry_1 = 0;
5147 entry_2 = 0;
5148 goto install;
5149 }
5150 }
ths3b46e622007-09-17 08:09:54 +00005151
bellard6dbad632003-03-16 18:05:05 +00005152 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5153 (ldt_info.limit & 0x0ffff);
5154 entry_2 = (ldt_info.base_addr & 0xff000000) |
5155 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5156 (ldt_info.limit & 0xf0000) |
5157 ((read_exec_only ^ 1) << 9) |
5158 (contents << 10) |
5159 ((seg_not_present ^ 1) << 15) |
5160 (seg_32bit << 22) |
5161 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005162 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005163 0x7000;
5164 if (!oldmode)
5165 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005166
bellard6dbad632003-03-16 18:05:05 +00005167 /* Install the new entry ... */
5168install:
5169 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5170 lp[0] = tswap32(entry_1);
5171 lp[1] = tswap32(entry_2);
5172 return 0;
5173}
5174
5175/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005176static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5177 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005178{
bellard03acab62007-11-11 14:57:14 +00005179 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005180
bellard6dbad632003-03-16 18:05:05 +00005181 switch (func) {
5182 case 0:
5183 ret = read_ldt(ptr, bytecount);
5184 break;
5185 case 1:
5186 ret = write_ldt(env, ptr, bytecount, 1);
5187 break;
5188 case 0x11:
5189 ret = write_ldt(env, ptr, bytecount, 0);
5190 break;
bellard03acab62007-11-11 14:57:14 +00005191 default:
5192 ret = -TARGET_ENOSYS;
5193 break;
bellard6dbad632003-03-16 18:05:05 +00005194 }
5195 return ret;
5196}
bellard1b6b0292003-03-22 17:31:38 +00005197
blueswir14583f582008-08-24 10:35:55 +00005198#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005199abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005200{
5201 uint64_t *gdt_table = g2h(env->gdt.base);
5202 struct target_modify_ldt_ldt_s ldt_info;
5203 struct target_modify_ldt_ldt_s *target_ldt_info;
5204 int seg_32bit, contents, read_exec_only, limit_in_pages;
5205 int seg_not_present, useable, lm;
5206 uint32_t *lp, entry_1, entry_2;
5207 int i;
5208
5209 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5210 if (!target_ldt_info)
5211 return -TARGET_EFAULT;
5212 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005213 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005214 ldt_info.limit = tswap32(target_ldt_info->limit);
5215 ldt_info.flags = tswap32(target_ldt_info->flags);
5216 if (ldt_info.entry_number == -1) {
5217 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5218 if (gdt_table[i] == 0) {
5219 ldt_info.entry_number = i;
5220 target_ldt_info->entry_number = tswap32(i);
5221 break;
5222 }
5223 }
5224 }
5225 unlock_user_struct(target_ldt_info, ptr, 1);
5226
5227 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5228 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5229 return -TARGET_EINVAL;
5230 seg_32bit = ldt_info.flags & 1;
5231 contents = (ldt_info.flags >> 1) & 3;
5232 read_exec_only = (ldt_info.flags >> 3) & 1;
5233 limit_in_pages = (ldt_info.flags >> 4) & 1;
5234 seg_not_present = (ldt_info.flags >> 5) & 1;
5235 useable = (ldt_info.flags >> 6) & 1;
5236#ifdef TARGET_ABI32
5237 lm = 0;
5238#else
5239 lm = (ldt_info.flags >> 7) & 1;
5240#endif
5241
5242 if (contents == 3) {
5243 if (seg_not_present == 0)
5244 return -TARGET_EINVAL;
5245 }
5246
5247 /* NOTE: same code as Linux kernel */
5248 /* Allow LDTs to be cleared by the user. */
5249 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5250 if ((contents == 0 &&
5251 read_exec_only == 1 &&
5252 seg_32bit == 0 &&
5253 limit_in_pages == 0 &&
5254 seg_not_present == 1 &&
5255 useable == 0 )) {
5256 entry_1 = 0;
5257 entry_2 = 0;
5258 goto install;
5259 }
5260 }
5261
5262 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5263 (ldt_info.limit & 0x0ffff);
5264 entry_2 = (ldt_info.base_addr & 0xff000000) |
5265 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5266 (ldt_info.limit & 0xf0000) |
5267 ((read_exec_only ^ 1) << 9) |
5268 (contents << 10) |
5269 ((seg_not_present ^ 1) << 15) |
5270 (seg_32bit << 22) |
5271 (limit_in_pages << 23) |
5272 (useable << 20) |
5273 (lm << 21) |
5274 0x7000;
5275
5276 /* Install the new entry ... */
5277install:
5278 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5279 lp[0] = tswap32(entry_1);
5280 lp[1] = tswap32(entry_2);
5281 return 0;
5282}
5283
blueswir18fcd3692008-08-17 20:26:25 +00005284static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005285{
5286 struct target_modify_ldt_ldt_s *target_ldt_info;
5287 uint64_t *gdt_table = g2h(env->gdt.base);
5288 uint32_t base_addr, limit, flags;
5289 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5290 int seg_not_present, useable, lm;
5291 uint32_t *lp, entry_1, entry_2;
5292
5293 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5294 if (!target_ldt_info)
5295 return -TARGET_EFAULT;
5296 idx = tswap32(target_ldt_info->entry_number);
5297 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5298 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5299 unlock_user_struct(target_ldt_info, ptr, 1);
5300 return -TARGET_EINVAL;
5301 }
5302 lp = (uint32_t *)(gdt_table + idx);
5303 entry_1 = tswap32(lp[0]);
5304 entry_2 = tswap32(lp[1]);
5305
5306 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5307 contents = (entry_2 >> 10) & 3;
5308 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5309 seg_32bit = (entry_2 >> 22) & 1;
5310 limit_in_pages = (entry_2 >> 23) & 1;
5311 useable = (entry_2 >> 20) & 1;
5312#ifdef TARGET_ABI32
5313 lm = 0;
5314#else
5315 lm = (entry_2 >> 21) & 1;
5316#endif
5317 flags = (seg_32bit << 0) | (contents << 1) |
5318 (read_exec_only << 3) | (limit_in_pages << 4) |
5319 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5320 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5321 base_addr = (entry_1 >> 16) |
5322 (entry_2 & 0xff000000) |
5323 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005324 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005325 target_ldt_info->limit = tswap32(limit);
5326 target_ldt_info->flags = tswap32(flags);
5327 unlock_user_struct(target_ldt_info, ptr, 1);
5328 return 0;
5329}
blueswir14583f582008-08-24 10:35:55 +00005330#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005331
bellardd2fd1af2007-11-14 18:08:56 +00005332#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005333abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005334{
Juan Quintela1add8692011-06-16 17:37:09 +01005335 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005336 abi_ulong val;
5337 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005338
bellardd2fd1af2007-11-14 18:08:56 +00005339 switch(code) {
5340 case TARGET_ARCH_SET_GS:
5341 case TARGET_ARCH_SET_FS:
5342 if (code == TARGET_ARCH_SET_GS)
5343 idx = R_GS;
5344 else
5345 idx = R_FS;
5346 cpu_x86_load_seg(env, idx, 0);
5347 env->segs[idx].base = addr;
5348 break;
5349 case TARGET_ARCH_GET_GS:
5350 case TARGET_ARCH_GET_FS:
5351 if (code == TARGET_ARCH_GET_GS)
5352 idx = R_GS;
5353 else
5354 idx = R_FS;
5355 val = env->segs[idx].base;
5356 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005357 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005358 break;
5359 default:
5360 ret = -TARGET_EINVAL;
5361 break;
5362 }
Juan Quintela1add8692011-06-16 17:37:09 +01005363 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005364}
5365#endif
5366
bellard2ab83ea2003-06-15 19:56:46 +00005367#endif /* defined(TARGET_I386) */
5368
Riku Voipio05098a92011-03-04 15:27:29 +02005369#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005370
pbrookd865bab2008-06-07 22:12:17 +00005371
5372static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5373typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005374 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005375 pthread_mutex_t mutex;
5376 pthread_cond_t cond;
5377 pthread_t thread;
5378 uint32_t tid;
5379 abi_ulong child_tidptr;
5380 abi_ulong parent_tidptr;
5381 sigset_t sigmask;
5382} new_thread_info;
5383
5384static void *clone_func(void *arg)
5385{
5386 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005387 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005388 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005389 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005390
Emilio G. Cota70903762015-08-23 20:23:41 -04005391 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005392 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005393 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005394 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005395 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005396 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005397 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005398 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005399 if (info->child_tidptr)
5400 put_user_u32(info->tid, info->child_tidptr);
5401 if (info->parent_tidptr)
5402 put_user_u32(info->tid, info->parent_tidptr);
5403 /* Enable signals. */
5404 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5405 /* Signal to the parent that we're ready. */
5406 pthread_mutex_lock(&info->mutex);
5407 pthread_cond_broadcast(&info->cond);
5408 pthread_mutex_unlock(&info->mutex);
5409 /* Wait until the parent has finshed initializing the tls state. */
5410 pthread_mutex_lock(&clone_lock);
5411 pthread_mutex_unlock(&clone_lock);
5412 cpu_loop(env);
5413 /* never exits */
5414 return NULL;
5415}
bellard1b6b0292003-03-22 17:31:38 +00005416
ths0da46a62007-10-20 20:23:07 +00005417/* do_fork() Must return host values and target errnos (unlike most
5418 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005419static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005420 abi_ulong parent_tidptr, target_ulong newtls,
5421 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005422{
Andreas Färber0429a972013-08-26 18:14:44 +02005423 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005424 int ret;
bellard5cd43932003-03-29 16:54:36 +00005425 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005426 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005427 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005428 unsigned int nptl_flags;
5429 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005430
balrog436d1242008-09-21 02:39:45 +00005431 /* Emulate vfork() with fork() */
5432 if (flags & CLONE_VFORK)
5433 flags &= ~(CLONE_VFORK | CLONE_VM);
5434
bellard1b6b0292003-03-22 17:31:38 +00005435 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005436 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005437 new_thread_info info;
5438 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005439
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005440 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005441 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005442 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005443 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005444 /* Init regs that differ from the parent. */
5445 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005446 new_cpu = ENV_GET_CPU(new_env);
5447 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005448 ts->bprm = parent_ts->bprm;
5449 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005450 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005451 nptl_flags = flags;
5452 flags &= ~CLONE_NPTL_FLAGS2;
5453
pbrookc2764712009-03-07 15:24:59 +00005454 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5455 ts->child_tidptr = child_tidptr;
5456 }
5457
pbrookd865bab2008-06-07 22:12:17 +00005458 if (nptl_flags & CLONE_SETTLS)
5459 cpu_set_tls (new_env, newtls);
5460
5461 /* Grab a mutex so that thread setup appears atomic. */
5462 pthread_mutex_lock(&clone_lock);
5463
5464 memset(&info, 0, sizeof(info));
5465 pthread_mutex_init(&info.mutex, NULL);
5466 pthread_mutex_lock(&info.mutex);
5467 pthread_cond_init(&info.cond, NULL);
5468 info.env = new_env;
5469 if (nptl_flags & CLONE_CHILD_SETTID)
5470 info.child_tidptr = child_tidptr;
5471 if (nptl_flags & CLONE_PARENT_SETTID)
5472 info.parent_tidptr = parent_tidptr;
5473
5474 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005475 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5476 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005477 /* It is not safe to deliver signals until the child has finished
5478 initializing, so temporarily block all signals. */
5479 sigfillset(&sigmask);
5480 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5481
5482 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005483 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005484
5485 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5486 pthread_attr_destroy(&attr);
5487 if (ret == 0) {
5488 /* Wait for the child to initialize. */
5489 pthread_cond_wait(&info.cond, &info.mutex);
5490 ret = info.tid;
5491 if (flags & CLONE_PARENT_SETTID)
5492 put_user_u32(ret, parent_tidptr);
5493 } else {
5494 ret = -1;
5495 }
5496 pthread_mutex_unlock(&info.mutex);
5497 pthread_cond_destroy(&info.cond);
5498 pthread_mutex_destroy(&info.mutex);
5499 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005500 } else {
5501 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005502 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5503 return -TARGET_EINVAL;
5504 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005505
5506 if (block_signals()) {
5507 return -TARGET_ERESTARTSYS;
5508 }
5509
pbrookd865bab2008-06-07 22:12:17 +00005510 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005511 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005512 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005513 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005514 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005515 cpu_clone_regs(env, newsp);
5516 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005517 /* There is a race condition here. The parent process could
5518 theoretically read the TID in the child process before the child
5519 tid is set. This would require using either ptrace
5520 (not implemented) or having *_tidptr to point at a shared memory
5521 mapping. We can't repeat the spinlock hack used above because
5522 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005523 if (flags & CLONE_CHILD_SETTID)
5524 put_user_u32(gettid(), child_tidptr);
5525 if (flags & CLONE_PARENT_SETTID)
5526 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005527 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005528 if (flags & CLONE_SETTLS)
5529 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005530 if (flags & CLONE_CHILD_CLEARTID)
5531 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005532 } else {
5533 fork_end(0);
5534 }
bellard1b6b0292003-03-22 17:31:38 +00005535 }
5536 return ret;
5537}
5538
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005539/* warning : doesn't handle linux specific flags... */
5540static int target_to_host_fcntl_cmd(int cmd)
5541{
5542 switch(cmd) {
5543 case TARGET_F_DUPFD:
5544 case TARGET_F_GETFD:
5545 case TARGET_F_SETFD:
5546 case TARGET_F_GETFL:
5547 case TARGET_F_SETFL:
5548 return cmd;
5549 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005550 return F_GETLK64;
5551 case TARGET_F_SETLK:
5552 return F_SETLK64;
5553 case TARGET_F_SETLKW:
5554 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005555 case TARGET_F_GETOWN:
5556 return F_GETOWN;
5557 case TARGET_F_SETOWN:
5558 return F_SETOWN;
5559 case TARGET_F_GETSIG:
5560 return F_GETSIG;
5561 case TARGET_F_SETSIG:
5562 return F_SETSIG;
5563#if TARGET_ABI_BITS == 32
5564 case TARGET_F_GETLK64:
5565 return F_GETLK64;
5566 case TARGET_F_SETLK64:
5567 return F_SETLK64;
5568 case TARGET_F_SETLKW64:
5569 return F_SETLKW64;
5570#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005571 case TARGET_F_SETLEASE:
5572 return F_SETLEASE;
5573 case TARGET_F_GETLEASE:
5574 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005575#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005576 case TARGET_F_DUPFD_CLOEXEC:
5577 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005578#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005579 case TARGET_F_NOTIFY:
5580 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005581#ifdef F_GETOWN_EX
5582 case TARGET_F_GETOWN_EX:
5583 return F_GETOWN_EX;
5584#endif
5585#ifdef F_SETOWN_EX
5586 case TARGET_F_SETOWN_EX:
5587 return F_SETOWN_EX;
5588#endif
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005589 case TARGET_F_SETPIPE_SZ:
5590 return F_SETPIPE_SZ;
5591 case TARGET_F_GETPIPE_SZ:
5592 return F_GETPIPE_SZ;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005593 default:
5594 return -TARGET_EINVAL;
5595 }
5596 return -TARGET_EINVAL;
5597}
5598
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005599#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5600static const bitmask_transtbl flock_tbl[] = {
5601 TRANSTBL_CONVERT(F_RDLCK),
5602 TRANSTBL_CONVERT(F_WRLCK),
5603 TRANSTBL_CONVERT(F_UNLCK),
5604 TRANSTBL_CONVERT(F_EXLCK),
5605 TRANSTBL_CONVERT(F_SHLCK),
5606 { 0, 0, 0, 0 }
5607};
5608
Peter Maydell213d3e92016-06-13 11:22:05 +01005609static inline abi_long copy_from_user_flock(struct flock64 *fl,
5610 abi_ulong target_flock_addr)
5611{
5612 struct target_flock *target_fl;
5613 short l_type;
5614
5615 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5616 return -TARGET_EFAULT;
5617 }
5618
5619 __get_user(l_type, &target_fl->l_type);
5620 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5621 __get_user(fl->l_whence, &target_fl->l_whence);
5622 __get_user(fl->l_start, &target_fl->l_start);
5623 __get_user(fl->l_len, &target_fl->l_len);
5624 __get_user(fl->l_pid, &target_fl->l_pid);
5625 unlock_user_struct(target_fl, target_flock_addr, 0);
5626 return 0;
5627}
5628
5629static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
5630 const struct flock64 *fl)
5631{
5632 struct target_flock *target_fl;
5633 short l_type;
5634
5635 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5636 return -TARGET_EFAULT;
5637 }
5638
5639 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5640 __put_user(l_type, &target_fl->l_type);
5641 __put_user(fl->l_whence, &target_fl->l_whence);
5642 __put_user(fl->l_start, &target_fl->l_start);
5643 __put_user(fl->l_len, &target_fl->l_len);
5644 __put_user(fl->l_pid, &target_fl->l_pid);
5645 unlock_user_struct(target_fl, target_flock_addr, 1);
5646 return 0;
5647}
5648
5649typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
5650typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
5651
5652#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
5653static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
5654 abi_ulong target_flock_addr)
5655{
5656 struct target_eabi_flock64 *target_fl;
5657 short l_type;
5658
5659 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5660 return -TARGET_EFAULT;
5661 }
5662
5663 __get_user(l_type, &target_fl->l_type);
5664 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5665 __get_user(fl->l_whence, &target_fl->l_whence);
5666 __get_user(fl->l_start, &target_fl->l_start);
5667 __get_user(fl->l_len, &target_fl->l_len);
5668 __get_user(fl->l_pid, &target_fl->l_pid);
5669 unlock_user_struct(target_fl, target_flock_addr, 0);
5670 return 0;
5671}
5672
5673static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
5674 const struct flock64 *fl)
5675{
5676 struct target_eabi_flock64 *target_fl;
5677 short l_type;
5678
5679 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5680 return -TARGET_EFAULT;
5681 }
5682
5683 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5684 __put_user(l_type, &target_fl->l_type);
5685 __put_user(fl->l_whence, &target_fl->l_whence);
5686 __put_user(fl->l_start, &target_fl->l_start);
5687 __put_user(fl->l_len, &target_fl->l_len);
5688 __put_user(fl->l_pid, &target_fl->l_pid);
5689 unlock_user_struct(target_fl, target_flock_addr, 1);
5690 return 0;
5691}
5692#endif
5693
5694static inline abi_long copy_from_user_flock64(struct flock64 *fl,
5695 abi_ulong target_flock_addr)
5696{
5697 struct target_flock64 *target_fl;
5698 short l_type;
5699
5700 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5701 return -TARGET_EFAULT;
5702 }
5703
5704 __get_user(l_type, &target_fl->l_type);
5705 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5706 __get_user(fl->l_whence, &target_fl->l_whence);
5707 __get_user(fl->l_start, &target_fl->l_start);
5708 __get_user(fl->l_len, &target_fl->l_len);
5709 __get_user(fl->l_pid, &target_fl->l_pid);
5710 unlock_user_struct(target_fl, target_flock_addr, 0);
5711 return 0;
5712}
5713
5714static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
5715 const struct flock64 *fl)
5716{
5717 struct target_flock64 *target_fl;
5718 short l_type;
5719
5720 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5721 return -TARGET_EFAULT;
5722 }
5723
5724 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5725 __put_user(l_type, &target_fl->l_type);
5726 __put_user(fl->l_whence, &target_fl->l_whence);
5727 __put_user(fl->l_start, &target_fl->l_start);
5728 __put_user(fl->l_len, &target_fl->l_len);
5729 __put_user(fl->l_pid, &target_fl->l_pid);
5730 unlock_user_struct(target_fl, target_flock_addr, 1);
5731 return 0;
5732}
5733
blueswir1992f48a2007-10-14 16:27:31 +00005734static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005735{
ths43f238d2007-01-05 20:55:49 +00005736 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005737#ifdef F_GETOWN_EX
5738 struct f_owner_ex fox;
5739 struct target_f_owner_ex *target_fox;
5740#endif
blueswir1992f48a2007-10-14 16:27:31 +00005741 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005742 int host_cmd = target_to_host_fcntl_cmd(cmd);
5743
5744 if (host_cmd == -TARGET_EINVAL)
5745 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005746
bellard7775e9e2003-05-14 22:46:48 +00005747 switch(cmd) {
5748 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005749 ret = copy_from_user_flock(&fl64, arg);
5750 if (ret) {
5751 return ret;
5752 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005753 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005754 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005755 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00005756 }
5757 break;
ths3b46e622007-09-17 08:09:54 +00005758
bellard7775e9e2003-05-14 22:46:48 +00005759 case TARGET_F_SETLK:
5760 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01005761 ret = copy_from_user_flock(&fl64, arg);
5762 if (ret) {
5763 return ret;
5764 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005765 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005766 break;
ths3b46e622007-09-17 08:09:54 +00005767
bellard7775e9e2003-05-14 22:46:48 +00005768 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005769 ret = copy_from_user_flock64(&fl64, arg);
5770 if (ret) {
5771 return ret;
5772 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005773 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005774 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005775 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00005776 }
bellard9ee1fa22007-11-11 15:11:19 +00005777 break;
bellard7775e9e2003-05-14 22:46:48 +00005778 case TARGET_F_SETLK64:
5779 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005780 ret = copy_from_user_flock64(&fl64, arg);
5781 if (ret) {
5782 return ret;
5783 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005784 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005785 break;
5786
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005787 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005788 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005789 if (ret >= 0) {
5790 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5791 }
bellardffa65c32004-01-04 23:57:22 +00005792 break;
5793
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005794 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005795 ret = get_errno(safe_fcntl(fd, host_cmd,
5796 target_to_host_bitmask(arg,
5797 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005798 break;
5799
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005800#ifdef F_GETOWN_EX
5801 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01005802 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005803 if (ret >= 0) {
5804 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5805 return -TARGET_EFAULT;
5806 target_fox->type = tswap32(fox.type);
5807 target_fox->pid = tswap32(fox.pid);
5808 unlock_user_struct(target_fox, arg, 1);
5809 }
5810 break;
5811#endif
5812
5813#ifdef F_SETOWN_EX
5814 case TARGET_F_SETOWN_EX:
5815 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5816 return -TARGET_EFAULT;
5817 fox.type = tswap32(target_fox->type);
5818 fox.pid = tswap32(target_fox->pid);
5819 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01005820 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005821 break;
5822#endif
5823
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005824 case TARGET_F_SETOWN:
5825 case TARGET_F_GETOWN:
5826 case TARGET_F_SETSIG:
5827 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005828 case TARGET_F_SETLEASE:
5829 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005830 case TARGET_F_SETPIPE_SZ:
5831 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01005832 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005833 break;
5834
bellard7775e9e2003-05-14 22:46:48 +00005835 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01005836 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005837 break;
5838 }
5839 return ret;
5840}
5841
bellard67867302003-11-23 17:05:30 +00005842#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005843
bellard67867302003-11-23 17:05:30 +00005844static inline int high2lowuid(int uid)
5845{
5846 if (uid > 65535)
5847 return 65534;
5848 else
5849 return uid;
5850}
5851
5852static inline int high2lowgid(int gid)
5853{
5854 if (gid > 65535)
5855 return 65534;
5856 else
5857 return gid;
5858}
5859
5860static inline int low2highuid(int uid)
5861{
5862 if ((int16_t)uid == -1)
5863 return -1;
5864 else
5865 return uid;
5866}
5867
5868static inline int low2highgid(int gid)
5869{
5870 if ((int16_t)gid == -1)
5871 return -1;
5872 else
5873 return gid;
5874}
Riku Voipio0c866a72011-04-18 15:23:06 +03005875static inline int tswapid(int id)
5876{
5877 return tswap16(id);
5878}
Peter Maydell76ca3102014-03-02 19:36:41 +00005879
5880#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5881
Riku Voipio0c866a72011-04-18 15:23:06 +03005882#else /* !USE_UID16 */
5883static inline int high2lowuid(int uid)
5884{
5885 return uid;
5886}
5887static inline int high2lowgid(int gid)
5888{
5889 return gid;
5890}
5891static inline int low2highuid(int uid)
5892{
5893 return uid;
5894}
5895static inline int low2highgid(int gid)
5896{
5897 return gid;
5898}
5899static inline int tswapid(int id)
5900{
5901 return tswap32(id);
5902}
Peter Maydell76ca3102014-03-02 19:36:41 +00005903
5904#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5905
bellard67867302003-11-23 17:05:30 +00005906#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005907
Peter Maydellfd6f7792016-03-01 16:33:02 +00005908/* We must do direct syscalls for setting UID/GID, because we want to
5909 * implement the Linux system call semantics of "change only for this thread",
5910 * not the libc/POSIX semantics of "change for all threads in process".
5911 * (See http://ewontfix.com/17/ for more details.)
5912 * We use the 32-bit version of the syscalls if present; if it is not
5913 * then either the host architecture supports 32-bit UIDs natively with
5914 * the standard syscall, or the 16-bit UID is the best we can do.
5915 */
5916#ifdef __NR_setuid32
5917#define __NR_sys_setuid __NR_setuid32
5918#else
5919#define __NR_sys_setuid __NR_setuid
5920#endif
5921#ifdef __NR_setgid32
5922#define __NR_sys_setgid __NR_setgid32
5923#else
5924#define __NR_sys_setgid __NR_setgid
5925#endif
5926#ifdef __NR_setresuid32
5927#define __NR_sys_setresuid __NR_setresuid32
5928#else
5929#define __NR_sys_setresuid __NR_setresuid
5930#endif
5931#ifdef __NR_setresgid32
5932#define __NR_sys_setresgid __NR_setresgid32
5933#else
5934#define __NR_sys_setresgid __NR_setresgid
5935#endif
5936
5937_syscall1(int, sys_setuid, uid_t, uid)
5938_syscall1(int, sys_setgid, gid_t, gid)
5939_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
5940_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
5941
bellard31e31b82003-02-18 22:55:36 +00005942void syscall_init(void)
5943{
bellard2ab83ea2003-06-15 19:56:46 +00005944 IOCTLEntry *ie;
5945 const argtype *arg_type;
5946 int size;
thsb92c47c2007-11-01 00:07:38 +00005947 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005948
Alexander Graf8be656b2015-05-06 23:47:32 +02005949 thunk_init(STRUCT_MAX);
5950
Blue Swirl001faf32009-05-13 17:53:17 +00005951#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005952#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005953#include "syscall_types.h"
5954#undef STRUCT
5955#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005956
Peter Maydelldd6e9572012-07-23 08:07:22 +00005957 /* Build target_to_host_errno_table[] table from
5958 * host_to_target_errno_table[]. */
5959 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5960 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5961 }
5962
bellard2ab83ea2003-06-15 19:56:46 +00005963 /* we patch the ioctl size if necessary. We rely on the fact that
5964 no ioctl has all the bits at '1' in the size field */
5965 ie = ioctl_entries;
5966 while (ie->target_cmd != 0) {
5967 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5968 TARGET_IOC_SIZEMASK) {
5969 arg_type = ie->arg_type;
5970 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005971 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005972 ie->target_cmd);
5973 exit(1);
5974 }
5975 arg_type++;
5976 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005977 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005978 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5979 (size << TARGET_IOC_SIZESHIFT);
5980 }
thsb92c47c2007-11-01 00:07:38 +00005981
bellard2ab83ea2003-06-15 19:56:46 +00005982 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005983#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5984 (defined(__x86_64__) && defined(TARGET_X86_64))
5985 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5986 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5987 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005988 }
5989#endif
5990 ie++;
5991 }
bellard31e31b82003-02-18 22:55:36 +00005992}
bellardc573ff62004-01-04 15:51:36 +00005993
blueswir1992f48a2007-10-14 16:27:31 +00005994#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005995static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5996{
thsaf325d32008-06-10 15:29:15 +00005997#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005998 return ((uint64_t)word0 << 32) | word1;
5999#else
6000 return ((uint64_t)word1 << 32) | word0;
6001#endif
6002}
blueswir1992f48a2007-10-14 16:27:31 +00006003#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006004static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6005{
6006 return word0;
6007}
blueswir1992f48a2007-10-14 16:27:31 +00006008#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006009
6010#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006011static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6012 abi_long arg2,
6013 abi_long arg3,
6014 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006015{
Riku Voipio48e515d2011-07-12 15:40:51 +03006016 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006017 arg2 = arg3;
6018 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006019 }
pbrookce4defa2006-02-09 16:49:55 +00006020 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6021}
6022#endif
6023
6024#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006025static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6026 abi_long arg2,
6027 abi_long arg3,
6028 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006029{
Riku Voipio48e515d2011-07-12 15:40:51 +03006030 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006031 arg2 = arg3;
6032 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006033 }
pbrookce4defa2006-02-09 16:49:55 +00006034 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6035}
6036#endif
6037
bellard579a97f2007-11-11 14:26:47 +00006038static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6039 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006040{
6041 struct target_timespec *target_ts;
6042
bellard579a97f2007-11-11 14:26:47 +00006043 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6044 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006045 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6046 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006047 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006048 return 0;
pbrook53a59602006-03-25 19:31:22 +00006049}
6050
bellard579a97f2007-11-11 14:26:47 +00006051static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6052 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006053{
6054 struct target_timespec *target_ts;
6055
bellard579a97f2007-11-11 14:26:47 +00006056 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6057 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006058 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6059 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006060 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006061 return 0;
pbrook53a59602006-03-25 19:31:22 +00006062}
6063
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006064static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6065 abi_ulong target_addr)
6066{
6067 struct target_itimerspec *target_itspec;
6068
6069 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6070 return -TARGET_EFAULT;
6071 }
6072
6073 host_itspec->it_interval.tv_sec =
6074 tswapal(target_itspec->it_interval.tv_sec);
6075 host_itspec->it_interval.tv_nsec =
6076 tswapal(target_itspec->it_interval.tv_nsec);
6077 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6078 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6079
6080 unlock_user_struct(target_itspec, target_addr, 1);
6081 return 0;
6082}
6083
6084static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6085 struct itimerspec *host_its)
6086{
6087 struct target_itimerspec *target_itspec;
6088
6089 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6090 return -TARGET_EFAULT;
6091 }
6092
6093 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6094 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6095
6096 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6097 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6098
6099 unlock_user_struct(target_itspec, target_addr, 0);
6100 return 0;
6101}
6102
Peter Maydellc0659762014-08-09 15:42:32 +01006103static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6104 abi_ulong target_addr)
6105{
6106 struct target_sigevent *target_sevp;
6107
6108 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6109 return -TARGET_EFAULT;
6110 }
6111
6112 /* This union is awkward on 64 bit systems because it has a 32 bit
6113 * integer and a pointer in it; we follow the conversion approach
6114 * used for handling sigval types in signal.c so the guest should get
6115 * the correct value back even if we did a 64 bit byteswap and it's
6116 * using the 32 bit integer.
6117 */
6118 host_sevp->sigev_value.sival_ptr =
6119 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6120 host_sevp->sigev_signo =
6121 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6122 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6123 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6124
6125 unlock_user_struct(target_sevp, target_addr, 1);
6126 return 0;
6127}
6128
Tom Musta6f6a4032014-08-12 13:53:42 -05006129#if defined(TARGET_NR_mlockall)
6130static inline int target_to_host_mlockall_arg(int arg)
6131{
6132 int result = 0;
6133
6134 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6135 result |= MCL_CURRENT;
6136 }
6137 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6138 result |= MCL_FUTURE;
6139 }
6140 return result;
6141}
6142#endif
6143
balrog6a24a772008-09-20 02:23:36 +00006144static inline abi_long host_to_target_stat64(void *cpu_env,
6145 abi_ulong target_addr,
6146 struct stat *host_st)
6147{
Alexander Graf09701192013-09-03 20:12:15 +01006148#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006149 if (((CPUARMState *)cpu_env)->eabi) {
6150 struct target_eabi_stat64 *target_st;
6151
6152 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6153 return -TARGET_EFAULT;
6154 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6155 __put_user(host_st->st_dev, &target_st->st_dev);
6156 __put_user(host_st->st_ino, &target_st->st_ino);
6157#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6158 __put_user(host_st->st_ino, &target_st->__st_ino);
6159#endif
6160 __put_user(host_st->st_mode, &target_st->st_mode);
6161 __put_user(host_st->st_nlink, &target_st->st_nlink);
6162 __put_user(host_st->st_uid, &target_st->st_uid);
6163 __put_user(host_st->st_gid, &target_st->st_gid);
6164 __put_user(host_st->st_rdev, &target_st->st_rdev);
6165 __put_user(host_st->st_size, &target_st->st_size);
6166 __put_user(host_st->st_blksize, &target_st->st_blksize);
6167 __put_user(host_st->st_blocks, &target_st->st_blocks);
6168 __put_user(host_st->st_atime, &target_st->target_st_atime);
6169 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6170 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6171 unlock_user_struct(target_st, target_addr, 1);
6172 } else
6173#endif
6174 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006175#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006176 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006177#else
6178 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006179#endif
balrog6a24a772008-09-20 02:23:36 +00006180
6181 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6182 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006183 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006184 __put_user(host_st->st_dev, &target_st->st_dev);
6185 __put_user(host_st->st_ino, &target_st->st_ino);
6186#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6187 __put_user(host_st->st_ino, &target_st->__st_ino);
6188#endif
6189 __put_user(host_st->st_mode, &target_st->st_mode);
6190 __put_user(host_st->st_nlink, &target_st->st_nlink);
6191 __put_user(host_st->st_uid, &target_st->st_uid);
6192 __put_user(host_st->st_gid, &target_st->st_gid);
6193 __put_user(host_st->st_rdev, &target_st->st_rdev);
6194 /* XXX: better use of kernel struct */
6195 __put_user(host_st->st_size, &target_st->st_size);
6196 __put_user(host_st->st_blksize, &target_st->st_blksize);
6197 __put_user(host_st->st_blocks, &target_st->st_blocks);
6198 __put_user(host_st->st_atime, &target_st->target_st_atime);
6199 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6200 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6201 unlock_user_struct(target_st, target_addr, 1);
6202 }
6203
6204 return 0;
6205}
balrog6a24a772008-09-20 02:23:36 +00006206
pbrookbd0c5662008-05-29 14:34:11 +00006207/* ??? Using host futex calls even when target atomic operations
6208 are not really atomic probably breaks things. However implementing
6209 futexes locally would make futexes shared between multiple processes
6210 tricky. However they're probably useless because guest atomic
6211 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006212static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6213 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006214{
6215 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006216 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006217
6218 /* ??? We assume FUTEX_* constants are the same on both host
6219 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006220#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006221 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006222#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006223 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006224#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006225 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006226 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006227 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006228 if (timeout) {
6229 pts = &ts;
6230 target_to_host_timespec(pts, timeout);
6231 } else {
6232 pts = NULL;
6233 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006234 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006235 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006236 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006237 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006238 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006239 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006240 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006241 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006242 case FUTEX_WAKE_OP:
6243 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6244 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6245 But the prototype takes a `struct timespec *'; insert casts
6246 to satisfy the compiler. We do not need to tswap TIMEOUT
6247 since it's not compared to guest memory. */
6248 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006249 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6250 g2h(uaddr2),
6251 (base_op == FUTEX_CMP_REQUEUE
6252 ? tswap32(val3)
6253 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006254 default:
6255 return -TARGET_ENOSYS;
6256 }
6257}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006258#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6259static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6260 abi_long handle, abi_long mount_id,
6261 abi_long flags)
6262{
6263 struct file_handle *target_fh;
6264 struct file_handle *fh;
6265 int mid = 0;
6266 abi_long ret;
6267 char *name;
6268 unsigned int size, total_size;
6269
6270 if (get_user_s32(size, handle)) {
6271 return -TARGET_EFAULT;
6272 }
6273
6274 name = lock_user_string(pathname);
6275 if (!name) {
6276 return -TARGET_EFAULT;
6277 }
6278
6279 total_size = sizeof(struct file_handle) + size;
6280 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6281 if (!target_fh) {
6282 unlock_user(name, pathname, 0);
6283 return -TARGET_EFAULT;
6284 }
6285
6286 fh = g_malloc0(total_size);
6287 fh->handle_bytes = size;
6288
6289 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6290 unlock_user(name, pathname, 0);
6291
6292 /* man name_to_handle_at(2):
6293 * Other than the use of the handle_bytes field, the caller should treat
6294 * the file_handle structure as an opaque data type
6295 */
6296
6297 memcpy(target_fh, fh, total_size);
6298 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6299 target_fh->handle_type = tswap32(fh->handle_type);
6300 g_free(fh);
6301 unlock_user(target_fh, handle, total_size);
6302
6303 if (put_user_s32(mid, mount_id)) {
6304 return -TARGET_EFAULT;
6305 }
6306
6307 return ret;
6308
6309}
6310#endif
6311
6312#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6313static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6314 abi_long flags)
6315{
6316 struct file_handle *target_fh;
6317 struct file_handle *fh;
6318 unsigned int size, total_size;
6319 abi_long ret;
6320
6321 if (get_user_s32(size, handle)) {
6322 return -TARGET_EFAULT;
6323 }
6324
6325 total_size = sizeof(struct file_handle) + size;
6326 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6327 if (!target_fh) {
6328 return -TARGET_EFAULT;
6329 }
6330
Thomas Huthe9d49d52015-10-09 17:56:38 +02006331 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006332 fh->handle_bytes = size;
6333 fh->handle_type = tswap32(target_fh->handle_type);
6334
6335 ret = get_errno(open_by_handle_at(mount_fd, fh,
6336 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6337
6338 g_free(fh);
6339
6340 unlock_user(target_fh, handle, total_size);
6341
6342 return ret;
6343}
6344#endif
pbrookbd0c5662008-05-29 14:34:11 +00006345
Laurent Viviere36800c2015-10-02 14:48:09 +02006346#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6347
6348/* signalfd siginfo conversion */
6349
6350static void
6351host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6352 const struct signalfd_siginfo *info)
6353{
6354 int sig = host_to_target_signal(info->ssi_signo);
6355
6356 /* linux/signalfd.h defines a ssi_addr_lsb
6357 * not defined in sys/signalfd.h but used by some kernels
6358 */
6359
6360#ifdef BUS_MCEERR_AO
6361 if (tinfo->ssi_signo == SIGBUS &&
6362 (tinfo->ssi_code == BUS_MCEERR_AR ||
6363 tinfo->ssi_code == BUS_MCEERR_AO)) {
6364 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6365 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6366 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6367 }
6368#endif
6369
6370 tinfo->ssi_signo = tswap32(sig);
6371 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6372 tinfo->ssi_code = tswap32(info->ssi_code);
6373 tinfo->ssi_pid = tswap32(info->ssi_pid);
6374 tinfo->ssi_uid = tswap32(info->ssi_uid);
6375 tinfo->ssi_fd = tswap32(info->ssi_fd);
6376 tinfo->ssi_tid = tswap32(info->ssi_tid);
6377 tinfo->ssi_band = tswap32(info->ssi_band);
6378 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6379 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6380 tinfo->ssi_status = tswap32(info->ssi_status);
6381 tinfo->ssi_int = tswap32(info->ssi_int);
6382 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6383 tinfo->ssi_utime = tswap64(info->ssi_utime);
6384 tinfo->ssi_stime = tswap64(info->ssi_stime);
6385 tinfo->ssi_addr = tswap64(info->ssi_addr);
6386}
6387
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006388static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006389{
6390 int i;
6391
6392 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6393 host_to_target_signalfd_siginfo(buf + i, buf + i);
6394 }
6395
6396 return len;
6397}
6398
6399static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006400 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006401};
6402
6403static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6404{
6405 int host_flags;
6406 target_sigset_t *target_mask;
6407 sigset_t host_mask;
6408 abi_long ret;
6409
6410 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6411 return -TARGET_EINVAL;
6412 }
6413 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6414 return -TARGET_EFAULT;
6415 }
6416
6417 target_to_host_sigset(&host_mask, target_mask);
6418
6419 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6420
6421 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6422 if (ret >= 0) {
6423 fd_trans_register(ret, &target_signalfd_trans);
6424 }
6425
6426 unlock_user_struct(target_mask, mask, 0);
6427
6428 return ret;
6429}
6430#endif
6431
pbrook1d9d8b52009-04-16 15:17:02 +00006432/* Map host to target signal numbers for the wait family of syscalls.
6433 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006434int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006435{
6436 if (WIFSIGNALED(status)) {
6437 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6438 }
6439 if (WIFSTOPPED(status)) {
6440 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6441 | (status & 0xff);
6442 }
6443 return status;
6444}
6445
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006446static int open_self_cmdline(void *cpu_env, int fd)
6447{
6448 int fd_orig = -1;
6449 bool word_skipped = false;
6450
6451 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6452 if (fd_orig < 0) {
6453 return fd_orig;
6454 }
6455
6456 while (true) {
6457 ssize_t nb_read;
6458 char buf[128];
6459 char *cp_buf = buf;
6460
6461 nb_read = read(fd_orig, buf, sizeof(buf));
6462 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006463 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006464 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006465 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006466 return -1;
6467 } else if (nb_read == 0) {
6468 break;
6469 }
6470
6471 if (!word_skipped) {
6472 /* Skip the first string, which is the path to qemu-*-static
6473 instead of the actual command. */
6474 cp_buf = memchr(buf, 0, sizeof(buf));
6475 if (cp_buf) {
6476 /* Null byte found, skip one string */
6477 cp_buf++;
6478 nb_read -= cp_buf - buf;
6479 word_skipped = true;
6480 }
6481 }
6482
6483 if (word_skipped) {
6484 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006485 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006486 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006487 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006488 return -1;
6489 }
6490 }
6491 }
6492
6493 return close(fd_orig);
6494}
6495
Alexander Graf36c08d42011-11-02 20:23:24 +01006496static int open_self_maps(void *cpu_env, int fd)
6497{
Andreas Färber0429a972013-08-26 18:14:44 +02006498 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6499 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006500 FILE *fp;
6501 char *line = NULL;
6502 size_t len = 0;
6503 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006504
Alexander Graf1a49ef22012-05-01 16:30:28 +01006505 fp = fopen("/proc/self/maps", "r");
6506 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006507 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006508 }
6509
6510 while ((read = getline(&line, &len, fp)) != -1) {
6511 int fields, dev_maj, dev_min, inode;
6512 uint64_t min, max, offset;
6513 char flag_r, flag_w, flag_x, flag_p;
6514 char path[512] = "";
6515 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6516 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6517 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6518
6519 if ((fields < 10) || (fields > 11)) {
6520 continue;
6521 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006522 if (h2g_valid(min)) {
6523 int flags = page_get_flags(h2g(min));
6524 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6525 if (page_check_range(h2g(min), max - min, flags) == -1) {
6526 continue;
6527 }
6528 if (h2g(min) == ts->info->stack_limit) {
6529 pstrcpy(path, sizeof(path), " [stack]");
6530 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006531 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006532 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006533 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006534 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006535 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006536 }
6537 }
6538
6539 free(line);
6540 fclose(fp);
6541
Alexander Graf36c08d42011-11-02 20:23:24 +01006542 return 0;
6543}
6544
Alexander Graf480b8e72011-11-02 20:23:25 +01006545static int open_self_stat(void *cpu_env, int fd)
6546{
Andreas Färber0429a972013-08-26 18:14:44 +02006547 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6548 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006549 abi_ulong start_stack = ts->info->start_stack;
6550 int i;
6551
6552 for (i = 0; i < 44; i++) {
6553 char buf[128];
6554 int len;
6555 uint64_t val = 0;
6556
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006557 if (i == 0) {
6558 /* pid */
6559 val = getpid();
6560 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6561 } else if (i == 1) {
6562 /* app name */
6563 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6564 } else if (i == 27) {
6565 /* stack bottom */
6566 val = start_stack;
6567 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6568 } else {
6569 /* for the rest, there is MasterCard */
6570 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006571 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006572
Alexander Graf480b8e72011-11-02 20:23:25 +01006573 len = strlen(buf);
6574 if (write(fd, buf, len) != len) {
6575 return -1;
6576 }
6577 }
6578
6579 return 0;
6580}
6581
Alexander Graf257450e2011-11-02 20:23:26 +01006582static int open_self_auxv(void *cpu_env, int fd)
6583{
Andreas Färber0429a972013-08-26 18:14:44 +02006584 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6585 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006586 abi_ulong auxv = ts->info->saved_auxv;
6587 abi_ulong len = ts->info->auxv_len;
6588 char *ptr;
6589
6590 /*
6591 * Auxiliary vector is stored in target process stack.
6592 * read in whole auxv vector and copy it to file
6593 */
6594 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6595 if (ptr != NULL) {
6596 while (len > 0) {
6597 ssize_t r;
6598 r = write(fd, ptr, len);
6599 if (r <= 0) {
6600 break;
6601 }
6602 len -= r;
6603 ptr += r;
6604 }
6605 lseek(fd, 0, SEEK_SET);
6606 unlock_user(ptr, auxv, len);
6607 }
6608
6609 return 0;
6610}
6611
Andreas Schwab463d8e72013-07-02 14:04:12 +01006612static int is_proc_myself(const char *filename, const char *entry)
6613{
6614 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6615 filename += strlen("/proc/");
6616 if (!strncmp(filename, "self/", strlen("self/"))) {
6617 filename += strlen("self/");
6618 } else if (*filename >= '1' && *filename <= '9') {
6619 char myself[80];
6620 snprintf(myself, sizeof(myself), "%d/", getpid());
6621 if (!strncmp(filename, myself, strlen(myself))) {
6622 filename += strlen(myself);
6623 } else {
6624 return 0;
6625 }
6626 } else {
6627 return 0;
6628 }
6629 if (!strcmp(filename, entry)) {
6630 return 1;
6631 }
6632 }
6633 return 0;
6634}
6635
Laurent Vivierde6b9932013-08-30 01:46:40 +02006636#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6637static int is_proc(const char *filename, const char *entry)
6638{
6639 return strcmp(filename, entry) == 0;
6640}
6641
6642static int open_net_route(void *cpu_env, int fd)
6643{
6644 FILE *fp;
6645 char *line = NULL;
6646 size_t len = 0;
6647 ssize_t read;
6648
6649 fp = fopen("/proc/net/route", "r");
6650 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006651 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006652 }
6653
6654 /* read header */
6655
6656 read = getline(&line, &len, fp);
6657 dprintf(fd, "%s", line);
6658
6659 /* read routes */
6660
6661 while ((read = getline(&line, &len, fp)) != -1) {
6662 char iface[16];
6663 uint32_t dest, gw, mask;
6664 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6665 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6666 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6667 &mask, &mtu, &window, &irtt);
6668 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6669 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6670 metric, tswap32(mask), mtu, window, irtt);
6671 }
6672
6673 free(line);
6674 fclose(fp);
6675
6676 return 0;
6677}
6678#endif
6679
Riku Voipio0b2effd2014-08-06 10:36:37 +03006680static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006681{
6682 struct fake_open {
6683 const char *filename;
6684 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006685 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006686 };
6687 const struct fake_open *fake_open;
6688 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006689 { "maps", open_self_maps, is_proc_myself },
6690 { "stat", open_self_stat, is_proc_myself },
6691 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006692 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006693#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6694 { "/proc/net/route", open_net_route, is_proc },
6695#endif
6696 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006697 };
6698
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006699 if (is_proc_myself(pathname, "exe")) {
6700 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006701 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006702 }
6703
Alexander Graf3be14d02011-11-02 20:23:23 +01006704 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006705 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006706 break;
6707 }
6708 }
6709
6710 if (fake_open->filename) {
6711 const char *tmpdir;
6712 char filename[PATH_MAX];
6713 int fd, r;
6714
6715 /* create temporary file to map stat to */
6716 tmpdir = getenv("TMPDIR");
6717 if (!tmpdir)
6718 tmpdir = "/tmp";
6719 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6720 fd = mkstemp(filename);
6721 if (fd < 0) {
6722 return fd;
6723 }
6724 unlink(filename);
6725
6726 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006727 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006728 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006729 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006730 return r;
6731 }
6732 lseek(fd, 0, SEEK_SET);
6733
6734 return fd;
6735 }
6736
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006737 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006738}
6739
Alexander Grafaecc8862014-11-10 21:33:03 +01006740#define TIMER_MAGIC 0x0caf0000
6741#define TIMER_MAGIC_MASK 0xffff0000
6742
6743/* Convert QEMU provided timer ID back to internal 16bit index format */
6744static target_timer_t get_timer_id(abi_long arg)
6745{
6746 target_timer_t timerid = arg;
6747
6748 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6749 return -TARGET_EINVAL;
6750 }
6751
6752 timerid &= 0xffff;
6753
6754 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6755 return -TARGET_EINVAL;
6756 }
6757
6758 return timerid;
6759}
6760
ths0da46a62007-10-20 20:23:07 +00006761/* do_syscall() should always have a single exit point at the end so
6762 that actions, such as logging of syscall results, can be performed.
6763 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006764abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6765 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006766 abi_long arg5, abi_long arg6, abi_long arg7,
6767 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006768{
Andreas Färber182735e2013-05-29 22:29:20 +02006769 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006770 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006771 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006772 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006773 void *p;
ths3b46e622007-09-17 08:09:54 +00006774
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006775#if defined(DEBUG_ERESTARTSYS)
6776 /* Debug-only code for exercising the syscall-restart code paths
6777 * in the per-architecture cpu main loops: restart every syscall
6778 * the guest makes once before letting it through.
6779 */
6780 {
6781 static int flag;
6782
6783 flag = !flag;
6784 if (flag) {
6785 return -TARGET_ERESTARTSYS;
6786 }
6787 }
6788#endif
6789
bellard72f03902003-02-18 23:33:18 +00006790#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006791 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006792#endif
thsb92c47c2007-11-01 00:07:38 +00006793 if(do_strace)
6794 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6795
bellard31e31b82003-02-18 22:55:36 +00006796 switch(num) {
6797 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006798 /* In old applications this may be used to implement _exit(2).
6799 However in threaded applictions it is used for thread termination,
6800 and _exit_group is used for application termination.
6801 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01006802
6803 if (block_signals()) {
6804 ret = -TARGET_ERESTARTSYS;
6805 break;
6806 }
6807
Andreas Färberbdc44642013-06-24 23:50:24 +02006808 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006809 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006810
Andreas Färber9b056fc2013-06-24 23:53:10 +02006811 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006812 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006813 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006814 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006815 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006816 if (ts->child_tidptr) {
6817 put_user_u32(0, ts->child_tidptr);
6818 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6819 NULL, NULL, 0);
6820 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006821 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006822 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006823 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006824 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006825 pthread_exit(NULL);
6826 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006827#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006828 _mcleanup();
6829#endif
bellarde9009672005-04-26 20:42:36 +00006830 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006831 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006832 ret = 0; /* avoid warning */
6833 break;
6834 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006835 if (arg3 == 0)
6836 ret = 0;
6837 else {
6838 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6839 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006840 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006841 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006842 fd_trans_host_to_target_data(arg1)) {
6843 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006844 }
aurel3238d840e2009-01-30 19:48:17 +00006845 unlock_user(p, arg2, ret);
6846 }
bellard31e31b82003-02-18 22:55:36 +00006847 break;
6848 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006849 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6850 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006851 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006852 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006853 break;
Chen Gang704eff62015-08-21 05:37:33 +08006854#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006855 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006856 if (!(p = lock_user_string(arg1)))
6857 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006858 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6859 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6860 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006861 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006862 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006863 break;
Chen Gang704eff62015-08-21 05:37:33 +08006864#endif
ths82424832007-09-24 09:21:55 +00006865 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006866 if (!(p = lock_user_string(arg2)))
6867 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006868 ret = get_errno(do_openat(cpu_env, arg1, p,
6869 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6870 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006871 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006872 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006873 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006874#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6875 case TARGET_NR_name_to_handle_at:
6876 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6877 break;
6878#endif
6879#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6880 case TARGET_NR_open_by_handle_at:
6881 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006882 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006883 break;
6884#endif
bellard31e31b82003-02-18 22:55:36 +00006885 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006886 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006887 ret = get_errno(close(arg1));
6888 break;
6889 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006890 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006891 break;
Chen Gang704eff62015-08-21 05:37:33 +08006892#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006893 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006894 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006895 break;
Chen Gang704eff62015-08-21 05:37:33 +08006896#endif
thse5febef2007-04-01 18:31:35 +00006897#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006898 case TARGET_NR_waitpid:
6899 {
pbrook53a59602006-03-25 19:31:22 +00006900 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006901 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006902 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006903 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006904 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006905 }
6906 break;
thse5febef2007-04-01 18:31:35 +00006907#endif
pbrookf0cbb612008-05-30 18:20:05 +00006908#ifdef TARGET_NR_waitid
6909 case TARGET_NR_waitid:
6910 {
6911 siginfo_t info;
6912 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006913 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006914 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006915 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006916 goto efault;
6917 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006918 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006919 }
6920 }
6921 break;
6922#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006923#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006924 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006925 if (!(p = lock_user_string(arg1)))
6926 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006927 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006928 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006929 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006930 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006931#endif
Chen Gang704eff62015-08-21 05:37:33 +08006932#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006933 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006934 {
6935 void * p2;
6936 p = lock_user_string(arg1);
6937 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006938 if (!p || !p2)
6939 ret = -TARGET_EFAULT;
6940 else
6941 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006942 unlock_user(p2, arg2, 0);
6943 unlock_user(p, arg1, 0);
6944 }
bellard31e31b82003-02-18 22:55:36 +00006945 break;
Chen Gang704eff62015-08-21 05:37:33 +08006946#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006947#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006948 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006949 {
6950 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006951 if (!arg2 || !arg4)
6952 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006953 p = lock_user_string(arg2);
6954 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006955 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006956 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006957 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006958 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006959 unlock_user(p, arg2, 0);
6960 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006961 }
6962 break;
6963#endif
Chen Gang704eff62015-08-21 05:37:33 +08006964#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006965 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006966 if (!(p = lock_user_string(arg1)))
6967 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006968 ret = get_errno(unlink(p));
6969 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006970 break;
Chen Gang704eff62015-08-21 05:37:33 +08006971#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006972#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006973 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006974 if (!(p = lock_user_string(arg2)))
6975 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006976 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006977 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006978 break;
balrogb7d35e62007-12-12 00:40:24 +00006979#endif
bellard31e31b82003-02-18 22:55:36 +00006980 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006981 {
6982 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006983 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006984 abi_ulong gp;
6985 abi_ulong guest_argp;
6986 abi_ulong guest_envp;
6987 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006988 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006989 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006990
bellardf7341ff2003-03-30 21:00:25 +00006991 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006992 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006993 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006994 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006995 goto efault;
ths03aa1972007-12-02 06:28:08 +00006996 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006997 break;
bellard7854b052003-03-29 17:22:23 +00006998 argc++;
bellard2f619692007-11-16 10:46:05 +00006999 }
bellardf7341ff2003-03-30 21:00:25 +00007000 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007001 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007002 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007003 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007004 goto efault;
ths03aa1972007-12-02 06:28:08 +00007005 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007006 break;
bellard7854b052003-03-29 17:22:23 +00007007 envc++;
bellard2f619692007-11-16 10:46:05 +00007008 }
bellard7854b052003-03-29 17:22:23 +00007009
bellardf7341ff2003-03-30 21:00:25 +00007010 argp = alloca((argc + 1) * sizeof(void *));
7011 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007012
pbrookda94d262008-05-30 18:24:00 +00007013 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007014 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007015 if (get_user_ual(addr, gp))
7016 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007017 if (!addr)
7018 break;
bellard2f619692007-11-16 10:46:05 +00007019 if (!(*q = lock_user_string(addr)))
7020 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007021 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007022 }
bellardf7341ff2003-03-30 21:00:25 +00007023 *q = NULL;
7024
pbrookda94d262008-05-30 18:24:00 +00007025 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007026 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007027 if (get_user_ual(addr, gp))
7028 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007029 if (!addr)
7030 break;
bellard2f619692007-11-16 10:46:05 +00007031 if (!(*q = lock_user_string(addr)))
7032 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007033 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007034 }
bellardf7341ff2003-03-30 21:00:25 +00007035 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007036
bellard2f619692007-11-16 10:46:05 +00007037 if (!(p = lock_user_string(arg1)))
7038 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007039 /* Although execve() is not an interruptible syscall it is
7040 * a special case where we must use the safe_syscall wrapper:
7041 * if we allow a signal to happen before we make the host
7042 * syscall then we will 'lose' it, because at the point of
7043 * execve the process leaves QEMU's control. So we use the
7044 * safe syscall wrapper to ensure that we either take the
7045 * signal as a guest signal, or else it does not happen
7046 * before the execve completes and makes it the other
7047 * program's problem.
7048 */
7049 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007050 unlock_user(p, arg1, 0);
7051
bellard2f619692007-11-16 10:46:05 +00007052 goto execve_end;
7053
7054 execve_efault:
7055 ret = -TARGET_EFAULT;
7056
7057 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007058 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007059 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007060 if (get_user_ual(addr, gp)
7061 || !addr)
7062 break;
pbrook53a59602006-03-25 19:31:22 +00007063 unlock_user(*q, addr, 0);
7064 }
7065 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007066 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007067 if (get_user_ual(addr, gp)
7068 || !addr)
7069 break;
pbrook53a59602006-03-25 19:31:22 +00007070 unlock_user(*q, addr, 0);
7071 }
bellard7854b052003-03-29 17:22:23 +00007072 }
bellard31e31b82003-02-18 22:55:36 +00007073 break;
7074 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007075 if (!(p = lock_user_string(arg1)))
7076 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007077 ret = get_errno(chdir(p));
7078 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007079 break;
bellarda315a142005-01-30 22:59:18 +00007080#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007081 case TARGET_NR_time:
7082 {
pbrook53a59602006-03-25 19:31:22 +00007083 time_t host_time;
7084 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007085 if (!is_error(ret)
7086 && arg1
7087 && put_user_sal(host_time, arg1))
7088 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007089 }
7090 break;
bellarda315a142005-01-30 22:59:18 +00007091#endif
Chen Gang704eff62015-08-21 05:37:33 +08007092#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007093 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007094 if (!(p = lock_user_string(arg1)))
7095 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007096 ret = get_errno(mknod(p, arg2, arg3));
7097 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007098 break;
Chen Gang704eff62015-08-21 05:37:33 +08007099#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007100#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007101 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007102 if (!(p = lock_user_string(arg2)))
7103 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007104 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007105 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007106 break;
7107#endif
Chen Gang704eff62015-08-21 05:37:33 +08007108#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007109 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007110 if (!(p = lock_user_string(arg1)))
7111 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007112 ret = get_errno(chmod(p, arg2));
7113 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007114 break;
Chen Gang704eff62015-08-21 05:37:33 +08007115#endif
bellardebc05482003-09-30 21:08:41 +00007116#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007117 case TARGET_NR_break:
7118 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007119#endif
7120#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007121 case TARGET_NR_oldstat:
7122 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007123#endif
bellard31e31b82003-02-18 22:55:36 +00007124 case TARGET_NR_lseek:
7125 ret = get_errno(lseek(arg1, arg2, arg3));
7126 break;
Richard Henderson92317332010-05-03 10:07:53 -07007127#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7128 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007129 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007130 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007131 ret = get_errno(getpid());
7132 break;
Richard Henderson92317332010-05-03 10:07:53 -07007133#endif
7134#ifdef TARGET_NR_getpid
7135 case TARGET_NR_getpid:
7136 ret = get_errno(getpid());
7137 break;
7138#endif
bellard31e31b82003-02-18 22:55:36 +00007139 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007140 {
7141 /* need to look at the data field */
7142 void *p2, *p3;
7143
7144 if (arg1) {
7145 p = lock_user_string(arg1);
7146 if (!p) {
7147 goto efault;
7148 }
7149 } else {
7150 p = NULL;
7151 }
7152
7153 p2 = lock_user_string(arg2);
7154 if (!p2) {
7155 if (arg1) {
7156 unlock_user(p, arg1, 0);
7157 }
7158 goto efault;
7159 }
7160
7161 if (arg3) {
7162 p3 = lock_user_string(arg3);
7163 if (!p3) {
7164 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007165 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007166 }
7167 unlock_user(p2, arg2, 0);
7168 goto efault;
7169 }
7170 } else {
7171 p3 = NULL;
7172 }
7173
7174 /* FIXME - arg5 should be locked, but it isn't clear how to
7175 * do that since it's not guaranteed to be a NULL-terminated
7176 * string.
7177 */
7178 if (!arg5) {
7179 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7180 } else {
7181 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7182 }
7183 ret = get_errno(ret);
7184
7185 if (arg1) {
7186 unlock_user(p, arg1, 0);
7187 }
7188 unlock_user(p2, arg2, 0);
7189 if (arg3) {
7190 unlock_user(p3, arg3, 0);
7191 }
7192 }
7193 break;
thse5febef2007-04-01 18:31:35 +00007194#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007195 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007196 if (!(p = lock_user_string(arg1)))
7197 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007198 ret = get_errno(umount(p));
7199 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007200 break;
thse5febef2007-04-01 18:31:35 +00007201#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007202#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007203 case TARGET_NR_stime:
7204 {
pbrook53a59602006-03-25 19:31:22 +00007205 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007206 if (get_user_sal(host_time, arg1))
7207 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007208 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007209 }
7210 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007211#endif
bellard31e31b82003-02-18 22:55:36 +00007212 case TARGET_NR_ptrace:
7213 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007214#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007215 case TARGET_NR_alarm:
7216 ret = alarm(arg1);
7217 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007218#endif
bellardebc05482003-09-30 21:08:41 +00007219#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007220 case TARGET_NR_oldfstat:
7221 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007222#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007223#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007224 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007225 if (!block_signals()) {
7226 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7227 }
7228 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007229 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007230#endif
thse5febef2007-04-01 18:31:35 +00007231#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007232 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007233 {
pbrook53a59602006-03-25 19:31:22 +00007234 struct utimbuf tbuf, *host_tbuf;
7235 struct target_utimbuf *target_tbuf;
7236 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007237 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7238 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007239 tbuf.actime = tswapal(target_tbuf->actime);
7240 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007241 unlock_user_struct(target_tbuf, arg2, 0);
7242 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007243 } else {
pbrook53a59602006-03-25 19:31:22 +00007244 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007245 }
bellard579a97f2007-11-11 14:26:47 +00007246 if (!(p = lock_user_string(arg1)))
7247 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007248 ret = get_errno(utime(p, host_tbuf));
7249 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007250 }
7251 break;
thse5febef2007-04-01 18:31:35 +00007252#endif
Chen Gang704eff62015-08-21 05:37:33 +08007253#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007254 case TARGET_NR_utimes:
7255 {
bellard978a66f2004-12-06 22:58:05 +00007256 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007257 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007258 if (copy_from_user_timeval(&tv[0], arg2)
7259 || copy_from_user_timeval(&tv[1],
7260 arg2 + sizeof(struct target_timeval)))
7261 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007262 tvp = tv;
7263 } else {
7264 tvp = NULL;
7265 }
bellard579a97f2007-11-11 14:26:47 +00007266 if (!(p = lock_user_string(arg1)))
7267 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007268 ret = get_errno(utimes(p, tvp));
7269 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007270 }
7271 break;
Chen Gang704eff62015-08-21 05:37:33 +08007272#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007273#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007274 case TARGET_NR_futimesat:
7275 {
7276 struct timeval *tvp, tv[2];
7277 if (arg3) {
7278 if (copy_from_user_timeval(&tv[0], arg3)
7279 || copy_from_user_timeval(&tv[1],
7280 arg3 + sizeof(struct target_timeval)))
7281 goto efault;
7282 tvp = tv;
7283 } else {
7284 tvp = NULL;
7285 }
7286 if (!(p = lock_user_string(arg2)))
7287 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007288 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007289 unlock_user(p, arg2, 0);
7290 }
7291 break;
7292#endif
bellardebc05482003-09-30 21:08:41 +00007293#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007294 case TARGET_NR_stty:
7295 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007296#endif
7297#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007298 case TARGET_NR_gtty:
7299 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007300#endif
Chen Gang704eff62015-08-21 05:37:33 +08007301#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007303 if (!(p = lock_user_string(arg1)))
7304 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007305 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007306 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007307 break;
Chen Gang704eff62015-08-21 05:37:33 +08007308#endif
ths92a34c12007-09-24 09:27:49 +00007309#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7310 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007311 if (!(p = lock_user_string(arg2)))
7312 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007313 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007314 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007315 break;
7316#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007317#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007318 case TARGET_NR_nice:
7319 ret = get_errno(nice(arg1));
7320 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007321#endif
bellardebc05482003-09-30 21:08:41 +00007322#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007323 case TARGET_NR_ftime:
7324 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007325#endif
bellard31e31b82003-02-18 22:55:36 +00007326 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007327 sync();
7328 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007329 break;
7330 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007331 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007332 break;
Chen Gang704eff62015-08-21 05:37:33 +08007333#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007334 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007335 {
7336 void *p2;
7337 p = lock_user_string(arg1);
7338 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007339 if (!p || !p2)
7340 ret = -TARGET_EFAULT;
7341 else
7342 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007343 unlock_user(p2, arg2, 0);
7344 unlock_user(p, arg1, 0);
7345 }
bellard31e31b82003-02-18 22:55:36 +00007346 break;
Chen Gang704eff62015-08-21 05:37:33 +08007347#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007348#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007349 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007350 {
bellard579a97f2007-11-11 14:26:47 +00007351 void *p2;
ths722183f2007-09-24 09:24:37 +00007352 p = lock_user_string(arg2);
7353 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007354 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007355 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007356 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007357 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007358 unlock_user(p2, arg4, 0);
7359 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007360 }
7361 break;
7362#endif
Chen Gang704eff62015-08-21 05:37:33 +08007363#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007364 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007365 if (!(p = lock_user_string(arg1)))
7366 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007367 ret = get_errno(mkdir(p, arg2));
7368 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007369 break;
Chen Gang704eff62015-08-21 05:37:33 +08007370#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007371#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007372 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007373 if (!(p = lock_user_string(arg2)))
7374 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007375 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007376 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007377 break;
7378#endif
Chen Gang704eff62015-08-21 05:37:33 +08007379#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007380 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007381 if (!(p = lock_user_string(arg1)))
7382 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007383 ret = get_errno(rmdir(p));
7384 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007385 break;
Chen Gang704eff62015-08-21 05:37:33 +08007386#endif
bellard31e31b82003-02-18 22:55:36 +00007387 case TARGET_NR_dup:
7388 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007389 if (ret >= 0) {
7390 fd_trans_dup(arg1, ret);
7391 }
bellard31e31b82003-02-18 22:55:36 +00007392 break;
Chen Gang704eff62015-08-21 05:37:33 +08007393#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007394 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007395 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007396 break;
Chen Gang704eff62015-08-21 05:37:33 +08007397#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007398#ifdef TARGET_NR_pipe2
7399 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007400 ret = do_pipe(cpu_env, arg1,
7401 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007402 break;
7403#endif
bellard31e31b82003-02-18 22:55:36 +00007404 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007405 {
pbrook53a59602006-03-25 19:31:22 +00007406 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007407 struct tms tms;
7408 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007409 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007410 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7411 if (!tmsp)
7412 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007413 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7414 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7415 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7416 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007417 }
bellardc596ed12003-07-13 17:32:31 +00007418 if (!is_error(ret))
7419 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007420 }
7421 break;
bellardebc05482003-09-30 21:08:41 +00007422#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007423 case TARGET_NR_prof:
7424 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007425#endif
thse5febef2007-04-01 18:31:35 +00007426#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007427 case TARGET_NR_signal:
7428 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007429#endif
bellard31e31b82003-02-18 22:55:36 +00007430 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007431 if (arg1 == 0) {
7432 ret = get_errno(acct(NULL));
7433 } else {
7434 if (!(p = lock_user_string(arg1)))
7435 goto efault;
7436 ret = get_errno(acct(path(p)));
7437 unlock_user(p, arg1, 0);
7438 }
pbrook24836682006-04-16 14:14:53 +00007439 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007440#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007441 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007442 if (!(p = lock_user_string(arg1)))
7443 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007444 ret = get_errno(umount2(p, arg2));
7445 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007446 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007447#endif
bellardebc05482003-09-30 21:08:41 +00007448#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007449 case TARGET_NR_lock:
7450 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007451#endif
bellard31e31b82003-02-18 22:55:36 +00007452 case TARGET_NR_ioctl:
7453 ret = do_ioctl(arg1, arg2, arg3);
7454 break;
7455 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007456 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007457 break;
bellardebc05482003-09-30 21:08:41 +00007458#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007459 case TARGET_NR_mpx:
7460 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007461#endif
bellard31e31b82003-02-18 22:55:36 +00007462 case TARGET_NR_setpgid:
7463 ret = get_errno(setpgid(arg1, arg2));
7464 break;
bellardebc05482003-09-30 21:08:41 +00007465#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007466 case TARGET_NR_ulimit:
7467 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007468#endif
7469#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007470 case TARGET_NR_oldolduname:
7471 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007472#endif
bellard31e31b82003-02-18 22:55:36 +00007473 case TARGET_NR_umask:
7474 ret = get_errno(umask(arg1));
7475 break;
7476 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007477 if (!(p = lock_user_string(arg1)))
7478 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007479 ret = get_errno(chroot(p));
7480 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007481 break;
Chen Gang704eff62015-08-21 05:37:33 +08007482#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007483 case TARGET_NR_ustat:
7484 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007485#endif
7486#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007487 case TARGET_NR_dup2:
7488 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007489 if (ret >= 0) {
7490 fd_trans_dup(arg1, arg2);
7491 }
bellard31e31b82003-02-18 22:55:36 +00007492 break;
Chen Gang704eff62015-08-21 05:37:33 +08007493#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007494#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7495 case TARGET_NR_dup3:
7496 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007497 if (ret >= 0) {
7498 fd_trans_dup(arg1, arg2);
7499 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007500 break;
7501#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007502#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007503 case TARGET_NR_getppid:
7504 ret = get_errno(getppid());
7505 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007506#endif
Chen Gang704eff62015-08-21 05:37:33 +08007507#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007508 case TARGET_NR_getpgrp:
7509 ret = get_errno(getpgrp());
7510 break;
Chen Gang704eff62015-08-21 05:37:33 +08007511#endif
bellard31e31b82003-02-18 22:55:36 +00007512 case TARGET_NR_setsid:
7513 ret = get_errno(setsid());
7514 break;
thse5febef2007-04-01 18:31:35 +00007515#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007516 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007517 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007518#if defined(TARGET_ALPHA)
7519 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007520 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007521 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007522 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7523 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007524 act._sa_handler = old_act->_sa_handler;
7525 target_siginitset(&act.sa_mask, old_act->sa_mask);
7526 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007527 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007528 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007529 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007530 }
7531 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007532 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007533 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7534 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007535 old_act->_sa_handler = oact._sa_handler;
7536 old_act->sa_mask = oact.sa_mask.sig[0];
7537 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007538 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007539 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007540#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007541 struct target_sigaction act, oact, *pact, *old_act;
7542
7543 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007544 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7545 goto efault;
bellard106ec872006-06-27 21:08:10 +00007546 act._sa_handler = old_act->_sa_handler;
7547 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7548 act.sa_flags = old_act->sa_flags;
7549 unlock_user_struct(old_act, arg2, 0);
7550 pact = &act;
7551 } else {
7552 pact = NULL;
7553 }
7554
7555 ret = get_errno(do_sigaction(arg1, pact, &oact));
7556
7557 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007558 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7559 goto efault;
bellard106ec872006-06-27 21:08:10 +00007560 old_act->_sa_handler = oact._sa_handler;
7561 old_act->sa_flags = oact.sa_flags;
7562 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7563 old_act->sa_mask.sig[1] = 0;
7564 old_act->sa_mask.sig[2] = 0;
7565 old_act->sa_mask.sig[3] = 0;
7566 unlock_user_struct(old_act, arg3, 1);
7567 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007568#else
7569 struct target_old_sigaction *old_act;
7570 struct target_sigaction act, oact, *pact;
7571 if (arg2) {
7572 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7573 goto efault;
7574 act._sa_handler = old_act->_sa_handler;
7575 target_siginitset(&act.sa_mask, old_act->sa_mask);
7576 act.sa_flags = old_act->sa_flags;
7577 act.sa_restorer = old_act->sa_restorer;
7578 unlock_user_struct(old_act, arg2, 0);
7579 pact = &act;
7580 } else {
7581 pact = NULL;
7582 }
7583 ret = get_errno(do_sigaction(arg1, pact, &oact));
7584 if (!is_error(ret) && arg3) {
7585 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7586 goto efault;
7587 old_act->_sa_handler = oact._sa_handler;
7588 old_act->sa_mask = oact.sa_mask.sig[0];
7589 old_act->sa_flags = oact.sa_flags;
7590 old_act->sa_restorer = oact.sa_restorer;
7591 unlock_user_struct(old_act, arg3, 1);
7592 }
ths388bb212007-05-13 13:58:00 +00007593#endif
bellard31e31b82003-02-18 22:55:36 +00007594 }
7595 break;
thse5febef2007-04-01 18:31:35 +00007596#endif
bellard66fb9762003-03-23 01:06:05 +00007597 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007598 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007599#if defined(TARGET_ALPHA)
7600 struct target_sigaction act, oact, *pact = 0;
7601 struct target_rt_sigaction *rt_act;
7602 /* ??? arg4 == sizeof(sigset_t). */
7603 if (arg2) {
7604 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7605 goto efault;
7606 act._sa_handler = rt_act->_sa_handler;
7607 act.sa_mask = rt_act->sa_mask;
7608 act.sa_flags = rt_act->sa_flags;
7609 act.sa_restorer = arg5;
7610 unlock_user_struct(rt_act, arg2, 0);
7611 pact = &act;
7612 }
7613 ret = get_errno(do_sigaction(arg1, pact, &oact));
7614 if (!is_error(ret) && arg3) {
7615 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7616 goto efault;
7617 rt_act->_sa_handler = oact._sa_handler;
7618 rt_act->sa_mask = oact.sa_mask;
7619 rt_act->sa_flags = oact.sa_flags;
7620 unlock_user_struct(rt_act, arg3, 1);
7621 }
7622#else
pbrook53a59602006-03-25 19:31:22 +00007623 struct target_sigaction *act;
7624 struct target_sigaction *oact;
7625
bellard579a97f2007-11-11 14:26:47 +00007626 if (arg2) {
7627 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7628 goto efault;
7629 } else
pbrook53a59602006-03-25 19:31:22 +00007630 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007631 if (arg3) {
7632 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7633 ret = -TARGET_EFAULT;
7634 goto rt_sigaction_fail;
7635 }
7636 } else
pbrook53a59602006-03-25 19:31:22 +00007637 oact = NULL;
7638 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007639 rt_sigaction_fail:
7640 if (act)
pbrook53a59602006-03-25 19:31:22 +00007641 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007642 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007643 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007644#endif
pbrook53a59602006-03-25 19:31:22 +00007645 }
bellard66fb9762003-03-23 01:06:05 +00007646 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007647#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007648 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007649 {
7650 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007651 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007652 ret = do_sigprocmask(0, NULL, &cur_set);
7653 if (!ret) {
7654 host_to_target_old_sigset(&target_set, &cur_set);
7655 ret = target_set;
7656 }
bellard66fb9762003-03-23 01:06:05 +00007657 }
7658 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007659#endif
7660#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007661 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007662 {
7663 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007664 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007665 /* We only have one word of the new mask so we must read
7666 * the rest of it with do_sigprocmask() and OR in this word.
7667 * We are guaranteed that a do_sigprocmask() that only queries
7668 * the signal mask will not fail.
7669 */
7670 ret = do_sigprocmask(0, NULL, &cur_set);
7671 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00007672 target_to_host_old_sigset(&set, &target_set);
7673 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007674 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7675 if (!ret) {
7676 host_to_target_old_sigset(&target_set, &oset);
7677 ret = target_set;
7678 }
bellard66fb9762003-03-23 01:06:05 +00007679 }
7680 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007681#endif
thse5febef2007-04-01 18:31:35 +00007682#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007683 case TARGET_NR_sigprocmask:
7684 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007685#if defined(TARGET_ALPHA)
7686 sigset_t set, oldset;
7687 abi_ulong mask;
7688 int how;
7689
7690 switch (arg1) {
7691 case TARGET_SIG_BLOCK:
7692 how = SIG_BLOCK;
7693 break;
7694 case TARGET_SIG_UNBLOCK:
7695 how = SIG_UNBLOCK;
7696 break;
7697 case TARGET_SIG_SETMASK:
7698 how = SIG_SETMASK;
7699 break;
7700 default:
7701 ret = -TARGET_EINVAL;
7702 goto fail;
7703 }
7704 mask = arg2;
7705 target_to_host_old_sigset(&set, &mask);
7706
Peter Maydell3d3efba2016-05-27 15:51:49 +01007707 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007708 if (!is_error(ret)) {
7709 host_to_target_old_sigset(&mask, &oldset);
7710 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007711 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007712 }
7713#else
bellard66fb9762003-03-23 01:06:05 +00007714 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007715 int how;
ths3b46e622007-09-17 08:09:54 +00007716
pbrook53a59602006-03-25 19:31:22 +00007717 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007718 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007719 case TARGET_SIG_BLOCK:
7720 how = SIG_BLOCK;
7721 break;
7722 case TARGET_SIG_UNBLOCK:
7723 how = SIG_UNBLOCK;
7724 break;
7725 case TARGET_SIG_SETMASK:
7726 how = SIG_SETMASK;
7727 break;
7728 default:
ths0da46a62007-10-20 20:23:07 +00007729 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007730 goto fail;
7731 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007732 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007733 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007734 target_to_host_old_sigset(&set, p);
7735 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007736 set_ptr = &set;
7737 } else {
7738 how = 0;
7739 set_ptr = NULL;
7740 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007741 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007742 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007743 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007744 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007745 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007746 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007747 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007748#endif
bellard66fb9762003-03-23 01:06:05 +00007749 }
7750 break;
thse5febef2007-04-01 18:31:35 +00007751#endif
bellard66fb9762003-03-23 01:06:05 +00007752 case TARGET_NR_rt_sigprocmask:
7753 {
7754 int how = arg1;
7755 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007756
pbrook53a59602006-03-25 19:31:22 +00007757 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007758 switch(how) {
7759 case TARGET_SIG_BLOCK:
7760 how = SIG_BLOCK;
7761 break;
7762 case TARGET_SIG_UNBLOCK:
7763 how = SIG_UNBLOCK;
7764 break;
7765 case TARGET_SIG_SETMASK:
7766 how = SIG_SETMASK;
7767 break;
7768 default:
ths0da46a62007-10-20 20:23:07 +00007769 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007770 goto fail;
7771 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007772 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007773 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007774 target_to_host_sigset(&set, p);
7775 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007776 set_ptr = &set;
7777 } else {
7778 how = 0;
7779 set_ptr = NULL;
7780 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007781 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007782 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007783 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007784 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007785 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007786 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007787 }
7788 }
7789 break;
thse5febef2007-04-01 18:31:35 +00007790#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007791 case TARGET_NR_sigpending:
7792 {
7793 sigset_t set;
7794 ret = get_errno(sigpending(&set));
7795 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007796 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007797 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007798 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007799 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007800 }
7801 }
7802 break;
thse5febef2007-04-01 18:31:35 +00007803#endif
bellard66fb9762003-03-23 01:06:05 +00007804 case TARGET_NR_rt_sigpending:
7805 {
7806 sigset_t set;
7807 ret = get_errno(sigpending(&set));
7808 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007809 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007810 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007811 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007812 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007813 }
7814 }
7815 break;
thse5febef2007-04-01 18:31:35 +00007816#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007817 case TARGET_NR_sigsuspend:
7818 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007819 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007820#if defined(TARGET_ALPHA)
7821 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007822 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007823#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007824 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007825 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007826 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007827 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007828#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01007829 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7830 SIGSET_T_SIZE));
7831 if (ret != -TARGET_ERESTARTSYS) {
7832 ts->in_sigsuspend = 1;
7833 }
bellard66fb9762003-03-23 01:06:05 +00007834 }
7835 break;
thse5febef2007-04-01 18:31:35 +00007836#endif
bellard66fb9762003-03-23 01:06:05 +00007837 case TARGET_NR_rt_sigsuspend:
7838 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007839 TaskState *ts = cpu->opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05007840 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007841 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007842 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007843 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007844 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7845 SIGSET_T_SIZE));
7846 if (ret != -TARGET_ERESTARTSYS) {
7847 ts->in_sigsuspend = 1;
7848 }
bellard66fb9762003-03-23 01:06:05 +00007849 }
7850 break;
7851 case TARGET_NR_rt_sigtimedwait:
7852 {
bellard66fb9762003-03-23 01:06:05 +00007853 sigset_t set;
7854 struct timespec uts, *puts;
7855 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007856
Anthony Liguoric227f092009-10-01 16:12:16 -05007857 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007858 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007859 target_to_host_sigset(&set, p);
7860 unlock_user(p, arg1, 0);
7861 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007862 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007863 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007864 } else {
7865 puts = NULL;
7866 }
Peter Maydellb3f82332016-06-06 19:58:08 +01007867 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
7868 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007869 if (!is_error(ret)) {
7870 if (arg2) {
7871 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7872 0);
7873 if (!p) {
7874 goto efault;
7875 }
7876 host_to_target_siginfo(p, &uinfo);
7877 unlock_user(p, arg2, sizeof(target_siginfo_t));
7878 }
7879 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007880 }
7881 }
7882 break;
7883 case TARGET_NR_rt_sigqueueinfo:
7884 {
7885 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01007886
7887 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
7888 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00007889 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01007890 }
pbrook53a59602006-03-25 19:31:22 +00007891 target_to_host_siginfo(&uinfo, p);
7892 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007893 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7894 }
7895 break;
thse5febef2007-04-01 18:31:35 +00007896#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007897 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007898 if (block_signals()) {
7899 ret = -TARGET_ERESTARTSYS;
7900 } else {
7901 ret = do_sigreturn(cpu_env);
7902 }
bellard66fb9762003-03-23 01:06:05 +00007903 break;
thse5febef2007-04-01 18:31:35 +00007904#endif
bellard66fb9762003-03-23 01:06:05 +00007905 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007906 if (block_signals()) {
7907 ret = -TARGET_ERESTARTSYS;
7908 } else {
7909 ret = do_rt_sigreturn(cpu_env);
7910 }
bellard66fb9762003-03-23 01:06:05 +00007911 break;
bellard31e31b82003-02-18 22:55:36 +00007912 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007913 if (!(p = lock_user_string(arg1)))
7914 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007915 ret = get_errno(sethostname(p, arg2));
7916 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007917 break;
7918 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007919 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007920 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007921 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007922 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007923 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7924 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007925 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7926 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007927 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007928 ret = get_errno(setrlimit(resource, &rlim));
7929 }
7930 break;
bellard31e31b82003-02-18 22:55:36 +00007931 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007932 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007933 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007934 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007935 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007936
bellard9de5e442003-03-23 16:49:39 +00007937 ret = get_errno(getrlimit(resource, &rlim));
7938 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007939 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7940 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007941 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7942 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007943 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007944 }
7945 }
7946 break;
bellard31e31b82003-02-18 22:55:36 +00007947 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007948 {
7949 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007950 ret = get_errno(getrusage(arg1, &rusage));
7951 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007952 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007953 }
7954 }
7955 break;
bellard31e31b82003-02-18 22:55:36 +00007956 case TARGET_NR_gettimeofday:
7957 {
bellard31e31b82003-02-18 22:55:36 +00007958 struct timeval tv;
7959 ret = get_errno(gettimeofday(&tv, NULL));
7960 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007961 if (copy_to_user_timeval(arg1, &tv))
7962 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007963 }
7964 }
7965 break;
7966 case TARGET_NR_settimeofday:
7967 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007968 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007969 struct timezone tz, *ptz = NULL;
7970
Paul Burtonb67d8032014-06-22 11:25:41 +01007971 if (arg1) {
7972 if (copy_from_user_timeval(&tv, arg1)) {
7973 goto efault;
7974 }
7975 ptv = &tv;
7976 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007977
7978 if (arg2) {
7979 if (copy_from_user_timezone(&tz, arg2)) {
7980 goto efault;
7981 }
7982 ptz = &tz;
7983 }
7984
Paul Burtonb67d8032014-06-22 11:25:41 +01007985 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007986 }
7987 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007988#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007989 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007990#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7991 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7992#else
bellardf2674e32003-07-09 12:26:09 +00007993 {
pbrook53a59602006-03-25 19:31:22 +00007994 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007995 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007996 long nsel;
7997
bellard579a97f2007-11-11 14:26:47 +00007998 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7999 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008000 nsel = tswapal(sel->n);
8001 inp = tswapal(sel->inp);
8002 outp = tswapal(sel->outp);
8003 exp = tswapal(sel->exp);
8004 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00008005 unlock_user_struct(sel, arg1, 0);
8006 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00008007 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008008#endif
bellardf2674e32003-07-09 12:26:09 +00008009 break;
bellard048f6b42005-11-26 18:47:20 +00008010#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008011#ifdef TARGET_NR_pselect6
8012 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008013 {
8014 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8015 fd_set rfds, wfds, efds;
8016 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8017 struct timespec ts, *ts_ptr;
8018
8019 /*
8020 * The 6th arg is actually two args smashed together,
8021 * so we cannot use the C library.
8022 */
8023 sigset_t set;
8024 struct {
8025 sigset_t *set;
8026 size_t size;
8027 } sig, *sig_ptr;
8028
8029 abi_ulong arg_sigset, arg_sigsize, *arg7;
8030 target_sigset_t *target_sigset;
8031
8032 n = arg1;
8033 rfd_addr = arg2;
8034 wfd_addr = arg3;
8035 efd_addr = arg4;
8036 ts_addr = arg5;
8037
8038 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8039 if (ret) {
8040 goto fail;
8041 }
8042 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8043 if (ret) {
8044 goto fail;
8045 }
8046 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8047 if (ret) {
8048 goto fail;
8049 }
8050
8051 /*
8052 * This takes a timespec, and not a timeval, so we cannot
8053 * use the do_select() helper ...
8054 */
8055 if (ts_addr) {
8056 if (target_to_host_timespec(&ts, ts_addr)) {
8057 goto efault;
8058 }
8059 ts_ptr = &ts;
8060 } else {
8061 ts_ptr = NULL;
8062 }
8063
8064 /* Extract the two packed args for the sigset */
8065 if (arg6) {
8066 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008067 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008068
8069 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8070 if (!arg7) {
8071 goto efault;
8072 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008073 arg_sigset = tswapal(arg7[0]);
8074 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008075 unlock_user(arg7, arg6, 0);
8076
8077 if (arg_sigset) {
8078 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008079 if (arg_sigsize != sizeof(*target_sigset)) {
8080 /* Like the kernel, we enforce correct size sigsets */
8081 ret = -TARGET_EINVAL;
8082 goto fail;
8083 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008084 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8085 sizeof(*target_sigset), 1);
8086 if (!target_sigset) {
8087 goto efault;
8088 }
8089 target_to_host_sigset(&set, target_sigset);
8090 unlock_user(target_sigset, arg_sigset, 0);
8091 } else {
8092 sig.set = NULL;
8093 }
8094 } else {
8095 sig_ptr = NULL;
8096 }
8097
Peter Maydell6df9d382016-05-12 18:47:51 +01008098 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8099 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008100
8101 if (!is_error(ret)) {
8102 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8103 goto efault;
8104 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8105 goto efault;
8106 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8107 goto efault;
8108
8109 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8110 goto efault;
8111 }
8112 }
8113 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008114#endif
Chen Gang704eff62015-08-21 05:37:33 +08008115#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008116 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008117 {
8118 void *p2;
8119 p = lock_user_string(arg1);
8120 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008121 if (!p || !p2)
8122 ret = -TARGET_EFAULT;
8123 else
8124 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008125 unlock_user(p2, arg2, 0);
8126 unlock_user(p, arg1, 0);
8127 }
bellard31e31b82003-02-18 22:55:36 +00008128 break;
Chen Gang704eff62015-08-21 05:37:33 +08008129#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008130#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008131 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008132 {
bellard579a97f2007-11-11 14:26:47 +00008133 void *p2;
thsf0b62432007-09-24 09:25:40 +00008134 p = lock_user_string(arg1);
8135 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008136 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008137 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008138 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008139 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008140 unlock_user(p2, arg3, 0);
8141 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008142 }
8143 break;
8144#endif
bellardebc05482003-09-30 21:08:41 +00008145#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008146 case TARGET_NR_oldlstat:
8147 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008148#endif
Chen Gang704eff62015-08-21 05:37:33 +08008149#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008150 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008151 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008152 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008153 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008154 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008155 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008156 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008157 } else if (!arg3) {
8158 /* Short circuit this for the magic exe check. */
8159 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008160 } else if (is_proc_myself((const char *)p, "exe")) {
8161 char real[PATH_MAX], *temp;
8162 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008163 /* Return value is # of bytes that we wrote to the buffer. */
8164 if (temp == NULL) {
8165 ret = get_errno(-1);
8166 } else {
8167 /* Don't worry about sign mismatch as earlier mapping
8168 * logic would have thrown a bad address error. */
8169 ret = MIN(strlen(real), arg3);
8170 /* We cannot NUL terminate the string. */
8171 memcpy(p2, real, ret);
8172 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008173 } else {
8174 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008175 }
pbrook53a59602006-03-25 19:31:22 +00008176 unlock_user(p2, arg2, ret);
8177 unlock_user(p, arg1, 0);
8178 }
bellard31e31b82003-02-18 22:55:36 +00008179 break;
Chen Gang704eff62015-08-21 05:37:33 +08008180#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008181#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008182 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008183 {
bellard579a97f2007-11-11 14:26:47 +00008184 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008185 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008186 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008187 if (!p || !p2) {
8188 ret = -TARGET_EFAULT;
8189 } else if (is_proc_myself((const char *)p, "exe")) {
8190 char real[PATH_MAX], *temp;
8191 temp = realpath(exec_path, real);
8192 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8193 snprintf((char *)p2, arg4, "%s", real);
8194 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008195 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008196 }
bellard579a97f2007-11-11 14:26:47 +00008197 unlock_user(p2, arg3, ret);
8198 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008199 }
8200 break;
8201#endif
thse5febef2007-04-01 18:31:35 +00008202#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008203 case TARGET_NR_uselib:
8204 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008205#endif
8206#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008207 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008208 if (!(p = lock_user_string(arg1)))
8209 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008210 ret = get_errno(swapon(p, arg2));
8211 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008212 break;
thse5febef2007-04-01 18:31:35 +00008213#endif
bellard31e31b82003-02-18 22:55:36 +00008214 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008215 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8216 /* arg4 must be ignored in all other cases */
8217 p = lock_user_string(arg4);
8218 if (!p) {
8219 goto efault;
8220 }
8221 ret = get_errno(reboot(arg1, arg2, arg3, p));
8222 unlock_user(p, arg4, 0);
8223 } else {
8224 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8225 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008226 break;
thse5febef2007-04-01 18:31:35 +00008227#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008228 case TARGET_NR_readdir:
8229 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008230#endif
8231#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008232 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008233#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8234 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008235 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8236 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008237 {
blueswir1992f48a2007-10-14 16:27:31 +00008238 abi_ulong *v;
8239 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008240 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8241 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008242 v1 = tswapal(v[0]);
8243 v2 = tswapal(v[1]);
8244 v3 = tswapal(v[2]);
8245 v4 = tswapal(v[3]);
8246 v5 = tswapal(v[4]);
8247 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008248 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008249 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008250 target_to_host_bitmask(v4, mmap_flags_tbl),
8251 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008252 }
bellard31e31b82003-02-18 22:55:36 +00008253#else
ths5fafdf22007-09-16 21:08:06 +00008254 ret = get_errno(target_mmap(arg1, arg2, arg3,
8255 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008256 arg5,
8257 arg6));
bellard31e31b82003-02-18 22:55:36 +00008258#endif
bellard6fb883e2003-07-09 17:12:39 +00008259 break;
thse5febef2007-04-01 18:31:35 +00008260#endif
bellarda315a142005-01-30 22:59:18 +00008261#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008262 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008263#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008264#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008265#endif
ths5fafdf22007-09-16 21:08:06 +00008266 ret = get_errno(target_mmap(arg1, arg2, arg3,
8267 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008268 arg5,
bellardc573ff62004-01-04 15:51:36 +00008269 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008270 break;
bellarda315a142005-01-30 22:59:18 +00008271#endif
bellard31e31b82003-02-18 22:55:36 +00008272 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008273 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008274 break;
bellard9de5e442003-03-23 16:49:39 +00008275 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008276 {
Andreas Färber0429a972013-08-26 18:14:44 +02008277 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008278 /* Special hack to detect libc making the stack executable. */
8279 if ((arg3 & PROT_GROWSDOWN)
8280 && arg1 >= ts->info->stack_limit
8281 && arg1 <= ts->info->start_stack) {
8282 arg3 &= ~PROT_GROWSDOWN;
8283 arg2 = arg2 + arg1 - ts->info->stack_limit;
8284 arg1 = ts->info->stack_limit;
8285 }
8286 }
bellard54936002003-05-13 00:25:15 +00008287 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008288 break;
thse5febef2007-04-01 18:31:35 +00008289#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008290 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008291 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008292 break;
thse5febef2007-04-01 18:31:35 +00008293#endif
pbrook53a59602006-03-25 19:31:22 +00008294 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008295#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008296 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008297 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008298 break;
thse5febef2007-04-01 18:31:35 +00008299#endif
8300#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008301 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008302 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008303 break;
thse5febef2007-04-01 18:31:35 +00008304#endif
8305#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008306 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008307 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008308 break;
thse5febef2007-04-01 18:31:35 +00008309#endif
8310#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008311 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008312 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008313 break;
thse5febef2007-04-01 18:31:35 +00008314#endif
8315#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008316 case TARGET_NR_munlockall:
8317 ret = get_errno(munlockall());
8318 break;
thse5febef2007-04-01 18:31:35 +00008319#endif
bellard31e31b82003-02-18 22:55:36 +00008320 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008321 if (!(p = lock_user_string(arg1)))
8322 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008323 ret = get_errno(truncate(p, arg2));
8324 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008325 break;
8326 case TARGET_NR_ftruncate:
8327 ret = get_errno(ftruncate(arg1, arg2));
8328 break;
8329 case TARGET_NR_fchmod:
8330 ret = get_errno(fchmod(arg1, arg2));
8331 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008332#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008333 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008334 if (!(p = lock_user_string(arg2)))
8335 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008336 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008337 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008338 break;
8339#endif
bellard31e31b82003-02-18 22:55:36 +00008340 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008341 /* Note that negative values are valid for getpriority, so we must
8342 differentiate based on errno settings. */
8343 errno = 0;
8344 ret = getpriority(arg1, arg2);
8345 if (ret == -1 && errno != 0) {
8346 ret = -host_to_target_errno(errno);
8347 break;
8348 }
8349#ifdef TARGET_ALPHA
8350 /* Return value is the unbiased priority. Signal no error. */
8351 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8352#else
8353 /* Return value is a biased priority to avoid negative numbers. */
8354 ret = 20 - ret;
8355#endif
bellard31e31b82003-02-18 22:55:36 +00008356 break;
8357 case TARGET_NR_setpriority:
8358 ret = get_errno(setpriority(arg1, arg2, arg3));
8359 break;
bellardebc05482003-09-30 21:08:41 +00008360#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008361 case TARGET_NR_profil:
8362 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008363#endif
bellard31e31b82003-02-18 22:55:36 +00008364 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008365 if (!(p = lock_user_string(arg1)))
8366 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008367 ret = get_errno(statfs(path(p), &stfs));
8368 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008369 convert_statfs:
8370 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008371 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008372
bellard579a97f2007-11-11 14:26:47 +00008373 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8374 goto efault;
8375 __put_user(stfs.f_type, &target_stfs->f_type);
8376 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8377 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8378 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8379 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8380 __put_user(stfs.f_files, &target_stfs->f_files);
8381 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8382 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8383 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8384 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008385 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8386 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008387 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008388 }
8389 break;
8390 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008391 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008392 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008393#ifdef TARGET_NR_statfs64
8394 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008395 if (!(p = lock_user_string(arg1)))
8396 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008397 ret = get_errno(statfs(path(p), &stfs));
8398 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008399 convert_statfs64:
8400 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008401 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008402
bellard579a97f2007-11-11 14:26:47 +00008403 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8404 goto efault;
8405 __put_user(stfs.f_type, &target_stfs->f_type);
8406 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8407 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8408 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8409 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8410 __put_user(stfs.f_files, &target_stfs->f_files);
8411 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8412 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8413 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8414 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008415 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8416 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008417 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008418 }
8419 break;
8420 case TARGET_NR_fstatfs64:
8421 ret = get_errno(fstatfs(arg1, &stfs));
8422 goto convert_statfs64;
8423#endif
bellardebc05482003-09-30 21:08:41 +00008424#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008425 case TARGET_NR_ioperm:
8426 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008427#endif
thse5febef2007-04-01 18:31:35 +00008428#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008429 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008430 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008431 break;
thse5febef2007-04-01 18:31:35 +00008432#endif
bellard3532fa72006-06-24 15:06:03 +00008433#ifdef TARGET_NR_accept
8434 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008435 ret = do_accept4(arg1, arg2, arg3, 0);
8436 break;
8437#endif
8438#ifdef TARGET_NR_accept4
8439 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00008440 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008441 break;
8442#endif
8443#ifdef TARGET_NR_bind
8444 case TARGET_NR_bind:
8445 ret = do_bind(arg1, arg2, arg3);
8446 break;
8447#endif
8448#ifdef TARGET_NR_connect
8449 case TARGET_NR_connect:
8450 ret = do_connect(arg1, arg2, arg3);
8451 break;
8452#endif
8453#ifdef TARGET_NR_getpeername
8454 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008455 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008456 break;
8457#endif
8458#ifdef TARGET_NR_getsockname
8459 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008460 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008461 break;
8462#endif
8463#ifdef TARGET_NR_getsockopt
8464 case TARGET_NR_getsockopt:
8465 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8466 break;
8467#endif
8468#ifdef TARGET_NR_listen
8469 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008470 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008471 break;
8472#endif
8473#ifdef TARGET_NR_recv
8474 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008475 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008476 break;
8477#endif
8478#ifdef TARGET_NR_recvfrom
8479 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008480 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008481 break;
8482#endif
8483#ifdef TARGET_NR_recvmsg
8484 case TARGET_NR_recvmsg:
8485 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8486 break;
8487#endif
8488#ifdef TARGET_NR_send
8489 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008490 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008491 break;
8492#endif
8493#ifdef TARGET_NR_sendmsg
8494 case TARGET_NR_sendmsg:
8495 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8496 break;
8497#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008498#ifdef TARGET_NR_sendmmsg
8499 case TARGET_NR_sendmmsg:
8500 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8501 break;
8502 case TARGET_NR_recvmmsg:
8503 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8504 break;
8505#endif
bellard3532fa72006-06-24 15:06:03 +00008506#ifdef TARGET_NR_sendto
8507 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008508 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008509 break;
8510#endif
8511#ifdef TARGET_NR_shutdown
8512 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008513 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008514 break;
8515#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008516#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8517 case TARGET_NR_getrandom:
8518 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8519 if (!p) {
8520 goto efault;
8521 }
8522 ret = get_errno(getrandom(p, arg2, arg3));
8523 unlock_user(p, arg1, ret);
8524 break;
8525#endif
bellard3532fa72006-06-24 15:06:03 +00008526#ifdef TARGET_NR_socket
8527 case TARGET_NR_socket:
8528 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008529 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008530 break;
8531#endif
8532#ifdef TARGET_NR_socketpair
8533 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008534 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008535 break;
8536#endif
8537#ifdef TARGET_NR_setsockopt
8538 case TARGET_NR_setsockopt:
8539 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8540 break;
8541#endif
ths7494b0f2007-02-11 18:26:53 +00008542
bellard31e31b82003-02-18 22:55:36 +00008543 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008544 if (!(p = lock_user_string(arg2)))
8545 goto efault;
thse5574482007-02-11 20:03:13 +00008546 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8547 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008548 break;
8549
bellard31e31b82003-02-18 22:55:36 +00008550 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008551 {
bellard66fb9762003-03-23 01:06:05 +00008552 struct itimerval value, ovalue, *pvalue;
8553
pbrook53a59602006-03-25 19:31:22 +00008554 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008555 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008556 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8557 || copy_from_user_timeval(&pvalue->it_value,
8558 arg2 + sizeof(struct target_timeval)))
8559 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008560 } else {
8561 pvalue = NULL;
8562 }
8563 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008564 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008565 if (copy_to_user_timeval(arg3,
8566 &ovalue.it_interval)
8567 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8568 &ovalue.it_value))
8569 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008570 }
8571 }
8572 break;
bellard31e31b82003-02-18 22:55:36 +00008573 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008574 {
bellard66fb9762003-03-23 01:06:05 +00008575 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008576
bellard66fb9762003-03-23 01:06:05 +00008577 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008578 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008579 if (copy_to_user_timeval(arg2,
8580 &value.it_interval)
8581 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8582 &value.it_value))
8583 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008584 }
8585 }
8586 break;
Chen Gang704eff62015-08-21 05:37:33 +08008587#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008588 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008589 if (!(p = lock_user_string(arg1)))
8590 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008591 ret = get_errno(stat(path(p), &st));
8592 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008593 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008594#endif
8595#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008596 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008597 if (!(p = lock_user_string(arg1)))
8598 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008599 ret = get_errno(lstat(path(p), &st));
8600 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008601 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008602#endif
bellard31e31b82003-02-18 22:55:36 +00008603 case TARGET_NR_fstat:
8604 {
8605 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008606#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008607 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008608#endif
bellard31e31b82003-02-18 22:55:36 +00008609 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008610 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008611
bellard579a97f2007-11-11 14:26:47 +00008612 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8613 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008614 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008615 __put_user(st.st_dev, &target_st->st_dev);
8616 __put_user(st.st_ino, &target_st->st_ino);
8617 __put_user(st.st_mode, &target_st->st_mode);
8618 __put_user(st.st_uid, &target_st->st_uid);
8619 __put_user(st.st_gid, &target_st->st_gid);
8620 __put_user(st.st_nlink, &target_st->st_nlink);
8621 __put_user(st.st_rdev, &target_st->st_rdev);
8622 __put_user(st.st_size, &target_st->st_size);
8623 __put_user(st.st_blksize, &target_st->st_blksize);
8624 __put_user(st.st_blocks, &target_st->st_blocks);
8625 __put_user(st.st_atime, &target_st->target_st_atime);
8626 __put_user(st.st_mtime, &target_st->target_st_mtime);
8627 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008628 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008629 }
8630 }
8631 break;
bellardebc05482003-09-30 21:08:41 +00008632#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008633 case TARGET_NR_olduname:
8634 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008635#endif
8636#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008637 case TARGET_NR_iopl:
8638 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008639#endif
bellard31e31b82003-02-18 22:55:36 +00008640 case TARGET_NR_vhangup:
8641 ret = get_errno(vhangup());
8642 break;
bellardebc05482003-09-30 21:08:41 +00008643#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008644 case TARGET_NR_idle:
8645 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008646#endif
bellard42ad6ae2005-01-03 22:48:11 +00008647#ifdef TARGET_NR_syscall
8648 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008649 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8650 arg6, arg7, arg8, 0);
8651 break;
bellard42ad6ae2005-01-03 22:48:11 +00008652#endif
bellard31e31b82003-02-18 22:55:36 +00008653 case TARGET_NR_wait4:
8654 {
8655 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008656 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008657 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008658 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008659 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008660 if (target_rusage)
8661 rusage_ptr = &rusage;
8662 else
8663 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008664 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008665 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008666 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008667 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008668 if (put_user_s32(status, status_ptr))
8669 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008670 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008671 if (target_rusage) {
8672 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8673 if (rusage_err) {
8674 ret = rusage_err;
8675 }
8676 }
bellard31e31b82003-02-18 22:55:36 +00008677 }
8678 }
8679 break;
thse5febef2007-04-01 18:31:35 +00008680#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008681 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008682 if (!(p = lock_user_string(arg1)))
8683 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008684 ret = get_errno(swapoff(p));
8685 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008686 break;
thse5febef2007-04-01 18:31:35 +00008687#endif
bellard31e31b82003-02-18 22:55:36 +00008688 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008689 {
pbrook53a59602006-03-25 19:31:22 +00008690 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008691 struct sysinfo value;
8692 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008693 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008694 {
bellard579a97f2007-11-11 14:26:47 +00008695 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8696 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008697 __put_user(value.uptime, &target_value->uptime);
8698 __put_user(value.loads[0], &target_value->loads[0]);
8699 __put_user(value.loads[1], &target_value->loads[1]);
8700 __put_user(value.loads[2], &target_value->loads[2]);
8701 __put_user(value.totalram, &target_value->totalram);
8702 __put_user(value.freeram, &target_value->freeram);
8703 __put_user(value.sharedram, &target_value->sharedram);
8704 __put_user(value.bufferram, &target_value->bufferram);
8705 __put_user(value.totalswap, &target_value->totalswap);
8706 __put_user(value.freeswap, &target_value->freeswap);
8707 __put_user(value.procs, &target_value->procs);
8708 __put_user(value.totalhigh, &target_value->totalhigh);
8709 __put_user(value.freehigh, &target_value->freehigh);
8710 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008711 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008712 }
8713 }
8714 break;
thse5febef2007-04-01 18:31:35 +00008715#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008716 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008717 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8718 break;
thse5febef2007-04-01 18:31:35 +00008719#endif
aurel32e5289082009-04-18 16:16:12 +00008720#ifdef TARGET_NR_semget
8721 case TARGET_NR_semget:
8722 ret = get_errno(semget(arg1, arg2, arg3));
8723 break;
8724#endif
8725#ifdef TARGET_NR_semop
8726 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008727 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008728 break;
8729#endif
8730#ifdef TARGET_NR_semctl
8731 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008732 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008733 break;
8734#endif
aurel32eeb438c2008-10-13 21:08:55 +00008735#ifdef TARGET_NR_msgctl
8736 case TARGET_NR_msgctl:
8737 ret = do_msgctl(arg1, arg2, arg3);
8738 break;
8739#endif
8740#ifdef TARGET_NR_msgget
8741 case TARGET_NR_msgget:
8742 ret = get_errno(msgget(arg1, arg2));
8743 break;
8744#endif
8745#ifdef TARGET_NR_msgrcv
8746 case TARGET_NR_msgrcv:
8747 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8748 break;
8749#endif
8750#ifdef TARGET_NR_msgsnd
8751 case TARGET_NR_msgsnd:
8752 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8753 break;
8754#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008755#ifdef TARGET_NR_shmget
8756 case TARGET_NR_shmget:
8757 ret = get_errno(shmget(arg1, arg2, arg3));
8758 break;
8759#endif
8760#ifdef TARGET_NR_shmctl
8761 case TARGET_NR_shmctl:
8762 ret = do_shmctl(arg1, arg2, arg3);
8763 break;
8764#endif
8765#ifdef TARGET_NR_shmat
8766 case TARGET_NR_shmat:
8767 ret = do_shmat(arg1, arg2, arg3);
8768 break;
8769#endif
8770#ifdef TARGET_NR_shmdt
8771 case TARGET_NR_shmdt:
8772 ret = do_shmdt(arg1);
8773 break;
8774#endif
bellard31e31b82003-02-18 22:55:36 +00008775 case TARGET_NR_fsync:
8776 ret = get_errno(fsync(arg1));
8777 break;
bellard31e31b82003-02-18 22:55:36 +00008778 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008779 /* Linux manages to have three different orderings for its
8780 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8781 * match the kernel's CONFIG_CLONE_* settings.
8782 * Microblaze is further special in that it uses a sixth
8783 * implicit argument to clone for the TLS pointer.
8784 */
8785#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008786 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008787#elif defined(TARGET_CLONE_BACKWARDS)
8788 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8789#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008790 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008791#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008792 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008793#endif
bellard1b6b0292003-03-22 17:31:38 +00008794 break;
bellardec86b0f2003-04-11 00:15:04 +00008795#ifdef __NR_exit_group
8796 /* new thread calls */
8797 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008798#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008799 _mcleanup();
8800#endif
bellarde9009672005-04-26 20:42:36 +00008801 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008802 ret = get_errno(exit_group(arg1));
8803 break;
8804#endif
bellard31e31b82003-02-18 22:55:36 +00008805 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008806 if (!(p = lock_user_string(arg1)))
8807 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008808 ret = get_errno(setdomainname(p, arg2));
8809 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008810 break;
8811 case TARGET_NR_uname:
8812 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008813 {
8814 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008815
bellard579a97f2007-11-11 14:26:47 +00008816 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8817 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008818 ret = get_errno(sys_uname(buf));
8819 if (!is_error(ret)) {
8820 /* Overrite the native machine name with whatever is being
8821 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01008822 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008823 /* Allow the user to override the reported release. */
8824 if (qemu_uname_release && *qemu_uname_release)
8825 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008826 }
pbrook53a59602006-03-25 19:31:22 +00008827 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008828 }
bellard31e31b82003-02-18 22:55:36 +00008829 break;
bellard6dbad632003-03-16 18:05:05 +00008830#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008831 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008832 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008833 break;
j_mayer84409dd2007-04-06 08:56:50 +00008834#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008835 case TARGET_NR_vm86old:
8836 goto unimplemented;
8837 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008838 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008839 break;
8840#endif
j_mayer84409dd2007-04-06 08:56:50 +00008841#endif
bellard31e31b82003-02-18 22:55:36 +00008842 case TARGET_NR_adjtimex:
8843 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008844#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008845 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008846#endif
bellard31e31b82003-02-18 22:55:36 +00008847 case TARGET_NR_init_module:
8848 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008849#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008850 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008851#endif
bellard31e31b82003-02-18 22:55:36 +00008852 goto unimplemented;
8853 case TARGET_NR_quotactl:
8854 goto unimplemented;
8855 case TARGET_NR_getpgid:
8856 ret = get_errno(getpgid(arg1));
8857 break;
8858 case TARGET_NR_fchdir:
8859 ret = get_errno(fchdir(arg1));
8860 break;
j_mayer84409dd2007-04-06 08:56:50 +00008861#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008862 case TARGET_NR_bdflush:
8863 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008864#endif
thse5febef2007-04-01 18:31:35 +00008865#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008866 case TARGET_NR_sysfs:
8867 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008868#endif
bellard31e31b82003-02-18 22:55:36 +00008869 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008870 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008871 break;
thse5febef2007-04-01 18:31:35 +00008872#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008873 case TARGET_NR_afs_syscall:
8874 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008875#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008876#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008877 case TARGET_NR__llseek:
8878 {
8879 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008880#if !defined(__NR_llseek)
8881 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8882 if (res == -1) {
8883 ret = get_errno(res);
8884 } else {
8885 ret = 0;
8886 }
8887#else
bellard31e31b82003-02-18 22:55:36 +00008888 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008889#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008890 if ((ret == 0) && put_user_s64(res, arg4)) {
8891 goto efault;
8892 }
bellard31e31b82003-02-18 22:55:36 +00008893 }
8894 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008895#endif
Chen Gang704eff62015-08-21 05:37:33 +08008896#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008897 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008898#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008899#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008900 {
pbrook53a59602006-03-25 19:31:22 +00008901 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008902 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008903 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008904
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308905 dirp = g_try_malloc(count);
8906 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008907 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008908 goto fail;
8909 }
ths3b46e622007-09-17 08:09:54 +00008910
bellard4add45b2003-06-05 01:52:59 +00008911 ret = get_errno(sys_getdents(arg1, dirp, count));
8912 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008913 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008914 struct target_dirent *tde;
8915 int len = ret;
8916 int reclen, treclen;
8917 int count1, tnamelen;
8918
8919 count1 = 0;
8920 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008921 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8922 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008923 tde = target_dirp;
8924 while (len > 0) {
8925 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008926 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8927 assert(tnamelen >= 0);
8928 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8929 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008930 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008931 tde->d_ino = tswapal(de->d_ino);
8932 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008933 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008934 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008935 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008936 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008937 count1 += treclen;
8938 }
8939 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008940 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008941 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308942 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008943 }
8944#else
bellard31e31b82003-02-18 22:55:36 +00008945 {
aurel326556a832008-10-13 21:08:17 +00008946 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008947 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008948
bellard579a97f2007-11-11 14:26:47 +00008949 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8950 goto efault;
bellard72f03902003-02-18 23:33:18 +00008951 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008952 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008953 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008954 int len = ret;
8955 int reclen;
8956 de = dirp;
8957 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008958 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008959 if (reclen > len)
8960 break;
bellard8083a3e2003-03-24 23:12:16 +00008961 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008962 tswapls(&de->d_ino);
8963 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008964 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008965 len -= reclen;
8966 }
8967 }
pbrook53a59602006-03-25 19:31:22 +00008968 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008969 }
bellard4add45b2003-06-05 01:52:59 +00008970#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008971#else
8972 /* Implement getdents in terms of getdents64 */
8973 {
8974 struct linux_dirent64 *dirp;
8975 abi_long count = arg3;
8976
8977 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8978 if (!dirp) {
8979 goto efault;
8980 }
8981 ret = get_errno(sys_getdents64(arg1, dirp, count));
8982 if (!is_error(ret)) {
8983 /* Convert the dirent64 structs to target dirent. We do this
8984 * in-place, since we can guarantee that a target_dirent is no
8985 * larger than a dirent64; however this means we have to be
8986 * careful to read everything before writing in the new format.
8987 */
8988 struct linux_dirent64 *de;
8989 struct target_dirent *tde;
8990 int len = ret;
8991 int tlen = 0;
8992
8993 de = dirp;
8994 tde = (struct target_dirent *)dirp;
8995 while (len > 0) {
8996 int namelen, treclen;
8997 int reclen = de->d_reclen;
8998 uint64_t ino = de->d_ino;
8999 int64_t off = de->d_off;
9000 uint8_t type = de->d_type;
9001
9002 namelen = strlen(de->d_name);
9003 treclen = offsetof(struct target_dirent, d_name)
9004 + namelen + 2;
9005 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9006
9007 memmove(tde->d_name, de->d_name, namelen + 1);
9008 tde->d_ino = tswapal(ino);
9009 tde->d_off = tswapal(off);
9010 tde->d_reclen = tswap16(treclen);
9011 /* The target_dirent type is in what was formerly a padding
9012 * byte at the end of the structure:
9013 */
9014 *(((char *)tde) + treclen - 1) = type;
9015
9016 de = (struct linux_dirent64 *)((char *)de + reclen);
9017 tde = (struct target_dirent *)((char *)tde + treclen);
9018 len -= reclen;
9019 tlen += treclen;
9020 }
9021 ret = tlen;
9022 }
9023 unlock_user(dirp, arg2, ret);
9024 }
9025#endif
bellard31e31b82003-02-18 22:55:36 +00009026 break;
Chen Gang704eff62015-08-21 05:37:33 +08009027#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009028#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009029 case TARGET_NR_getdents64:
9030 {
aurel326556a832008-10-13 21:08:17 +00009031 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009032 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009033 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9034 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009035 ret = get_errno(sys_getdents64(arg1, dirp, count));
9036 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009037 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009038 int len = ret;
9039 int reclen;
9040 de = dirp;
9041 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009042 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009043 if (reclen > len)
9044 break;
bellard8083a3e2003-03-24 23:12:16 +00009045 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009046 tswap64s((uint64_t *)&de->d_ino);
9047 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009048 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009049 len -= reclen;
9050 }
9051 }
pbrook53a59602006-03-25 19:31:22 +00009052 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009053 }
9054 break;
bellarda541f292004-04-12 20:39:29 +00009055#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009056#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009057 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009058 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009059 break;
thse5febef2007-04-01 18:31:35 +00009060#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009061#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9062# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009063 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009064# endif
9065# ifdef TARGET_NR_ppoll
9066 case TARGET_NR_ppoll:
9067# endif
bellard9de5e442003-03-23 16:49:39 +00009068 {
pbrook53a59602006-03-25 19:31:22 +00009069 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009070 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009071 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009072 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009073
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009074 pfd = NULL;
9075 target_pfd = NULL;
9076 if (nfds) {
9077 target_pfd = lock_user(VERIFY_WRITE, arg1,
9078 sizeof(struct target_pollfd) * nfds, 1);
9079 if (!target_pfd) {
9080 goto efault;
9081 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009082
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009083 pfd = alloca(sizeof(struct pollfd) * nfds);
9084 for (i = 0; i < nfds; i++) {
9085 pfd[i].fd = tswap32(target_pfd[i].fd);
9086 pfd[i].events = tswap16(target_pfd[i].events);
9087 }
bellard9de5e442003-03-23 16:49:39 +00009088 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009089
Peter Maydella6130232016-06-06 19:58:10 +01009090 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009091# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009092 case TARGET_NR_ppoll:
9093 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009094 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9095 target_sigset_t *target_set;
9096 sigset_t _set, *set = &_set;
9097
9098 if (arg3) {
9099 if (target_to_host_timespec(timeout_ts, arg3)) {
9100 unlock_user(target_pfd, arg1, 0);
9101 goto efault;
9102 }
9103 } else {
9104 timeout_ts = NULL;
9105 }
9106
9107 if (arg4) {
9108 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9109 if (!target_set) {
9110 unlock_user(target_pfd, arg1, 0);
9111 goto efault;
9112 }
9113 target_to_host_sigset(set, target_set);
9114 } else {
9115 set = NULL;
9116 }
9117
Peter Maydella6130232016-06-06 19:58:10 +01009118 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9119 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009120
9121 if (!is_error(ret) && arg3) {
9122 host_to_target_timespec(arg3, timeout_ts);
9123 }
9124 if (arg4) {
9125 unlock_user(target_set, arg4, 0);
9126 }
Peter Maydella6130232016-06-06 19:58:10 +01009127 break;
9128 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009129# endif
Peter Maydella6130232016-06-06 19:58:10 +01009130# ifdef TARGET_NR_poll
9131 case TARGET_NR_poll:
9132 {
9133 struct timespec ts, *pts;
9134
9135 if (arg3 >= 0) {
9136 /* Convert ms to secs, ns */
9137 ts.tv_sec = arg3 / 1000;
9138 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9139 pts = &ts;
9140 } else {
9141 /* -ve poll() timeout means "infinite" */
9142 pts = NULL;
9143 }
9144 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9145 break;
9146 }
9147# endif
9148 default:
9149 g_assert_not_reached();
9150 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009151
bellard9de5e442003-03-23 16:49:39 +00009152 if (!is_error(ret)) {
9153 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009154 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009155 }
9156 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009157 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009158 }
9159 break;
thse5febef2007-04-01 18:31:35 +00009160#endif
bellard31e31b82003-02-18 22:55:36 +00009161 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009162 /* NOTE: the flock constant seems to be the same for every
9163 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009164 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009165 break;
9166 case TARGET_NR_readv:
9167 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009168 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9169 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009170 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009171 unlock_iovec(vec, arg2, arg3, 1);
9172 } else {
9173 ret = -host_to_target_errno(errno);
9174 }
bellard31e31b82003-02-18 22:55:36 +00009175 }
9176 break;
9177 case TARGET_NR_writev:
9178 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009179 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9180 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009181 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009182 unlock_iovec(vec, arg2, arg3, 0);
9183 } else {
9184 ret = -host_to_target_errno(errno);
9185 }
bellard31e31b82003-02-18 22:55:36 +00009186 }
9187 break;
9188 case TARGET_NR_getsid:
9189 ret = get_errno(getsid(arg1));
9190 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009191#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009192 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009193 ret = get_errno(fdatasync(arg1));
9194 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009195#endif
Chen Gang704eff62015-08-21 05:37:33 +08009196#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009197 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009198 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009199 return value. */
ths0da46a62007-10-20 20:23:07 +00009200 ret = -TARGET_ENOTDIR;
9201 break;
Chen Gang704eff62015-08-21 05:37:33 +08009202#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009203 case TARGET_NR_sched_getaffinity:
9204 {
9205 unsigned int mask_size;
9206 unsigned long *mask;
9207
9208 /*
9209 * sched_getaffinity needs multiples of ulong, so need to take
9210 * care of mismatches between target ulong and host ulong sizes.
9211 */
9212 if (arg2 & (sizeof(abi_ulong) - 1)) {
9213 ret = -TARGET_EINVAL;
9214 break;
9215 }
9216 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9217
9218 mask = alloca(mask_size);
9219 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9220
9221 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009222 if (ret > arg2) {
9223 /* More data returned than the caller's buffer will fit.
9224 * This only happens if sizeof(abi_long) < sizeof(long)
9225 * and the caller passed us a buffer holding an odd number
9226 * of abi_longs. If the host kernel is actually using the
9227 * extra 4 bytes then fail EINVAL; otherwise we can just
9228 * ignore them and only copy the interesting part.
9229 */
9230 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9231 if (numcpus > arg2 * 8) {
9232 ret = -TARGET_EINVAL;
9233 break;
9234 }
9235 ret = arg2;
9236 }
9237
Mike McCormackcd18f052011-04-18 14:43:36 +09009238 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009239 goto efault;
9240 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009241 }
9242 }
9243 break;
9244 case TARGET_NR_sched_setaffinity:
9245 {
9246 unsigned int mask_size;
9247 unsigned long *mask;
9248
9249 /*
9250 * sched_setaffinity needs multiples of ulong, so need to take
9251 * care of mismatches between target ulong and host ulong sizes.
9252 */
9253 if (arg2 & (sizeof(abi_ulong) - 1)) {
9254 ret = -TARGET_EINVAL;
9255 break;
9256 }
9257 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9258
9259 mask = alloca(mask_size);
9260 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9261 goto efault;
9262 }
9263 memcpy(mask, p, arg2);
9264 unlock_user_struct(p, arg2, 0);
9265
9266 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9267 }
9268 break;
bellard31e31b82003-02-18 22:55:36 +00009269 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009270 {
pbrook53a59602006-03-25 19:31:22 +00009271 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009272 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009273
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009274 if (arg2 == 0) {
9275 return -TARGET_EINVAL;
9276 }
bellard579a97f2007-11-11 14:26:47 +00009277 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9278 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009279 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009280 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009281 ret = get_errno(sched_setparam(arg1, &schp));
9282 }
9283 break;
bellard31e31b82003-02-18 22:55:36 +00009284 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009285 {
pbrook53a59602006-03-25 19:31:22 +00009286 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009287 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009288
9289 if (arg2 == 0) {
9290 return -TARGET_EINVAL;
9291 }
bellard5cd43932003-03-29 16:54:36 +00009292 ret = get_errno(sched_getparam(arg1, &schp));
9293 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009294 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9295 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009296 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009297 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009298 }
9299 }
9300 break;
bellard31e31b82003-02-18 22:55:36 +00009301 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009302 {
pbrook53a59602006-03-25 19:31:22 +00009303 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009304 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009305 if (arg3 == 0) {
9306 return -TARGET_EINVAL;
9307 }
bellard579a97f2007-11-11 14:26:47 +00009308 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9309 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009310 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009311 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009312 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9313 }
9314 break;
bellard31e31b82003-02-18 22:55:36 +00009315 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009316 ret = get_errno(sched_getscheduler(arg1));
9317 break;
bellard31e31b82003-02-18 22:55:36 +00009318 case TARGET_NR_sched_yield:
9319 ret = get_errno(sched_yield());
9320 break;
9321 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009322 ret = get_errno(sched_get_priority_max(arg1));
9323 break;
bellard31e31b82003-02-18 22:55:36 +00009324 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009325 ret = get_errno(sched_get_priority_min(arg1));
9326 break;
bellard31e31b82003-02-18 22:55:36 +00009327 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009328 {
bellard5cd43932003-03-29 16:54:36 +00009329 struct timespec ts;
9330 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9331 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009332 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009333 }
9334 }
9335 break;
bellard31e31b82003-02-18 22:55:36 +00009336 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009337 {
bellard1b6b0292003-03-22 17:31:38 +00009338 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009339 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009340 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009341 if (is_error(ret) && arg2) {
9342 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009343 }
9344 }
9345 break;
thse5febef2007-04-01 18:31:35 +00009346#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009347 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009348 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009349#endif
9350#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009351 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009352 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009353#endif
bellard31e31b82003-02-18 22:55:36 +00009354 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009355 switch (arg1) {
9356 case PR_GET_PDEATHSIG:
9357 {
9358 int deathsig;
9359 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9360 if (!is_error(ret) && arg2
9361 && put_user_ual(deathsig, arg2)) {
9362 goto efault;
thse5574482007-02-11 20:03:13 +00009363 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009364 break;
9365 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009366#ifdef PR_GET_NAME
9367 case PR_GET_NAME:
9368 {
9369 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9370 if (!name) {
9371 goto efault;
9372 }
9373 ret = get_errno(prctl(arg1, (unsigned long)name,
9374 arg3, arg4, arg5));
9375 unlock_user(name, arg2, 16);
9376 break;
9377 }
9378 case PR_SET_NAME:
9379 {
9380 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9381 if (!name) {
9382 goto efault;
9383 }
9384 ret = get_errno(prctl(arg1, (unsigned long)name,
9385 arg3, arg4, arg5));
9386 unlock_user(name, arg2, 0);
9387 break;
9388 }
9389#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009390 default:
9391 /* Most prctl options have no pointer arguments */
9392 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9393 break;
9394 }
ths39b9aae2007-02-11 18:36:44 +00009395 break;
bellardd2fd1af2007-11-14 18:08:56 +00009396#ifdef TARGET_NR_arch_prctl
9397 case TARGET_NR_arch_prctl:
9398#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9399 ret = do_arch_prctl(cpu_env, arg1, arg2);
9400 break;
9401#else
9402 goto unimplemented;
9403#endif
9404#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009405#ifdef TARGET_NR_pread64
9406 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009407 if (regpairs_aligned(cpu_env)) {
9408 arg4 = arg5;
9409 arg5 = arg6;
9410 }
aurel32f2c7ba12008-03-28 22:32:06 +00009411 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9412 goto efault;
9413 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9414 unlock_user(p, arg2, ret);
9415 break;
9416 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009417 if (regpairs_aligned(cpu_env)) {
9418 arg4 = arg5;
9419 arg5 = arg6;
9420 }
aurel32f2c7ba12008-03-28 22:32:06 +00009421 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9422 goto efault;
9423 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9424 unlock_user(p, arg2, 0);
9425 break;
9426#endif
bellard31e31b82003-02-18 22:55:36 +00009427 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009428 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9429 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009430 ret = get_errno(sys_getcwd1(p, arg2));
9431 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009432 break;
9433 case TARGET_NR_capget:
9434 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009435 {
9436 struct target_user_cap_header *target_header;
9437 struct target_user_cap_data *target_data = NULL;
9438 struct __user_cap_header_struct header;
9439 struct __user_cap_data_struct data[2];
9440 struct __user_cap_data_struct *dataptr = NULL;
9441 int i, target_datalen;
9442 int data_items = 1;
9443
9444 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9445 goto efault;
9446 }
9447 header.version = tswap32(target_header->version);
9448 header.pid = tswap32(target_header->pid);
9449
Peter Maydellec864872014-03-19 16:07:30 +00009450 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009451 /* Version 2 and up takes pointer to two user_data structs */
9452 data_items = 2;
9453 }
9454
9455 target_datalen = sizeof(*target_data) * data_items;
9456
9457 if (arg2) {
9458 if (num == TARGET_NR_capget) {
9459 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9460 } else {
9461 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9462 }
9463 if (!target_data) {
9464 unlock_user_struct(target_header, arg1, 0);
9465 goto efault;
9466 }
9467
9468 if (num == TARGET_NR_capset) {
9469 for (i = 0; i < data_items; i++) {
9470 data[i].effective = tswap32(target_data[i].effective);
9471 data[i].permitted = tswap32(target_data[i].permitted);
9472 data[i].inheritable = tswap32(target_data[i].inheritable);
9473 }
9474 }
9475
9476 dataptr = data;
9477 }
9478
9479 if (num == TARGET_NR_capget) {
9480 ret = get_errno(capget(&header, dataptr));
9481 } else {
9482 ret = get_errno(capset(&header, dataptr));
9483 }
9484
9485 /* The kernel always updates version for both capget and capset */
9486 target_header->version = tswap32(header.version);
9487 unlock_user_struct(target_header, arg1, 1);
9488
9489 if (arg2) {
9490 if (num == TARGET_NR_capget) {
9491 for (i = 0; i < data_items; i++) {
9492 target_data[i].effective = tswap32(data[i].effective);
9493 target_data[i].permitted = tswap32(data[i].permitted);
9494 target_data[i].inheritable = tswap32(data[i].inheritable);
9495 }
9496 unlock_user(target_data, arg2, target_datalen);
9497 } else {
9498 unlock_user(target_data, arg2, 0);
9499 }
9500 }
9501 break;
9502 }
bellard31e31b82003-02-18 22:55:36 +00009503 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009504 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009505 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009506
9507#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009508 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009509 {
9510 off_t *offp = NULL;
9511 off_t off;
9512 if (arg3) {
9513 ret = get_user_sal(off, arg3);
9514 if (is_error(ret)) {
9515 break;
9516 }
9517 offp = &off;
9518 }
9519 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9520 if (!is_error(ret) && arg3) {
9521 abi_long ret2 = put_user_sal(off, arg3);
9522 if (is_error(ret2)) {
9523 ret = ret2;
9524 }
9525 }
9526 break;
9527 }
9528#ifdef TARGET_NR_sendfile64
9529 case TARGET_NR_sendfile64:
9530 {
9531 off_t *offp = NULL;
9532 off_t off;
9533 if (arg3) {
9534 ret = get_user_s64(off, arg3);
9535 if (is_error(ret)) {
9536 break;
9537 }
9538 offp = &off;
9539 }
9540 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9541 if (!is_error(ret) && arg3) {
9542 abi_long ret2 = put_user_s64(off, arg3);
9543 if (is_error(ret2)) {
9544 ret = ret2;
9545 }
9546 }
9547 break;
9548 }
9549#endif
9550#else
9551 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009552#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009553 case TARGET_NR_sendfile64:
9554#endif
bellard5cd43932003-03-29 16:54:36 +00009555 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009556#endif
9557
bellardebc05482003-09-30 21:08:41 +00009558#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009559 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009560 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009561#endif
9562#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009563 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009564 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009565#endif
bellard048f6b42005-11-26 18:47:20 +00009566#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009567 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009568 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9569 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009570 break;
bellard048f6b42005-11-26 18:47:20 +00009571#endif
bellardebc05482003-09-30 21:08:41 +00009572#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009573 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009574 {
9575 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009576 int resource = target_to_host_resource(arg1);
9577 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009578 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009579 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009580 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9581 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009582 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9583 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009584 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009585 }
9586 break;
9587 }
bellardebc05482003-09-30 21:08:41 +00009588#endif
bellarda315a142005-01-30 22:59:18 +00009589#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009590 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009591 if (!(p = lock_user_string(arg1)))
9592 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009593 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9594 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009595 break;
bellarda315a142005-01-30 22:59:18 +00009596#endif
9597#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009598 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009599 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009600 break;
bellarda315a142005-01-30 22:59:18 +00009601#endif
9602#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009603 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009604 if (!(p = lock_user_string(arg1)))
9605 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009606 ret = get_errno(stat(path(p), &st));
9607 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009608 if (!is_error(ret))
9609 ret = host_to_target_stat64(cpu_env, arg2, &st);
9610 break;
bellarda315a142005-01-30 22:59:18 +00009611#endif
9612#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009613 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009614 if (!(p = lock_user_string(arg1)))
9615 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009616 ret = get_errno(lstat(path(p), &st));
9617 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009618 if (!is_error(ret))
9619 ret = host_to_target_stat64(cpu_env, arg2, &st);
9620 break;
bellarda315a142005-01-30 22:59:18 +00009621#endif
9622#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009623 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009624 ret = get_errno(fstat(arg1, &st));
9625 if (!is_error(ret))
9626 ret = host_to_target_stat64(cpu_env, arg2, &st);
9627 break;
bellardec86b0f2003-04-11 00:15:04 +00009628#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009629#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009630#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009631 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009632#endif
9633#ifdef TARGET_NR_newfstatat
9634 case TARGET_NR_newfstatat:
9635#endif
balrog6a24a772008-09-20 02:23:36 +00009636 if (!(p = lock_user_string(arg2)))
9637 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009638 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009639 if (!is_error(ret))
9640 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009641 break;
bellarda315a142005-01-30 22:59:18 +00009642#endif
Chen Gang704eff62015-08-21 05:37:33 +08009643#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009644 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009645 if (!(p = lock_user_string(arg1)))
9646 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009647 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9648 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009649 break;
Chen Gang704eff62015-08-21 05:37:33 +08009650#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009651#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009652 case TARGET_NR_getuid:
9653 ret = get_errno(high2lowuid(getuid()));
9654 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009655#endif
9656#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009657 case TARGET_NR_getgid:
9658 ret = get_errno(high2lowgid(getgid()));
9659 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009660#endif
9661#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009662 case TARGET_NR_geteuid:
9663 ret = get_errno(high2lowuid(geteuid()));
9664 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009665#endif
9666#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009667 case TARGET_NR_getegid:
9668 ret = get_errno(high2lowgid(getegid()));
9669 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009670#endif
bellard67867302003-11-23 17:05:30 +00009671 case TARGET_NR_setreuid:
9672 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9673 break;
9674 case TARGET_NR_setregid:
9675 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9676 break;
9677 case TARGET_NR_getgroups:
9678 {
9679 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009680 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009681 gid_t *grouplist;
9682 int i;
9683
9684 grouplist = alloca(gidsetsize * sizeof(gid_t));
9685 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009686 if (gidsetsize == 0)
9687 break;
bellard67867302003-11-23 17:05:30 +00009688 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009689 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009690 if (!target_grouplist)
9691 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009692 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009693 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009694 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009695 }
9696 }
9697 break;
9698 case TARGET_NR_setgroups:
9699 {
9700 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009701 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009702 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009703 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009704 if (gidsetsize) {
9705 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009706 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009707 if (!target_grouplist) {
9708 ret = -TARGET_EFAULT;
9709 goto fail;
9710 }
9711 for (i = 0; i < gidsetsize; i++) {
9712 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9713 }
9714 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009715 }
bellard67867302003-11-23 17:05:30 +00009716 ret = get_errno(setgroups(gidsetsize, grouplist));
9717 }
9718 break;
9719 case TARGET_NR_fchown:
9720 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9721 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009722#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009723 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009724 if (!(p = lock_user_string(arg2)))
9725 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009726 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9727 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009728 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009729 break;
9730#endif
bellard67867302003-11-23 17:05:30 +00009731#ifdef TARGET_NR_setresuid
9732 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009733 ret = get_errno(sys_setresuid(low2highuid(arg1),
9734 low2highuid(arg2),
9735 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009736 break;
9737#endif
9738#ifdef TARGET_NR_getresuid
9739 case TARGET_NR_getresuid:
9740 {
pbrook53a59602006-03-25 19:31:22 +00009741 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009742 ret = get_errno(getresuid(&ruid, &euid, &suid));
9743 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009744 if (put_user_id(high2lowuid(ruid), arg1)
9745 || put_user_id(high2lowuid(euid), arg2)
9746 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009747 goto efault;
bellard67867302003-11-23 17:05:30 +00009748 }
9749 }
9750 break;
9751#endif
9752#ifdef TARGET_NR_getresgid
9753 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009754 ret = get_errno(sys_setresgid(low2highgid(arg1),
9755 low2highgid(arg2),
9756 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009757 break;
9758#endif
9759#ifdef TARGET_NR_getresgid
9760 case TARGET_NR_getresgid:
9761 {
pbrook53a59602006-03-25 19:31:22 +00009762 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009763 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9764 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009765 if (put_user_id(high2lowgid(rgid), arg1)
9766 || put_user_id(high2lowgid(egid), arg2)
9767 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009768 goto efault;
bellard67867302003-11-23 17:05:30 +00009769 }
9770 }
9771 break;
9772#endif
Chen Gang704eff62015-08-21 05:37:33 +08009773#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009774 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009775 if (!(p = lock_user_string(arg1)))
9776 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009777 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9778 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009779 break;
Chen Gang704eff62015-08-21 05:37:33 +08009780#endif
bellard67867302003-11-23 17:05:30 +00009781 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009782 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009783 break;
9784 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009785 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009786 break;
9787 case TARGET_NR_setfsuid:
9788 ret = get_errno(setfsuid(arg1));
9789 break;
9790 case TARGET_NR_setfsgid:
9791 ret = get_errno(setfsgid(arg1));
9792 break;
bellard67867302003-11-23 17:05:30 +00009793
bellarda315a142005-01-30 22:59:18 +00009794#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009795 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009796 if (!(p = lock_user_string(arg1)))
9797 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009798 ret = get_errno(lchown(p, arg2, arg3));
9799 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009800 break;
bellarda315a142005-01-30 22:59:18 +00009801#endif
9802#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009803 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009804 ret = get_errno(getuid());
9805 break;
bellarda315a142005-01-30 22:59:18 +00009806#endif
aurel3264b4d282008-11-14 17:20:15 +00009807
9808#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9809 /* Alpha specific */
9810 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009811 {
9812 uid_t euid;
9813 euid=geteuid();
9814 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9815 }
aurel3264b4d282008-11-14 17:20:15 +00009816 ret = get_errno(getuid());
9817 break;
9818#endif
9819#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9820 /* Alpha specific */
9821 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009822 {
9823 uid_t egid;
9824 egid=getegid();
9825 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9826 }
aurel3264b4d282008-11-14 17:20:15 +00009827 ret = get_errno(getgid());
9828 break;
9829#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009830#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9831 /* Alpha specific */
9832 case TARGET_NR_osf_getsysinfo:
9833 ret = -TARGET_EOPNOTSUPP;
9834 switch (arg1) {
9835 case TARGET_GSI_IEEE_FP_CONTROL:
9836 {
9837 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9838
9839 /* Copied from linux ieee_fpcr_to_swcr. */
9840 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9841 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9842 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9843 | SWCR_TRAP_ENABLE_DZE
9844 | SWCR_TRAP_ENABLE_OVF);
9845 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9846 | SWCR_TRAP_ENABLE_INE);
9847 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9848 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9849
9850 if (put_user_u64 (swcr, arg2))
9851 goto efault;
9852 ret = 0;
9853 }
9854 break;
9855
9856 /* case GSI_IEEE_STATE_AT_SIGNAL:
9857 -- Not implemented in linux kernel.
9858 case GSI_UACPROC:
9859 -- Retrieves current unaligned access state; not much used.
9860 case GSI_PROC_TYPE:
9861 -- Retrieves implver information; surely not used.
9862 case GSI_GET_HWRPB:
9863 -- Grabs a copy of the HWRPB; surely not used.
9864 */
9865 }
9866 break;
9867#endif
9868#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9869 /* Alpha specific */
9870 case TARGET_NR_osf_setsysinfo:
9871 ret = -TARGET_EOPNOTSUPP;
9872 switch (arg1) {
9873 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009874 {
9875 uint64_t swcr, fpcr, orig_fpcr;
9876
Richard Henderson6e06d512012-06-01 09:08:21 -07009877 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009878 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009879 }
9880 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009881 fpcr = orig_fpcr & FPCR_DYN_MASK;
9882
9883 /* Copied from linux ieee_swcr_to_fpcr. */
9884 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9885 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9886 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9887 | SWCR_TRAP_ENABLE_DZE
9888 | SWCR_TRAP_ENABLE_OVF)) << 48;
9889 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9890 | SWCR_TRAP_ENABLE_INE)) << 57;
9891 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9892 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9893
Richard Henderson6e06d512012-06-01 09:08:21 -07009894 cpu_alpha_store_fpcr(cpu_env, fpcr);
9895 ret = 0;
9896 }
9897 break;
9898
9899 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9900 {
9901 uint64_t exc, fpcr, orig_fpcr;
9902 int si_code;
9903
9904 if (get_user_u64(exc, arg2)) {
9905 goto efault;
9906 }
9907
9908 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9909
9910 /* We only add to the exception status here. */
9911 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9912
9913 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009914 ret = 0;
9915
Richard Henderson6e06d512012-06-01 09:08:21 -07009916 /* Old exceptions are not signaled. */
9917 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009918
Richard Henderson6e06d512012-06-01 09:08:21 -07009919 /* If any exceptions set by this call,
9920 and are unmasked, send a signal. */
9921 si_code = 0;
9922 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9923 si_code = TARGET_FPE_FLTRES;
9924 }
9925 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9926 si_code = TARGET_FPE_FLTUND;
9927 }
9928 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9929 si_code = TARGET_FPE_FLTOVF;
9930 }
9931 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9932 si_code = TARGET_FPE_FLTDIV;
9933 }
9934 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9935 si_code = TARGET_FPE_FLTINV;
9936 }
9937 if (si_code != 0) {
9938 target_siginfo_t info;
9939 info.si_signo = SIGFPE;
9940 info.si_errno = 0;
9941 info.si_code = si_code;
9942 info._sifields._sigfault._addr
9943 = ((CPUArchState *)cpu_env)->pc;
9944 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009945 }
9946 }
9947 break;
9948
9949 /* case SSI_NVPAIRS:
9950 -- Used with SSIN_UACPROC to enable unaligned accesses.
9951 case SSI_IEEE_STATE_AT_SIGNAL:
9952 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9953 -- Not implemented in linux kernel
9954 */
9955 }
9956 break;
9957#endif
9958#ifdef TARGET_NR_osf_sigprocmask
9959 /* Alpha specific. */
9960 case TARGET_NR_osf_sigprocmask:
9961 {
9962 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009963 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009964 sigset_t set, oldset;
9965
9966 switch(arg1) {
9967 case TARGET_SIG_BLOCK:
9968 how = SIG_BLOCK;
9969 break;
9970 case TARGET_SIG_UNBLOCK:
9971 how = SIG_UNBLOCK;
9972 break;
9973 case TARGET_SIG_SETMASK:
9974 how = SIG_SETMASK;
9975 break;
9976 default:
9977 ret = -TARGET_EINVAL;
9978 goto fail;
9979 }
9980 mask = arg2;
9981 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009982 ret = do_sigprocmask(how, &set, &oldset);
9983 if (!ret) {
9984 host_to_target_old_sigset(&mask, &oldset);
9985 ret = mask;
9986 }
Richard Hendersonba0e2762009-12-09 15:56:29 -08009987 }
9988 break;
9989#endif
aurel3264b4d282008-11-14 17:20:15 +00009990
bellarda315a142005-01-30 22:59:18 +00009991#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009992 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009993 ret = get_errno(getgid());
9994 break;
bellarda315a142005-01-30 22:59:18 +00009995#endif
9996#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009997 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009998 ret = get_errno(geteuid());
9999 break;
bellarda315a142005-01-30 22:59:18 +000010000#endif
10001#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010002 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010003 ret = get_errno(getegid());
10004 break;
bellarda315a142005-01-30 22:59:18 +000010005#endif
10006#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010007 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010008 ret = get_errno(setreuid(arg1, arg2));
10009 break;
bellarda315a142005-01-30 22:59:18 +000010010#endif
10011#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010012 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010013 ret = get_errno(setregid(arg1, arg2));
10014 break;
bellarda315a142005-01-30 22:59:18 +000010015#endif
10016#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010017 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010018 {
10019 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010020 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010021 gid_t *grouplist;
10022 int i;
10023
10024 grouplist = alloca(gidsetsize * sizeof(gid_t));
10025 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010026 if (gidsetsize == 0)
10027 break;
bellard99c475a2005-01-31 20:45:13 +000010028 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010029 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10030 if (!target_grouplist) {
10031 ret = -TARGET_EFAULT;
10032 goto fail;
10033 }
balroga2155fc2008-09-20 02:12:08 +000010034 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010035 target_grouplist[i] = tswap32(grouplist[i]);
10036 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010037 }
10038 }
10039 break;
bellarda315a142005-01-30 22:59:18 +000010040#endif
10041#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010042 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010043 {
10044 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010045 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010046 gid_t *grouplist;
10047 int i;
ths3b46e622007-09-17 08:09:54 +000010048
bellard99c475a2005-01-31 20:45:13 +000010049 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010050 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10051 if (!target_grouplist) {
10052 ret = -TARGET_EFAULT;
10053 goto fail;
10054 }
bellard99c475a2005-01-31 20:45:13 +000010055 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010056 grouplist[i] = tswap32(target_grouplist[i]);
10057 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010058 ret = get_errno(setgroups(gidsetsize, grouplist));
10059 }
10060 break;
bellarda315a142005-01-30 22:59:18 +000010061#endif
10062#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010063 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010064 ret = get_errno(fchown(arg1, arg2, arg3));
10065 break;
bellarda315a142005-01-30 22:59:18 +000010066#endif
10067#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010068 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010069 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010070 break;
bellarda315a142005-01-30 22:59:18 +000010071#endif
10072#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010073 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010074 {
pbrook53a59602006-03-25 19:31:22 +000010075 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010076 ret = get_errno(getresuid(&ruid, &euid, &suid));
10077 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010078 if (put_user_u32(ruid, arg1)
10079 || put_user_u32(euid, arg2)
10080 || put_user_u32(suid, arg3))
10081 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010082 }
10083 }
10084 break;
bellarda315a142005-01-30 22:59:18 +000010085#endif
10086#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010087 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010088 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010089 break;
bellarda315a142005-01-30 22:59:18 +000010090#endif
10091#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010092 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010093 {
pbrook53a59602006-03-25 19:31:22 +000010094 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010095 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10096 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010097 if (put_user_u32(rgid, arg1)
10098 || put_user_u32(egid, arg2)
10099 || put_user_u32(sgid, arg3))
10100 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010101 }
10102 }
10103 break;
bellarda315a142005-01-30 22:59:18 +000010104#endif
10105#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010106 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010107 if (!(p = lock_user_string(arg1)))
10108 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010109 ret = get_errno(chown(p, arg2, arg3));
10110 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010111 break;
bellarda315a142005-01-30 22:59:18 +000010112#endif
10113#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010114 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010115 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010116 break;
bellarda315a142005-01-30 22:59:18 +000010117#endif
10118#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010119 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010120 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010121 break;
bellarda315a142005-01-30 22:59:18 +000010122#endif
10123#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010124 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010125 ret = get_errno(setfsuid(arg1));
10126 break;
bellarda315a142005-01-30 22:59:18 +000010127#endif
10128#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010129 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010130 ret = get_errno(setfsgid(arg1));
10131 break;
bellarda315a142005-01-30 22:59:18 +000010132#endif
bellard67867302003-11-23 17:05:30 +000010133
bellard31e31b82003-02-18 22:55:36 +000010134 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010135 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010136#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010137 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010138 {
10139 void *a;
10140 ret = -TARGET_EFAULT;
10141 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10142 goto efault;
10143 if (!(p = lock_user_string(arg3)))
10144 goto mincore_fail;
10145 ret = get_errno(mincore(a, arg2, p));
10146 unlock_user(p, arg3, ret);
10147 mincore_fail:
10148 unlock_user(a, arg1, 0);
10149 }
10150 break;
bellardffa65c32004-01-04 23:57:22 +000010151#endif
aurel32408321b2008-10-01 21:46:32 +000010152#ifdef TARGET_NR_arm_fadvise64_64
10153 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010154 /* arm_fadvise64_64 looks like fadvise64_64 but
10155 * with different argument order: fd, advice, offset, len
10156 * rather than the usual fd, offset, len, advice.
10157 * Note that offset and len are both 64-bit so appear as
10158 * pairs of 32-bit registers.
10159 */
10160 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10161 target_offset64(arg5, arg6), arg2);
10162 ret = -host_to_target_errno(ret);
10163 break;
aurel32408321b2008-10-01 21:46:32 +000010164#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010165
10166#if TARGET_ABI_BITS == 32
10167
10168#ifdef TARGET_NR_fadvise64_64
10169 case TARGET_NR_fadvise64_64:
10170 /* 6 args: fd, offset (high, low), len (high, low), advice */
10171 if (regpairs_aligned(cpu_env)) {
10172 /* offset is in (3,4), len in (5,6) and advice in 7 */
10173 arg2 = arg3;
10174 arg3 = arg4;
10175 arg4 = arg5;
10176 arg5 = arg6;
10177 arg6 = arg7;
10178 }
10179 ret = -host_to_target_errno(posix_fadvise(arg1,
10180 target_offset64(arg2, arg3),
10181 target_offset64(arg4, arg5),
10182 arg6));
10183 break;
10184#endif
10185
10186#ifdef TARGET_NR_fadvise64
10187 case TARGET_NR_fadvise64:
10188 /* 5 args: fd, offset (high, low), len, advice */
10189 if (regpairs_aligned(cpu_env)) {
10190 /* offset is in (3,4), len in 5 and advice in 6 */
10191 arg2 = arg3;
10192 arg3 = arg4;
10193 arg4 = arg5;
10194 arg5 = arg6;
10195 }
10196 ret = -host_to_target_errno(posix_fadvise(arg1,
10197 target_offset64(arg2, arg3),
10198 arg4, arg5));
10199 break;
10200#endif
10201
10202#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010203#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010204#ifdef TARGET_NR_fadvise64_64
10205 case TARGET_NR_fadvise64_64:
10206#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010207#ifdef TARGET_NR_fadvise64
10208 case TARGET_NR_fadvise64:
10209#endif
10210#ifdef TARGET_S390X
10211 switch (arg4) {
10212 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10213 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10214 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10215 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10216 default: break;
10217 }
10218#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010219 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10220 break;
aurel32408321b2008-10-01 21:46:32 +000010221#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010222#endif /* end of 64-bit ABI fadvise handling */
10223
bellardffa65c32004-01-04 23:57:22 +000010224#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010225 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010226 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010227 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010228 This will break MADV_DONTNEED.
10229 This is a hint, so ignoring and returning success is ok. */
10230 ret = get_errno(0);
10231 break;
bellardffa65c32004-01-04 23:57:22 +000010232#endif
blueswir1992f48a2007-10-14 16:27:31 +000010233#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010234 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010235 {
thsb1e341e2007-03-20 21:50:52 +000010236 int cmd;
bellard77e46722003-04-29 20:39:06 +000010237 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010238 from_flock64_fn *copyfrom = copy_from_user_flock64;
10239 to_flock64_fn *copyto = copy_to_user_flock64;
10240
pbrookce4defa2006-02-09 16:49:55 +000010241#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010242 if (((CPUARMState *)cpu_env)->eabi) {
10243 copyfrom = copy_from_user_eabi_flock64;
10244 copyto = copy_to_user_eabi_flock64;
10245 }
pbrookce4defa2006-02-09 16:49:55 +000010246#endif
bellard77e46722003-04-29 20:39:06 +000010247
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010248 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010249 if (cmd == -TARGET_EINVAL) {
10250 ret = cmd;
10251 break;
10252 }
thsb1e341e2007-03-20 21:50:52 +000010253
bellard60cd49d2003-03-16 22:53:56 +000010254 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010255 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010256 ret = copyfrom(&fl, arg3);
10257 if (ret) {
10258 break;
ths58134272007-03-31 18:59:32 +000010259 }
thsb1e341e2007-03-20 21:50:52 +000010260 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010261 if (ret == 0) {
10262 ret = copyto(arg3, &fl);
10263 }
bellard77e46722003-04-29 20:39:06 +000010264 break;
10265
thsb1e341e2007-03-20 21:50:52 +000010266 case TARGET_F_SETLK64:
10267 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010268 ret = copyfrom(&fl, arg3);
10269 if (ret) {
10270 break;
pbrookce4defa2006-02-09 16:49:55 +000010271 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010272 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010273 break;
bellard60cd49d2003-03-16 22:53:56 +000010274 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010275 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010276 break;
10277 }
bellard77e46722003-04-29 20:39:06 +000010278 break;
10279 }
bellard60cd49d2003-03-16 22:53:56 +000010280#endif
ths7d600c82006-12-08 01:32:58 +000010281#ifdef TARGET_NR_cacheflush
10282 case TARGET_NR_cacheflush:
10283 /* self-modifying code is handled automatically, so nothing needed */
10284 ret = 0;
10285 break;
10286#endif
bellardebc05482003-09-30 21:08:41 +000010287#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010288 case TARGET_NR_security:
10289 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010290#endif
bellardc573ff62004-01-04 15:51:36 +000010291#ifdef TARGET_NR_getpagesize
10292 case TARGET_NR_getpagesize:
10293 ret = TARGET_PAGE_SIZE;
10294 break;
10295#endif
bellard31e31b82003-02-18 22:55:36 +000010296 case TARGET_NR_gettid:
10297 ret = get_errno(gettid());
10298 break;
thse5febef2007-04-01 18:31:35 +000010299#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010300 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010301#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010302 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010303 arg2 = arg3;
10304 arg3 = arg4;
10305 arg4 = arg5;
10306 }
aurel322054ac92008-10-13 21:08:07 +000010307 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10308#else
10309 ret = get_errno(readahead(arg1, arg2, arg3));
10310#endif
10311 break;
thse5febef2007-04-01 18:31:35 +000010312#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010313#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010314#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010315 case TARGET_NR_listxattr:
10316 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010317 {
10318 void *p, *b = 0;
10319 if (arg2) {
10320 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10321 if (!b) {
10322 ret = -TARGET_EFAULT;
10323 break;
10324 }
10325 }
10326 p = lock_user_string(arg1);
10327 if (p) {
10328 if (num == TARGET_NR_listxattr) {
10329 ret = get_errno(listxattr(p, b, arg3));
10330 } else {
10331 ret = get_errno(llistxattr(p, b, arg3));
10332 }
10333 } else {
10334 ret = -TARGET_EFAULT;
10335 }
10336 unlock_user(p, arg1, 0);
10337 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010338 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010339 }
10340 case TARGET_NR_flistxattr:
10341 {
10342 void *b = 0;
10343 if (arg2) {
10344 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10345 if (!b) {
10346 ret = -TARGET_EFAULT;
10347 break;
10348 }
10349 }
10350 ret = get_errno(flistxattr(arg1, b, arg3));
10351 unlock_user(b, arg2, arg3);
10352 break;
10353 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010354 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010355 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010356 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010357 void *p, *n, *v = 0;
10358 if (arg3) {
10359 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10360 if (!v) {
10361 ret = -TARGET_EFAULT;
10362 break;
10363 }
10364 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010365 p = lock_user_string(arg1);
10366 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010367 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010368 if (num == TARGET_NR_setxattr) {
10369 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10370 } else {
10371 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10372 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010373 } else {
10374 ret = -TARGET_EFAULT;
10375 }
10376 unlock_user(p, arg1, 0);
10377 unlock_user(n, arg2, 0);
10378 unlock_user(v, arg3, 0);
10379 }
10380 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010381 case TARGET_NR_fsetxattr:
10382 {
10383 void *n, *v = 0;
10384 if (arg3) {
10385 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10386 if (!v) {
10387 ret = -TARGET_EFAULT;
10388 break;
10389 }
10390 }
10391 n = lock_user_string(arg2);
10392 if (n) {
10393 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10394 } else {
10395 ret = -TARGET_EFAULT;
10396 }
10397 unlock_user(n, arg2, 0);
10398 unlock_user(v, arg3, 0);
10399 }
10400 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010401 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010402 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010403 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010404 void *p, *n, *v = 0;
10405 if (arg3) {
10406 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10407 if (!v) {
10408 ret = -TARGET_EFAULT;
10409 break;
10410 }
10411 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010412 p = lock_user_string(arg1);
10413 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010414 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010415 if (num == TARGET_NR_getxattr) {
10416 ret = get_errno(getxattr(p, n, v, arg4));
10417 } else {
10418 ret = get_errno(lgetxattr(p, n, v, arg4));
10419 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010420 } else {
10421 ret = -TARGET_EFAULT;
10422 }
10423 unlock_user(p, arg1, 0);
10424 unlock_user(n, arg2, 0);
10425 unlock_user(v, arg3, arg4);
10426 }
10427 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010428 case TARGET_NR_fgetxattr:
10429 {
10430 void *n, *v = 0;
10431 if (arg3) {
10432 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10433 if (!v) {
10434 ret = -TARGET_EFAULT;
10435 break;
10436 }
10437 }
10438 n = lock_user_string(arg2);
10439 if (n) {
10440 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10441 } else {
10442 ret = -TARGET_EFAULT;
10443 }
10444 unlock_user(n, arg2, 0);
10445 unlock_user(v, arg3, arg4);
10446 }
10447 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010448 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010449 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010450 {
10451 void *p, *n;
10452 p = lock_user_string(arg1);
10453 n = lock_user_string(arg2);
10454 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010455 if (num == TARGET_NR_removexattr) {
10456 ret = get_errno(removexattr(p, n));
10457 } else {
10458 ret = get_errno(lremovexattr(p, n));
10459 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010460 } else {
10461 ret = -TARGET_EFAULT;
10462 }
10463 unlock_user(p, arg1, 0);
10464 unlock_user(n, arg2, 0);
10465 }
10466 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010467 case TARGET_NR_fremovexattr:
10468 {
10469 void *n;
10470 n = lock_user_string(arg2);
10471 if (n) {
10472 ret = get_errno(fremovexattr(arg1, n));
10473 } else {
10474 ret = -TARGET_EFAULT;
10475 }
10476 unlock_user(n, arg2, 0);
10477 }
10478 break;
bellardebc05482003-09-30 21:08:41 +000010479#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010480#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010481#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010482 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010483#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010484 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010485 ret = 0;
10486 break;
edgar_iglef967792009-01-07 14:19:38 +000010487#elif defined(TARGET_CRIS)
10488 if (arg1 & 0xff)
10489 ret = -TARGET_EINVAL;
10490 else {
10491 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10492 ret = 0;
10493 }
10494 break;
bellard8d18e892007-11-14 15:18:40 +000010495#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10496 ret = do_set_thread_area(cpu_env, arg1);
10497 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010498#elif defined(TARGET_M68K)
10499 {
Andreas Färber0429a972013-08-26 18:14:44 +020010500 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010501 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010502 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010503 break;
10504 }
ths6f5b89a2007-03-02 20:48:00 +000010505#else
10506 goto unimplemented_nowarn;
10507#endif
10508#endif
10509#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010510 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010511#if defined(TARGET_I386) && defined(TARGET_ABI32)
10512 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010513 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010514#elif defined(TARGET_M68K)
10515 {
Andreas Färber0429a972013-08-26 18:14:44 +020010516 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010517 ret = ts->tp_value;
10518 break;
10519 }
bellard8d18e892007-11-14 15:18:40 +000010520#else
bellard5cd43932003-03-29 16:54:36 +000010521 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010522#endif
bellard8d18e892007-11-14 15:18:40 +000010523#endif
bellard48dc41e2006-06-21 18:15:50 +000010524#ifdef TARGET_NR_getdomainname
10525 case TARGET_NR_getdomainname:
10526 goto unimplemented_nowarn;
10527#endif
ths6f5b89a2007-03-02 20:48:00 +000010528
thsb5906f92007-03-19 13:32:45 +000010529#ifdef TARGET_NR_clock_gettime
10530 case TARGET_NR_clock_gettime:
10531 {
10532 struct timespec ts;
10533 ret = get_errno(clock_gettime(arg1, &ts));
10534 if (!is_error(ret)) {
10535 host_to_target_timespec(arg2, &ts);
10536 }
10537 break;
10538 }
10539#endif
10540#ifdef TARGET_NR_clock_getres
10541 case TARGET_NR_clock_getres:
10542 {
10543 struct timespec ts;
10544 ret = get_errno(clock_getres(arg1, &ts));
10545 if (!is_error(ret)) {
10546 host_to_target_timespec(arg2, &ts);
10547 }
10548 break;
10549 }
10550#endif
pbrook63d76512008-05-29 13:43:29 +000010551#ifdef TARGET_NR_clock_nanosleep
10552 case TARGET_NR_clock_nanosleep:
10553 {
10554 struct timespec ts;
10555 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010010556 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
10557 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000010558 if (arg4)
10559 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010560
10561#if defined(TARGET_PPC)
10562 /* clock_nanosleep is odd in that it returns positive errno values.
10563 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010010564 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010565 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10566 }
10567#endif
pbrook63d76512008-05-29 13:43:29 +000010568 break;
10569 }
10570#endif
thsb5906f92007-03-19 13:32:45 +000010571
ths6f5b89a2007-03-02 20:48:00 +000010572#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10573 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010574 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10575 break;
ths6f5b89a2007-03-02 20:48:00 +000010576#endif
10577
ths4cae1d12007-07-12 11:06:53 +000010578 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010579 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010580 break;
ths4cae1d12007-07-12 11:06:53 +000010581
ths71455572007-06-21 21:45:30 +000010582 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010583 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000010584 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010010585 break;
ths71455572007-06-21 21:45:30 +000010586
ths4f2b1fe2007-06-21 21:57:12 +000010587#ifdef TARGET_NR_set_robust_list
10588 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010589 case TARGET_NR_get_robust_list:
10590 /* The ABI for supporting robust futexes has userspace pass
10591 * the kernel a pointer to a linked list which is updated by
10592 * userspace after the syscall; the list is walked by the kernel
10593 * when the thread exits. Since the linked list in QEMU guest
10594 * memory isn't a valid linked list for the host and we have
10595 * no way to reliably intercept the thread-death event, we can't
10596 * support these. Silently return ENOSYS so that guest userspace
10597 * falls back to a non-robust futex implementation (which should
10598 * be OK except in the corner case of the guest crashing while
10599 * holding a mutex that is shared with another process via
10600 * shared memory).
10601 */
10602 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010603#endif
10604
Peter Maydell1acae9f2013-07-02 14:04:12 +010010605#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010606 case TARGET_NR_utimensat:
10607 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010608 struct timespec *tsp, ts[2];
10609 if (!arg3) {
10610 tsp = NULL;
10611 } else {
10612 target_to_host_timespec(ts, arg3);
10613 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10614 tsp = ts;
10615 }
ths9007f0e2007-09-25 17:50:37 +000010616 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010617 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010618 else {
bellard579a97f2007-11-11 14:26:47 +000010619 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010620 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010621 goto fail;
10622 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010623 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010624 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010625 }
10626 }
10627 break;
10628#endif
pbrookbd0c5662008-05-29 14:34:11 +000010629 case TARGET_NR_futex:
10630 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10631 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010632#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010633 case TARGET_NR_inotify_init:
10634 ret = get_errno(sys_inotify_init());
10635 break;
10636#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010637#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010638#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10639 case TARGET_NR_inotify_init1:
10640 ret = get_errno(sys_inotify_init1(arg1));
10641 break;
10642#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010643#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010644#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010645 case TARGET_NR_inotify_add_watch:
10646 p = lock_user_string(arg2);
10647 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10648 unlock_user(p, arg2, 0);
10649 break;
10650#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010651#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010652 case TARGET_NR_inotify_rm_watch:
10653 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10654 break;
10655#endif
ths9007f0e2007-09-25 17:50:37 +000010656
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010657#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010658 case TARGET_NR_mq_open:
10659 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010660 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010661
10662 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010663 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010664 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010665 attrp = &posix_mq_attr;
10666 } else {
10667 attrp = 0;
10668 }
10669 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010670 unlock_user (p, arg1, 0);
10671 }
10672 break;
10673
10674 case TARGET_NR_mq_unlink:
10675 p = lock_user_string(arg1 - 1);
10676 ret = get_errno(mq_unlink(p));
10677 unlock_user (p, arg1, 0);
10678 break;
10679
10680 case TARGET_NR_mq_timedsend:
10681 {
10682 struct timespec ts;
10683
10684 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10685 if (arg5 != 0) {
10686 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010687 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000010688 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010689 } else {
10690 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000010691 }
aurel3224e10032009-04-15 16:11:43 +000010692 unlock_user (p, arg2, arg3);
10693 }
10694 break;
10695
10696 case TARGET_NR_mq_timedreceive:
10697 {
10698 struct timespec ts;
10699 unsigned int prio;
10700
10701 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10702 if (arg5 != 0) {
10703 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010704 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10705 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000010706 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010707 } else {
10708 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10709 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000010710 }
aurel3224e10032009-04-15 16:11:43 +000010711 unlock_user (p, arg2, arg3);
10712 if (arg4 != 0)
10713 put_user_u32(prio, arg4);
10714 }
10715 break;
10716
10717 /* Not implemented for now... */
10718/* case TARGET_NR_mq_notify: */
10719/* break; */
10720
10721 case TARGET_NR_mq_getsetattr:
10722 {
10723 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10724 ret = 0;
10725 if (arg3 != 0) {
10726 ret = mq_getattr(arg1, &posix_mq_attr_out);
10727 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10728 }
10729 if (arg2 != 0) {
10730 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10731 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10732 }
10733
10734 }
10735 break;
10736#endif
10737
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010738#ifdef CONFIG_SPLICE
10739#ifdef TARGET_NR_tee
10740 case TARGET_NR_tee:
10741 {
10742 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10743 }
10744 break;
10745#endif
10746#ifdef TARGET_NR_splice
10747 case TARGET_NR_splice:
10748 {
10749 loff_t loff_in, loff_out;
10750 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010751 if (arg2) {
10752 if (get_user_u64(loff_in, arg2)) {
10753 goto efault;
10754 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010755 ploff_in = &loff_in;
10756 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010757 if (arg4) {
10758 if (get_user_u64(loff_out, arg4)) {
10759 goto efault;
10760 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010761 ploff_out = &loff_out;
10762 }
10763 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010764 if (arg2) {
10765 if (put_user_u64(loff_in, arg2)) {
10766 goto efault;
10767 }
10768 }
10769 if (arg4) {
10770 if (put_user_u64(loff_out, arg4)) {
10771 goto efault;
10772 }
10773 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010774 }
10775 break;
10776#endif
10777#ifdef TARGET_NR_vmsplice
10778 case TARGET_NR_vmsplice:
10779 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010780 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10781 if (vec != NULL) {
10782 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10783 unlock_iovec(vec, arg2, arg3, 0);
10784 } else {
10785 ret = -host_to_target_errno(errno);
10786 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010787 }
10788 break;
10789#endif
10790#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010791#ifdef CONFIG_EVENTFD
10792#if defined(TARGET_NR_eventfd)
10793 case TARGET_NR_eventfd:
10794 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010795 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010796 break;
10797#endif
10798#if defined(TARGET_NR_eventfd2)
10799 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010800 {
10801 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10802 if (arg2 & TARGET_O_NONBLOCK) {
10803 host_flags |= O_NONBLOCK;
10804 }
10805 if (arg2 & TARGET_O_CLOEXEC) {
10806 host_flags |= O_CLOEXEC;
10807 }
10808 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010809 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010810 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010811 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010812#endif
10813#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010814#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10815 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010816#if TARGET_ABI_BITS == 32
10817 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10818 target_offset64(arg5, arg6)));
10819#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010820 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010821#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010822 break;
10823#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010824#if defined(CONFIG_SYNC_FILE_RANGE)
10825#if defined(TARGET_NR_sync_file_range)
10826 case TARGET_NR_sync_file_range:
10827#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010828#if defined(TARGET_MIPS)
10829 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10830 target_offset64(arg5, arg6), arg7));
10831#else
Peter Maydellc727f472011-01-06 11:05:10 +000010832 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10833 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010834#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010835#else
10836 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10837#endif
10838 break;
10839#endif
10840#if defined(TARGET_NR_sync_file_range2)
10841 case TARGET_NR_sync_file_range2:
10842 /* This is like sync_file_range but the arguments are reordered */
10843#if TARGET_ABI_BITS == 32
10844 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10845 target_offset64(arg5, arg6), arg2));
10846#else
10847 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10848#endif
10849 break;
10850#endif
10851#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010852#if defined(TARGET_NR_signalfd4)
10853 case TARGET_NR_signalfd4:
10854 ret = do_signalfd4(arg1, arg2, arg4);
10855 break;
10856#endif
10857#if defined(TARGET_NR_signalfd)
10858 case TARGET_NR_signalfd:
10859 ret = do_signalfd4(arg1, arg2, 0);
10860 break;
10861#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010862#if defined(CONFIG_EPOLL)
10863#if defined(TARGET_NR_epoll_create)
10864 case TARGET_NR_epoll_create:
10865 ret = get_errno(epoll_create(arg1));
10866 break;
10867#endif
10868#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10869 case TARGET_NR_epoll_create1:
10870 ret = get_errno(epoll_create1(arg1));
10871 break;
10872#endif
10873#if defined(TARGET_NR_epoll_ctl)
10874 case TARGET_NR_epoll_ctl:
10875 {
10876 struct epoll_event ep;
10877 struct epoll_event *epp = 0;
10878 if (arg4) {
10879 struct target_epoll_event *target_ep;
10880 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10881 goto efault;
10882 }
10883 ep.events = tswap32(target_ep->events);
10884 /* The epoll_data_t union is just opaque data to the kernel,
10885 * so we transfer all 64 bits across and need not worry what
10886 * actual data type it is.
10887 */
10888 ep.data.u64 = tswap64(target_ep->data.u64);
10889 unlock_user_struct(target_ep, arg4, 0);
10890 epp = &ep;
10891 }
10892 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10893 break;
10894 }
10895#endif
10896
Peter Maydell227f0212016-06-06 19:58:11 +010010897#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010898#if defined(TARGET_NR_epoll_wait)
10899 case TARGET_NR_epoll_wait:
10900#endif
Peter Maydell227f0212016-06-06 19:58:11 +010010901#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010902 case TARGET_NR_epoll_pwait:
10903#endif
10904 {
10905 struct target_epoll_event *target_ep;
10906 struct epoll_event *ep;
10907 int epfd = arg1;
10908 int maxevents = arg3;
10909 int timeout = arg4;
10910
10911 target_ep = lock_user(VERIFY_WRITE, arg2,
10912 maxevents * sizeof(struct target_epoll_event), 1);
10913 if (!target_ep) {
10914 goto efault;
10915 }
10916
10917 ep = alloca(maxevents * sizeof(struct epoll_event));
10918
10919 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010010920#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010921 case TARGET_NR_epoll_pwait:
10922 {
10923 target_sigset_t *target_set;
10924 sigset_t _set, *set = &_set;
10925
10926 if (arg5) {
10927 target_set = lock_user(VERIFY_READ, arg5,
10928 sizeof(target_sigset_t), 1);
10929 if (!target_set) {
10930 unlock_user(target_ep, arg2, 0);
10931 goto efault;
10932 }
10933 target_to_host_sigset(set, target_set);
10934 unlock_user(target_set, arg5, 0);
10935 } else {
10936 set = NULL;
10937 }
10938
Peter Maydell227f0212016-06-06 19:58:11 +010010939 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10940 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010941 break;
10942 }
10943#endif
10944#if defined(TARGET_NR_epoll_wait)
10945 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010010946 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10947 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010948 break;
10949#endif
10950 default:
10951 ret = -TARGET_ENOSYS;
10952 }
10953 if (!is_error(ret)) {
10954 int i;
10955 for (i = 0; i < ret; i++) {
10956 target_ep[i].events = tswap32(ep[i].events);
10957 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10958 }
10959 }
10960 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10961 break;
10962 }
10963#endif
10964#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010965#ifdef TARGET_NR_prlimit64
10966 case TARGET_NR_prlimit64:
10967 {
10968 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10969 struct target_rlimit64 *target_rnew, *target_rold;
10970 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010971 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010972 if (arg3) {
10973 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10974 goto efault;
10975 }
10976 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10977 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10978 unlock_user_struct(target_rnew, arg3, 0);
10979 rnewp = &rnew;
10980 }
10981
Felix Janda95018012014-12-02 22:11:17 +010010982 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010983 if (!is_error(ret) && arg4) {
10984 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10985 goto efault;
10986 }
10987 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10988 target_rold->rlim_max = tswap64(rold.rlim_max);
10989 unlock_user_struct(target_rold, arg4, 1);
10990 }
10991 break;
10992 }
10993#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010994#ifdef TARGET_NR_gethostname
10995 case TARGET_NR_gethostname:
10996 {
10997 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10998 if (name) {
10999 ret = get_errno(gethostname(name, arg2));
11000 unlock_user(name, arg1, arg2);
11001 } else {
11002 ret = -TARGET_EFAULT;
11003 }
11004 break;
11005 }
11006#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011007#ifdef TARGET_NR_atomic_cmpxchg_32
11008 case TARGET_NR_atomic_cmpxchg_32:
11009 {
11010 /* should use start_exclusive from main.c */
11011 abi_ulong mem_value;
11012 if (get_user_u32(mem_value, arg6)) {
11013 target_siginfo_t info;
11014 info.si_signo = SIGSEGV;
11015 info.si_errno = 0;
11016 info.si_code = TARGET_SEGV_MAPERR;
11017 info._sifields._sigfault._addr = arg6;
11018 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11019 ret = 0xdeadbeef;
11020
11021 }
11022 if (mem_value == arg2)
11023 put_user_u32(arg1, arg6);
11024 ret = mem_value;
11025 break;
11026 }
11027#endif
11028#ifdef TARGET_NR_atomic_barrier
11029 case TARGET_NR_atomic_barrier:
11030 {
11031 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011032 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011033 break;
11034 }
11035#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011036
11037#ifdef TARGET_NR_timer_create
11038 case TARGET_NR_timer_create:
11039 {
11040 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11041
11042 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011043
11044 int clkid = arg1;
11045 int timer_index = next_free_host_timer();
11046
11047 if (timer_index < 0) {
11048 ret = -TARGET_EAGAIN;
11049 } else {
11050 timer_t *phtimer = g_posix_timers + timer_index;
11051
11052 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011053 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011054 ret = target_to_host_sigevent(phost_sevp, arg2);
11055 if (ret != 0) {
11056 break;
11057 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011058 }
11059
11060 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11061 if (ret) {
11062 phtimer = NULL;
11063 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011064 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011065 goto efault;
11066 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011067 }
11068 }
11069 break;
11070 }
11071#endif
11072
11073#ifdef TARGET_NR_timer_settime
11074 case TARGET_NR_timer_settime:
11075 {
11076 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11077 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011078 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011079
Alexander Grafaecc8862014-11-10 21:33:03 +010011080 if (timerid < 0) {
11081 ret = timerid;
11082 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011083 ret = -TARGET_EINVAL;
11084 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011085 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011086 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11087
11088 target_to_host_itimerspec(&hspec_new, arg3);
11089 ret = get_errno(
11090 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11091 host_to_target_itimerspec(arg2, &hspec_old);
11092 }
11093 break;
11094 }
11095#endif
11096
11097#ifdef TARGET_NR_timer_gettime
11098 case TARGET_NR_timer_gettime:
11099 {
11100 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011101 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011102
Alexander Grafaecc8862014-11-10 21:33:03 +010011103 if (timerid < 0) {
11104 ret = timerid;
11105 } else if (!arg2) {
11106 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011107 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011108 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011109 struct itimerspec hspec;
11110 ret = get_errno(timer_gettime(htimer, &hspec));
11111
11112 if (host_to_target_itimerspec(arg2, &hspec)) {
11113 ret = -TARGET_EFAULT;
11114 }
11115 }
11116 break;
11117 }
11118#endif
11119
11120#ifdef TARGET_NR_timer_getoverrun
11121 case TARGET_NR_timer_getoverrun:
11122 {
11123 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011124 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011125
Alexander Grafaecc8862014-11-10 21:33:03 +010011126 if (timerid < 0) {
11127 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011128 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011129 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011130 ret = get_errno(timer_getoverrun(htimer));
11131 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011132 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011133 break;
11134 }
11135#endif
11136
11137#ifdef TARGET_NR_timer_delete
11138 case TARGET_NR_timer_delete:
11139 {
11140 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011141 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011142
Alexander Grafaecc8862014-11-10 21:33:03 +010011143 if (timerid < 0) {
11144 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011145 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011146 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011147 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011148 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011149 }
11150 break;
11151 }
11152#endif
11153
Riku Voipio51834342014-06-22 11:25:42 +010011154#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11155 case TARGET_NR_timerfd_create:
11156 ret = get_errno(timerfd_create(arg1,
11157 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11158 break;
11159#endif
11160
11161#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11162 case TARGET_NR_timerfd_gettime:
11163 {
11164 struct itimerspec its_curr;
11165
11166 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11167
11168 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11169 goto efault;
11170 }
11171 }
11172 break;
11173#endif
11174
11175#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11176 case TARGET_NR_timerfd_settime:
11177 {
11178 struct itimerspec its_new, its_old, *p_new;
11179
11180 if (arg3) {
11181 if (target_to_host_itimerspec(&its_new, arg3)) {
11182 goto efault;
11183 }
11184 p_new = &its_new;
11185 } else {
11186 p_new = NULL;
11187 }
11188
11189 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11190
11191 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11192 goto efault;
11193 }
11194 }
11195 break;
11196#endif
11197
Paul Burtonab31cda2014-06-22 11:25:43 +010011198#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11199 case TARGET_NR_ioprio_get:
11200 ret = get_errno(ioprio_get(arg1, arg2));
11201 break;
11202#endif
11203
11204#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11205 case TARGET_NR_ioprio_set:
11206 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11207 break;
11208#endif
11209
Riku Voipio9af5c902014-08-12 15:58:57 +030011210#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11211 case TARGET_NR_setns:
11212 ret = get_errno(setns(arg1, arg2));
11213 break;
11214#endif
11215#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11216 case TARGET_NR_unshare:
11217 ret = get_errno(unshare(arg1));
11218 break;
11219#endif
11220
bellard31e31b82003-02-18 22:55:36 +000011221 default:
11222 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011223 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011224#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 +000011225 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011226#endif
ths0da46a62007-10-20 20:23:07 +000011227 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011228 break;
11229 }
bellard579a97f2007-11-11 14:26:47 +000011230fail:
bellardc573ff62004-01-04 15:51:36 +000011231#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011232 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011233#endif
thsb92c47c2007-11-01 00:07:38 +000011234 if(do_strace)
11235 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000011236 return ret;
bellard579a97f2007-11-11 14:26:47 +000011237efault:
11238 ret = -TARGET_EFAULT;
11239 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011240}