blob: 59defff01f602584894b4d541d08d1646b62362e [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:
Laurent Vivierb9403972016-06-16 21:01:37 +02001951 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
1952 ifi = NLMSG_DATA(nlh);
1953 ifi->ifi_type = tswap16(ifi->ifi_type);
1954 ifi->ifi_index = tswap32(ifi->ifi_index);
1955 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1956 ifi->ifi_change = tswap32(ifi->ifi_change);
1957 host_to_target_link_rtattr(IFLA_RTA(ifi),
1958 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1959 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001960 break;
1961 case RTM_NEWADDR:
1962 case RTM_DELADDR:
1963 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02001964 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
1965 ifa = NLMSG_DATA(nlh);
1966 ifa->ifa_index = tswap32(ifa->ifa_index);
1967 host_to_target_addr_rtattr(IFA_RTA(ifa),
1968 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1969 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001970 break;
1971 case RTM_NEWROUTE:
1972 case RTM_DELROUTE:
1973 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02001974 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
1975 rtm = NLMSG_DATA(nlh);
1976 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1977 host_to_target_route_rtattr(RTM_RTA(rtm),
1978 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1979 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001980 break;
1981 default:
1982 return -TARGET_EINVAL;
1983 }
1984 return 0;
1985}
1986
1987static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1988 size_t len)
1989{
1990 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1991}
1992
1993static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1994 size_t len,
1995 abi_long (*target_to_host_rtattr)
1996 (struct rtattr *))
1997{
1998 abi_long ret;
1999
2000 while (len >= sizeof(struct rtattr)) {
2001 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2002 tswap16(rtattr->rta_len) > len) {
2003 break;
2004 }
2005 rtattr->rta_len = tswap16(rtattr->rta_len);
2006 rtattr->rta_type = tswap16(rtattr->rta_type);
2007 ret = target_to_host_rtattr(rtattr);
2008 if (ret < 0) {
2009 return ret;
2010 }
2011 len -= RTA_ALIGN(rtattr->rta_len);
2012 rtattr = (struct rtattr *)(((char *)rtattr) +
2013 RTA_ALIGN(rtattr->rta_len));
2014 }
2015 return 0;
2016}
2017
2018static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2019{
2020 switch (rtattr->rta_type) {
2021 default:
2022 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
2023 break;
2024 }
2025 return 0;
2026}
2027
2028static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2029{
2030 switch (rtattr->rta_type) {
2031 /* binary: depends on family type */
2032 case IFA_LOCAL:
2033 case IFA_ADDRESS:
2034 break;
2035 default:
2036 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2037 break;
2038 }
2039 return 0;
2040}
2041
2042static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2043{
2044 uint32_t *u32;
2045 switch (rtattr->rta_type) {
2046 /* binary: depends on family type */
2047 case RTA_DST:
2048 case RTA_SRC:
2049 case RTA_GATEWAY:
2050 break;
2051 /* u32 */
2052 case RTA_OIF:
2053 u32 = RTA_DATA(rtattr);
2054 *u32 = tswap32(*u32);
2055 break;
2056 default:
2057 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2058 break;
2059 }
2060 return 0;
2061}
2062
2063static void target_to_host_link_rtattr(struct rtattr *rtattr,
2064 uint32_t rtattr_len)
2065{
2066 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2067 target_to_host_data_link_rtattr);
2068}
2069
2070static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2071 uint32_t rtattr_len)
2072{
2073 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2074 target_to_host_data_addr_rtattr);
2075}
2076
2077static void target_to_host_route_rtattr(struct rtattr *rtattr,
2078 uint32_t rtattr_len)
2079{
2080 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2081 target_to_host_data_route_rtattr);
2082}
2083
2084static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2085{
2086 struct ifinfomsg *ifi;
2087 struct ifaddrmsg *ifa;
2088 struct rtmsg *rtm;
2089
2090 switch (nlh->nlmsg_type) {
2091 case RTM_GETLINK:
2092 break;
2093 case RTM_NEWLINK:
2094 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002095 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2096 ifi = NLMSG_DATA(nlh);
2097 ifi->ifi_type = tswap16(ifi->ifi_type);
2098 ifi->ifi_index = tswap32(ifi->ifi_index);
2099 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2100 ifi->ifi_change = tswap32(ifi->ifi_change);
2101 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2102 NLMSG_LENGTH(sizeof(*ifi)));
2103 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002104 break;
2105 case RTM_GETADDR:
2106 case RTM_NEWADDR:
2107 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002108 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2109 ifa = NLMSG_DATA(nlh);
2110 ifa->ifa_index = tswap32(ifa->ifa_index);
2111 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2112 NLMSG_LENGTH(sizeof(*ifa)));
2113 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002114 break;
2115 case RTM_GETROUTE:
2116 break;
2117 case RTM_NEWROUTE:
2118 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002119 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2120 rtm = NLMSG_DATA(nlh);
2121 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2122 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2123 NLMSG_LENGTH(sizeof(*rtm)));
2124 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002125 break;
2126 default:
2127 return -TARGET_EOPNOTSUPP;
2128 }
2129 return 0;
2130}
2131
2132static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2133{
2134 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2135}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002136#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002137
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002138static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2139{
2140 switch (nlh->nlmsg_type) {
2141 default:
2142 gemu_log("Unknown host audit message type %d\n",
2143 nlh->nlmsg_type);
2144 return -TARGET_EINVAL;
2145 }
2146 return 0;
2147}
2148
2149static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2150 size_t len)
2151{
2152 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2153}
2154
2155static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2156{
2157 switch (nlh->nlmsg_type) {
2158 case AUDIT_USER:
2159 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2160 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2161 break;
2162 default:
2163 gemu_log("Unknown target audit message type %d\n",
2164 nlh->nlmsg_type);
2165 return -TARGET_EINVAL;
2166 }
2167
2168 return 0;
2169}
2170
2171static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2172{
2173 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2174}
2175
ths0da46a62007-10-20 20:23:07 +00002176/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002177static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002178 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002179{
blueswir1992f48a2007-10-14 16:27:31 +00002180 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002181 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002182 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002183 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002184
bellard8853f862004-02-22 14:57:26 +00002185 switch(level) {
2186 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002187 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002188 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002189 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002190
bellard2f619692007-11-16 10:46:05 +00002191 if (get_user_u32(val, optval_addr))
2192 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002193 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2194 break;
2195 case SOL_IP:
2196 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002197 case IP_TOS:
2198 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002199 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002200 case IP_ROUTER_ALERT:
2201 case IP_RECVOPTS:
2202 case IP_RETOPTS:
2203 case IP_PKTINFO:
2204 case IP_MTU_DISCOVER:
2205 case IP_RECVERR:
2206 case IP_RECVTOS:
2207#ifdef IP_FREEBIND
2208 case IP_FREEBIND:
2209#endif
2210 case IP_MULTICAST_TTL:
2211 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002212 val = 0;
2213 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002214 if (get_user_u32(val, optval_addr))
2215 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002216 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002217 if (get_user_u8(val, optval_addr))
2218 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002219 }
2220 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2221 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002222 case IP_ADD_MEMBERSHIP:
2223 case IP_DROP_MEMBERSHIP:
2224 if (optlen < sizeof (struct target_ip_mreq) ||
2225 optlen > sizeof (struct target_ip_mreqn))
2226 return -TARGET_EINVAL;
2227
2228 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2229 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2230 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2231 break;
2232
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002233 case IP_BLOCK_SOURCE:
2234 case IP_UNBLOCK_SOURCE:
2235 case IP_ADD_SOURCE_MEMBERSHIP:
2236 case IP_DROP_SOURCE_MEMBERSHIP:
2237 if (optlen != sizeof (struct target_ip_mreq_source))
2238 return -TARGET_EINVAL;
2239
2240 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2241 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2242 unlock_user (ip_mreq_source, optval_addr, 0);
2243 break;
2244
bellard8853f862004-02-22 14:57:26 +00002245 default:
2246 goto unimplemented;
2247 }
2248 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002249 case SOL_IPV6:
2250 switch (optname) {
2251 case IPV6_MTU_DISCOVER:
2252 case IPV6_MTU:
2253 case IPV6_V6ONLY:
2254 case IPV6_RECVPKTINFO:
2255 val = 0;
2256 if (optlen < sizeof(uint32_t)) {
2257 return -TARGET_EINVAL;
2258 }
2259 if (get_user_u32(val, optval_addr)) {
2260 return -TARGET_EFAULT;
2261 }
2262 ret = get_errno(setsockopt(sockfd, level, optname,
2263 &val, sizeof(val)));
2264 break;
2265 default:
2266 goto unimplemented;
2267 }
2268 break;
Jing Huang920394d2012-07-24 13:59:23 +00002269 case SOL_RAW:
2270 switch (optname) {
2271 case ICMP_FILTER:
2272 /* struct icmp_filter takes an u32 value */
2273 if (optlen < sizeof(uint32_t)) {
2274 return -TARGET_EINVAL;
2275 }
2276
2277 if (get_user_u32(val, optval_addr)) {
2278 return -TARGET_EFAULT;
2279 }
2280 ret = get_errno(setsockopt(sockfd, level, optname,
2281 &val, sizeof(val)));
2282 break;
2283
2284 default:
2285 goto unimplemented;
2286 }
2287 break;
bellard3532fa72006-06-24 15:06:03 +00002288 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002289 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002290 case TARGET_SO_RCVTIMEO:
2291 {
2292 struct timeval tv;
2293
2294 optname = SO_RCVTIMEO;
2295
2296set_timeout:
2297 if (optlen != sizeof(struct target_timeval)) {
2298 return -TARGET_EINVAL;
2299 }
2300
2301 if (copy_from_user_timeval(&tv, optval_addr)) {
2302 return -TARGET_EFAULT;
2303 }
2304
2305 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2306 &tv, sizeof(tv)));
2307 return ret;
2308 }
2309 case TARGET_SO_SNDTIMEO:
2310 optname = SO_SNDTIMEO;
2311 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002312 case TARGET_SO_ATTACH_FILTER:
2313 {
2314 struct target_sock_fprog *tfprog;
2315 struct target_sock_filter *tfilter;
2316 struct sock_fprog fprog;
2317 struct sock_filter *filter;
2318 int i;
2319
2320 if (optlen != sizeof(*tfprog)) {
2321 return -TARGET_EINVAL;
2322 }
2323 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2324 return -TARGET_EFAULT;
2325 }
2326 if (!lock_user_struct(VERIFY_READ, tfilter,
2327 tswapal(tfprog->filter), 0)) {
2328 unlock_user_struct(tfprog, optval_addr, 1);
2329 return -TARGET_EFAULT;
2330 }
2331
2332 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302333 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002334 if (filter == NULL) {
2335 unlock_user_struct(tfilter, tfprog->filter, 1);
2336 unlock_user_struct(tfprog, optval_addr, 1);
2337 return -TARGET_ENOMEM;
2338 }
2339 for (i = 0; i < fprog.len; i++) {
2340 filter[i].code = tswap16(tfilter[i].code);
2341 filter[i].jt = tfilter[i].jt;
2342 filter[i].jf = tfilter[i].jf;
2343 filter[i].k = tswap32(tfilter[i].k);
2344 }
2345 fprog.filter = filter;
2346
2347 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2348 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302349 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002350
2351 unlock_user_struct(tfilter, tfprog->filter, 1);
2352 unlock_user_struct(tfprog, optval_addr, 1);
2353 return ret;
2354 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002355 case TARGET_SO_BINDTODEVICE:
2356 {
2357 char *dev_ifname, *addr_ifname;
2358
2359 if (optlen > IFNAMSIZ - 1) {
2360 optlen = IFNAMSIZ - 1;
2361 }
2362 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2363 if (!dev_ifname) {
2364 return -TARGET_EFAULT;
2365 }
2366 optname = SO_BINDTODEVICE;
2367 addr_ifname = alloca(IFNAMSIZ);
2368 memcpy(addr_ifname, dev_ifname, optlen);
2369 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002370 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2371 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002372 unlock_user (dev_ifname, optval_addr, 0);
2373 return ret;
2374 }
bellard8853f862004-02-22 14:57:26 +00002375 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002376 case TARGET_SO_DEBUG:
2377 optname = SO_DEBUG;
2378 break;
2379 case TARGET_SO_REUSEADDR:
2380 optname = SO_REUSEADDR;
2381 break;
2382 case TARGET_SO_TYPE:
2383 optname = SO_TYPE;
2384 break;
2385 case TARGET_SO_ERROR:
2386 optname = SO_ERROR;
2387 break;
2388 case TARGET_SO_DONTROUTE:
2389 optname = SO_DONTROUTE;
2390 break;
2391 case TARGET_SO_BROADCAST:
2392 optname = SO_BROADCAST;
2393 break;
2394 case TARGET_SO_SNDBUF:
2395 optname = SO_SNDBUF;
2396 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002397 case TARGET_SO_SNDBUFFORCE:
2398 optname = SO_SNDBUFFORCE;
2399 break;
bellard3532fa72006-06-24 15:06:03 +00002400 case TARGET_SO_RCVBUF:
2401 optname = SO_RCVBUF;
2402 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002403 case TARGET_SO_RCVBUFFORCE:
2404 optname = SO_RCVBUFFORCE;
2405 break;
bellard3532fa72006-06-24 15:06:03 +00002406 case TARGET_SO_KEEPALIVE:
2407 optname = SO_KEEPALIVE;
2408 break;
2409 case TARGET_SO_OOBINLINE:
2410 optname = SO_OOBINLINE;
2411 break;
2412 case TARGET_SO_NO_CHECK:
2413 optname = SO_NO_CHECK;
2414 break;
2415 case TARGET_SO_PRIORITY:
2416 optname = SO_PRIORITY;
2417 break;
bellard5e83e8e2005-03-01 22:32:06 +00002418#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002419 case TARGET_SO_BSDCOMPAT:
2420 optname = SO_BSDCOMPAT;
2421 break;
bellard5e83e8e2005-03-01 22:32:06 +00002422#endif
bellard3532fa72006-06-24 15:06:03 +00002423 case TARGET_SO_PASSCRED:
2424 optname = SO_PASSCRED;
2425 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002426 case TARGET_SO_PASSSEC:
2427 optname = SO_PASSSEC;
2428 break;
bellard3532fa72006-06-24 15:06:03 +00002429 case TARGET_SO_TIMESTAMP:
2430 optname = SO_TIMESTAMP;
2431 break;
2432 case TARGET_SO_RCVLOWAT:
2433 optname = SO_RCVLOWAT;
2434 break;
bellard8853f862004-02-22 14:57:26 +00002435 break;
2436 default:
2437 goto unimplemented;
2438 }
bellard3532fa72006-06-24 15:06:03 +00002439 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002440 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002441
bellard2f619692007-11-16 10:46:05 +00002442 if (get_user_u32(val, optval_addr))
2443 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002444 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002445 break;
bellard7854b052003-03-29 17:22:23 +00002446 default:
bellard8853f862004-02-22 14:57:26 +00002447 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002448 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002449 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002450 }
bellard8853f862004-02-22 14:57:26 +00002451 return ret;
bellard7854b052003-03-29 17:22:23 +00002452}
2453
ths0da46a62007-10-20 20:23:07 +00002454/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002455static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002456 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002457{
blueswir1992f48a2007-10-14 16:27:31 +00002458 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002459 int len, val;
2460 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002461
2462 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002463 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002464 level = SOL_SOCKET;
2465 switch (optname) {
2466 /* These don't just return a single integer */
2467 case TARGET_SO_LINGER:
2468 case TARGET_SO_RCVTIMEO:
2469 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002470 case TARGET_SO_PEERNAME:
2471 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002472 case TARGET_SO_PEERCRED: {
2473 struct ucred cr;
2474 socklen_t crlen;
2475 struct target_ucred *tcr;
2476
2477 if (get_user_u32(len, optlen)) {
2478 return -TARGET_EFAULT;
2479 }
2480 if (len < 0) {
2481 return -TARGET_EINVAL;
2482 }
2483
2484 crlen = sizeof(cr);
2485 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2486 &cr, &crlen));
2487 if (ret < 0) {
2488 return ret;
2489 }
2490 if (len > crlen) {
2491 len = crlen;
2492 }
2493 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2494 return -TARGET_EFAULT;
2495 }
2496 __put_user(cr.pid, &tcr->pid);
2497 __put_user(cr.uid, &tcr->uid);
2498 __put_user(cr.gid, &tcr->gid);
2499 unlock_user_struct(tcr, optval_addr, 1);
2500 if (put_user_u32(len, optlen)) {
2501 return -TARGET_EFAULT;
2502 }
2503 break;
2504 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002505 /* Options with 'int' argument. */
2506 case TARGET_SO_DEBUG:
2507 optname = SO_DEBUG;
2508 goto int_case;
2509 case TARGET_SO_REUSEADDR:
2510 optname = SO_REUSEADDR;
2511 goto int_case;
2512 case TARGET_SO_TYPE:
2513 optname = SO_TYPE;
2514 goto int_case;
2515 case TARGET_SO_ERROR:
2516 optname = SO_ERROR;
2517 goto int_case;
2518 case TARGET_SO_DONTROUTE:
2519 optname = SO_DONTROUTE;
2520 goto int_case;
2521 case TARGET_SO_BROADCAST:
2522 optname = SO_BROADCAST;
2523 goto int_case;
2524 case TARGET_SO_SNDBUF:
2525 optname = SO_SNDBUF;
2526 goto int_case;
2527 case TARGET_SO_RCVBUF:
2528 optname = SO_RCVBUF;
2529 goto int_case;
2530 case TARGET_SO_KEEPALIVE:
2531 optname = SO_KEEPALIVE;
2532 goto int_case;
2533 case TARGET_SO_OOBINLINE:
2534 optname = SO_OOBINLINE;
2535 goto int_case;
2536 case TARGET_SO_NO_CHECK:
2537 optname = SO_NO_CHECK;
2538 goto int_case;
2539 case TARGET_SO_PRIORITY:
2540 optname = SO_PRIORITY;
2541 goto int_case;
2542#ifdef SO_BSDCOMPAT
2543 case TARGET_SO_BSDCOMPAT:
2544 optname = SO_BSDCOMPAT;
2545 goto int_case;
2546#endif
2547 case TARGET_SO_PASSCRED:
2548 optname = SO_PASSCRED;
2549 goto int_case;
2550 case TARGET_SO_TIMESTAMP:
2551 optname = SO_TIMESTAMP;
2552 goto int_case;
2553 case TARGET_SO_RCVLOWAT:
2554 optname = SO_RCVLOWAT;
2555 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002556 case TARGET_SO_ACCEPTCONN:
2557 optname = SO_ACCEPTCONN;
2558 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002559 default:
bellard2efbe912005-07-23 15:10:20 +00002560 goto int_case;
2561 }
2562 break;
2563 case SOL_TCP:
2564 /* TCP options all take an 'int' value. */
2565 int_case:
bellard2f619692007-11-16 10:46:05 +00002566 if (get_user_u32(len, optlen))
2567 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002568 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002569 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002570 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002571 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2572 if (ret < 0)
2573 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002574 if (optname == SO_TYPE) {
2575 val = host_to_target_sock_type(val);
2576 }
bellard2efbe912005-07-23 15:10:20 +00002577 if (len > lv)
2578 len = lv;
bellard2f619692007-11-16 10:46:05 +00002579 if (len == 4) {
2580 if (put_user_u32(val, optval_addr))
2581 return -TARGET_EFAULT;
2582 } else {
2583 if (put_user_u8(val, optval_addr))
2584 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002585 }
bellard2f619692007-11-16 10:46:05 +00002586 if (put_user_u32(len, optlen))
2587 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002588 break;
2589 case SOL_IP:
2590 switch(optname) {
2591 case IP_TOS:
2592 case IP_TTL:
2593 case IP_HDRINCL:
2594 case IP_ROUTER_ALERT:
2595 case IP_RECVOPTS:
2596 case IP_RETOPTS:
2597 case IP_PKTINFO:
2598 case IP_MTU_DISCOVER:
2599 case IP_RECVERR:
2600 case IP_RECVTOS:
2601#ifdef IP_FREEBIND
2602 case IP_FREEBIND:
2603#endif
2604 case IP_MULTICAST_TTL:
2605 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002606 if (get_user_u32(len, optlen))
2607 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002608 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002609 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002610 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002611 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2612 if (ret < 0)
2613 return ret;
bellard2efbe912005-07-23 15:10:20 +00002614 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002615 len = 1;
bellard2f619692007-11-16 10:46:05 +00002616 if (put_user_u32(len, optlen)
2617 || put_user_u8(val, optval_addr))
2618 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002619 } else {
bellard2efbe912005-07-23 15:10:20 +00002620 if (len > sizeof(int))
2621 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002622 if (put_user_u32(len, optlen)
2623 || put_user_u32(val, optval_addr))
2624 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002625 }
bellard8853f862004-02-22 14:57:26 +00002626 break;
bellard2efbe912005-07-23 15:10:20 +00002627 default:
thsc02f4992007-12-18 02:39:59 +00002628 ret = -TARGET_ENOPROTOOPT;
2629 break;
bellard8853f862004-02-22 14:57:26 +00002630 }
2631 break;
2632 default:
2633 unimplemented:
2634 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2635 level, optname);
thsc02f4992007-12-18 02:39:59 +00002636 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002637 break;
2638 }
2639 return ret;
bellard7854b052003-03-29 17:22:23 +00002640}
2641
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002642static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2643 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002644{
2645 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002646 struct iovec *vec;
2647 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002648 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002649 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002650 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002651
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002652 if (count == 0) {
2653 errno = 0;
2654 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002655 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002656 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002657 errno = EINVAL;
2658 return NULL;
2659 }
2660
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302661 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002662 if (vec == NULL) {
2663 errno = ENOMEM;
2664 return NULL;
2665 }
2666
2667 target_vec = lock_user(VERIFY_READ, target_addr,
2668 count * sizeof(struct target_iovec), 1);
2669 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002670 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002671 goto fail2;
2672 }
2673
2674 /* ??? If host page size > target page size, this will result in a
2675 value larger than what we can actually support. */
2676 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2677 total_len = 0;
2678
2679 for (i = 0; i < count; i++) {
2680 abi_ulong base = tswapal(target_vec[i].iov_base);
2681 abi_long len = tswapal(target_vec[i].iov_len);
2682
2683 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002684 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002685 goto fail;
2686 } else if (len == 0) {
2687 /* Zero length pointer is ignored. */
2688 vec[i].iov_base = 0;
2689 } else {
2690 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002691 /* If the first buffer pointer is bad, this is a fault. But
2692 * subsequent bad buffers will result in a partial write; this
2693 * is realized by filling the vector with null pointers and
2694 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002695 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002696 if (i == 0) {
2697 err = EFAULT;
2698 goto fail;
2699 } else {
2700 bad_address = true;
2701 }
2702 }
2703 if (bad_address) {
2704 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002705 }
2706 if (len > max_len - total_len) {
2707 len = max_len - total_len;
2708 }
2709 }
2710 vec[i].iov_len = len;
2711 total_len += len;
2712 }
2713
2714 unlock_user(target_vec, target_addr, 0);
2715 return vec;
2716
2717 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002718 while (--i >= 0) {
2719 if (tswapal(target_vec[i].iov_len) > 0) {
2720 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2721 }
2722 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002723 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002724 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302725 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002726 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002727 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002728}
2729
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002730static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2731 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002732{
2733 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002734 int i;
2735
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002736 target_vec = lock_user(VERIFY_READ, target_addr,
2737 count * sizeof(struct target_iovec), 1);
2738 if (target_vec) {
2739 for (i = 0; i < count; i++) {
2740 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002741 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002742 if (len < 0) {
2743 break;
2744 }
balrogd732dcb2008-10-28 10:21:03 +00002745 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2746 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002747 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002748 }
bellard579a97f2007-11-11 14:26:47 +00002749
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302750 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002751}
2752
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002753static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002754{
2755 int host_type = 0;
2756 int target_type = *type;
2757
2758 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2759 case TARGET_SOCK_DGRAM:
2760 host_type = SOCK_DGRAM;
2761 break;
2762 case TARGET_SOCK_STREAM:
2763 host_type = SOCK_STREAM;
2764 break;
2765 default:
2766 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2767 break;
2768 }
2769 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002770#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002771 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002772#else
2773 return -TARGET_EINVAL;
2774#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002775 }
2776 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002777#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002778 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002779#elif !defined(O_NONBLOCK)
2780 return -TARGET_EINVAL;
2781#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002782 }
2783 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002784 return 0;
2785}
2786
2787/* Try to emulate socket type flags after socket creation. */
2788static int sock_flags_fixup(int fd, int target_type)
2789{
2790#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2791 if (target_type & TARGET_SOCK_NONBLOCK) {
2792 int flags = fcntl(fd, F_GETFL);
2793 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2794 close(fd);
2795 return -TARGET_EINVAL;
2796 }
2797 }
2798#endif
2799 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002800}
2801
Laurent Vivier0cf22722015-10-28 21:40:45 +01002802static abi_long packet_target_to_host_sockaddr(void *host_addr,
2803 abi_ulong target_addr,
2804 socklen_t len)
2805{
2806 struct sockaddr *addr = host_addr;
2807 struct target_sockaddr *target_saddr;
2808
2809 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2810 if (!target_saddr) {
2811 return -TARGET_EFAULT;
2812 }
2813
2814 memcpy(addr, target_saddr, len);
2815 addr->sa_family = tswap16(target_saddr->sa_family);
2816 /* spkt_protocol is big-endian */
2817
2818 unlock_user(target_saddr, target_addr, 0);
2819 return 0;
2820}
2821
2822static TargetFdTrans target_packet_trans = {
2823 .target_to_host_addr = packet_target_to_host_sockaddr,
2824};
2825
Laurent Vivier575b22b2016-06-02 22:14:15 +02002826#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002827static abi_long netlink_route_target_to_host(void *buf, size_t len)
2828{
Laurent Vivieref759f62016-06-21 19:51:13 +02002829 abi_long ret;
2830
2831 ret = target_to_host_nlmsg_route(buf, len);
2832 if (ret < 0) {
2833 return ret;
2834 }
2835
2836 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002837}
2838
2839static abi_long netlink_route_host_to_target(void *buf, size_t len)
2840{
Laurent Vivieref759f62016-06-21 19:51:13 +02002841 abi_long ret;
2842
2843 ret = host_to_target_nlmsg_route(buf, len);
2844 if (ret < 0) {
2845 return ret;
2846 }
2847
2848 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002849}
2850
2851static TargetFdTrans target_netlink_route_trans = {
2852 .target_to_host_data = netlink_route_target_to_host,
2853 .host_to_target_data = netlink_route_host_to_target,
2854};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002855#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002856
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002857static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2858{
Laurent Vivieref759f62016-06-21 19:51:13 +02002859 abi_long ret;
2860
2861 ret = target_to_host_nlmsg_audit(buf, len);
2862 if (ret < 0) {
2863 return ret;
2864 }
2865
2866 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002867}
2868
2869static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2870{
Laurent Vivieref759f62016-06-21 19:51:13 +02002871 abi_long ret;
2872
2873 ret = host_to_target_nlmsg_audit(buf, len);
2874 if (ret < 0) {
2875 return ret;
2876 }
2877
2878 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002879}
2880
2881static TargetFdTrans target_netlink_audit_trans = {
2882 .target_to_host_data = netlink_audit_target_to_host,
2883 .host_to_target_data = netlink_audit_host_to_target,
2884};
2885
ths0da46a62007-10-20 20:23:07 +00002886/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002887static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002888{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002889 int target_type = type;
2890 int ret;
2891
2892 ret = target_to_host_sock_type(&type);
2893 if (ret) {
2894 return ret;
2895 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002896
Laurent Vivier575b22b2016-06-02 22:14:15 +02002897 if (domain == PF_NETLINK && !(
2898#ifdef CONFIG_RTNETLINK
2899 protocol == NETLINK_ROUTE ||
2900#endif
2901 protocol == NETLINK_KOBJECT_UEVENT ||
2902 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002903 return -EPFNOSUPPORT;
2904 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002905
2906 if (domain == AF_PACKET ||
2907 (domain == AF_INET && type == SOCK_PACKET)) {
2908 protocol = tswap16(protocol);
2909 }
2910
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002911 ret = get_errno(socket(domain, type, protocol));
2912 if (ret >= 0) {
2913 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002914 if (type == SOCK_PACKET) {
2915 /* Manage an obsolete case :
2916 * if socket type is SOCK_PACKET, bind by name
2917 */
2918 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002919 } else if (domain == PF_NETLINK) {
2920 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002921#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002922 case NETLINK_ROUTE:
2923 fd_trans_register(ret, &target_netlink_route_trans);
2924 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002925#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002926 case NETLINK_KOBJECT_UEVENT:
2927 /* nothing to do: messages are strings */
2928 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002929 case NETLINK_AUDIT:
2930 fd_trans_register(ret, &target_netlink_audit_trans);
2931 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002932 default:
2933 g_assert_not_reached();
2934 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002935 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002936 }
2937 return ret;
bellard3532fa72006-06-24 15:06:03 +00002938}
2939
ths0da46a62007-10-20 20:23:07 +00002940/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002941static abi_long do_bind(int sockfd, abi_ulong target_addr,
2942 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002943{
aurel328f7aeaf2009-01-30 19:47:57 +00002944 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002945 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002946
Blue Swirl38724252010-09-18 05:53:14 +00002947 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002948 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002949 }
aurel328f7aeaf2009-01-30 19:47:57 +00002950
aurel32607175e2009-04-15 16:11:59 +00002951 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002952
Laurent Vivier7b36f782015-10-28 21:40:44 +01002953 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002954 if (ret)
2955 return ret;
2956
bellard3532fa72006-06-24 15:06:03 +00002957 return get_errno(bind(sockfd, addr, addrlen));
2958}
2959
ths0da46a62007-10-20 20:23:07 +00002960/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002961static abi_long do_connect(int sockfd, abi_ulong target_addr,
2962 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002963{
aurel328f7aeaf2009-01-30 19:47:57 +00002964 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002965 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002966
Blue Swirl38724252010-09-18 05:53:14 +00002967 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002968 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002969 }
aurel328f7aeaf2009-01-30 19:47:57 +00002970
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002971 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002972
Laurent Vivier7b36f782015-10-28 21:40:44 +01002973 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002974 if (ret)
2975 return ret;
2976
Peter Maydell2a3c7612016-06-06 19:58:03 +01002977 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002978}
2979
Alexander Graff19e00d2014-03-02 19:36:42 +00002980/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2981static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2982 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002983{
balrog6de645c2008-10-28 10:26:29 +00002984 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002985 struct msghdr msg;
2986 int count;
2987 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002988 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002989
bellard3532fa72006-06-24 15:06:03 +00002990 if (msgp->msg_name) {
2991 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002992 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002993 ret = target_to_host_sockaddr(fd, msg.msg_name,
2994 tswapal(msgp->msg_name),
2995 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002996 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002997 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002998 }
bellard3532fa72006-06-24 15:06:03 +00002999 } else {
3000 msg.msg_name = NULL;
3001 msg.msg_namelen = 0;
3002 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003003 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003004 msg.msg_control = alloca(msg.msg_controllen);
3005 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003006
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003007 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003008 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003009 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3010 target_vec, count, send);
3011 if (vec == NULL) {
3012 ret = -host_to_target_errno(errno);
3013 goto out2;
3014 }
bellard3532fa72006-06-24 15:06:03 +00003015 msg.msg_iovlen = count;
3016 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003017
bellard3532fa72006-06-24 15:06:03 +00003018 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003019 if (fd_trans_target_to_host_data(fd)) {
3020 ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base,
3021 msg.msg_iov->iov_len);
3022 } else {
3023 ret = target_to_host_cmsg(&msg, msgp);
3024 }
3025 if (ret == 0) {
Peter Maydell66687532016-06-06 19:58:04 +01003026 ret = get_errno(safe_sendmsg(fd, &msg, flags));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003027 }
bellard3532fa72006-06-24 15:06:03 +00003028 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003029 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003030 if (!is_error(ret)) {
3031 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003032 if (fd_trans_host_to_target_data(fd)) {
3033 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003034 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003035 } else {
3036 ret = host_to_target_cmsg(msgp, &msg);
3037 }
Jing Huangca619062012-07-24 13:58:02 +00003038 if (!is_error(ret)) {
3039 msgp->msg_namelen = tswap32(msg.msg_namelen);
3040 if (msg.msg_name != NULL) {
3041 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3042 msg.msg_name, msg.msg_namelen);
3043 if (ret) {
3044 goto out;
3045 }
3046 }
3047
balrog6de645c2008-10-28 10:26:29 +00003048 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003049 }
balrog6de645c2008-10-28 10:26:29 +00003050 }
bellard3532fa72006-06-24 15:06:03 +00003051 }
Jing Huangca619062012-07-24 13:58:02 +00003052
3053out:
bellard3532fa72006-06-24 15:06:03 +00003054 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003055out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003056 return ret;
3057}
3058
3059static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3060 int flags, int send)
3061{
3062 abi_long ret;
3063 struct target_msghdr *msgp;
3064
3065 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3066 msgp,
3067 target_msg,
3068 send ? 1 : 0)) {
3069 return -TARGET_EFAULT;
3070 }
3071 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003072 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003073 return ret;
3074}
3075
Alexander Graff19e00d2014-03-02 19:36:42 +00003076/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3077 * so it might not have this *mmsg-specific flag either.
3078 */
3079#ifndef MSG_WAITFORONE
3080#define MSG_WAITFORONE 0x10000
3081#endif
3082
3083static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3084 unsigned int vlen, unsigned int flags,
3085 int send)
3086{
3087 struct target_mmsghdr *mmsgp;
3088 abi_long ret = 0;
3089 int i;
3090
3091 if (vlen > UIO_MAXIOV) {
3092 vlen = UIO_MAXIOV;
3093 }
3094
3095 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3096 if (!mmsgp) {
3097 return -TARGET_EFAULT;
3098 }
3099
3100 for (i = 0; i < vlen; i++) {
3101 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3102 if (is_error(ret)) {
3103 break;
3104 }
3105 mmsgp[i].msg_len = tswap32(ret);
3106 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3107 if (flags & MSG_WAITFORONE) {
3108 flags |= MSG_DONTWAIT;
3109 }
3110 }
3111
3112 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3113
3114 /* Return number of datagrams sent if we sent any at all;
3115 * otherwise return the error.
3116 */
3117 if (i) {
3118 return i;
3119 }
3120 return ret;
3121}
Alexander Graff19e00d2014-03-02 19:36:42 +00003122
Peter Maydella94b4982013-02-08 04:35:04 +00003123/* do_accept4() Must return target values and target errnos. */
3124static abi_long do_accept4(int fd, abi_ulong target_addr,
3125 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003126{
bellard2f619692007-11-16 10:46:05 +00003127 socklen_t addrlen;
3128 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003129 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003130 int host_flags;
3131
3132 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003133
Peter Maydella94b4982013-02-08 04:35:04 +00003134 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003135 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003136 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003137
3138 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003139 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003140 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003141
Blue Swirl38724252010-09-18 05:53:14 +00003142 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003143 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003144 }
aurel328f7aeaf2009-01-30 19:47:57 +00003145
Arnaud Patard917507b2009-06-19 10:44:45 +03003146 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3147 return -TARGET_EINVAL;
3148
bellard2f619692007-11-16 10:46:05 +00003149 addr = alloca(addrlen);
3150
Peter Maydellff6dc132016-06-06 19:58:13 +01003151 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003152 if (!is_error(ret)) {
3153 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003154 if (put_user_u32(addrlen, target_addrlen_addr))
3155 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003156 }
3157 return ret;
3158}
3159
ths0da46a62007-10-20 20:23:07 +00003160/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003161static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003162 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003163{
bellard2f619692007-11-16 10:46:05 +00003164 socklen_t addrlen;
3165 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003166 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003167
bellard2f619692007-11-16 10:46:05 +00003168 if (get_user_u32(addrlen, target_addrlen_addr))
3169 return -TARGET_EFAULT;
3170
Blue Swirl38724252010-09-18 05:53:14 +00003171 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003172 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003173 }
aurel328f7aeaf2009-01-30 19:47:57 +00003174
Arnaud Patard917507b2009-06-19 10:44:45 +03003175 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3176 return -TARGET_EFAULT;
3177
bellard2f619692007-11-16 10:46:05 +00003178 addr = alloca(addrlen);
3179
pbrook1be9e1d2006-11-19 15:26:04 +00003180 ret = get_errno(getpeername(fd, addr, &addrlen));
3181 if (!is_error(ret)) {
3182 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003183 if (put_user_u32(addrlen, target_addrlen_addr))
3184 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003185 }
3186 return ret;
3187}
3188
ths0da46a62007-10-20 20:23:07 +00003189/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003190static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003191 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003192{
bellard2f619692007-11-16 10:46:05 +00003193 socklen_t addrlen;
3194 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003195 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003196
bellard2f619692007-11-16 10:46:05 +00003197 if (get_user_u32(addrlen, target_addrlen_addr))
3198 return -TARGET_EFAULT;
3199
Blue Swirl38724252010-09-18 05:53:14 +00003200 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003201 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003202 }
aurel328f7aeaf2009-01-30 19:47:57 +00003203
Arnaud Patard917507b2009-06-19 10:44:45 +03003204 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3205 return -TARGET_EFAULT;
3206
bellard2f619692007-11-16 10:46:05 +00003207 addr = alloca(addrlen);
3208
pbrook1be9e1d2006-11-19 15:26:04 +00003209 ret = get_errno(getsockname(fd, addr, &addrlen));
3210 if (!is_error(ret)) {
3211 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003212 if (put_user_u32(addrlen, target_addrlen_addr))
3213 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003214 }
3215 return ret;
3216}
3217
ths0da46a62007-10-20 20:23:07 +00003218/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003219static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003220 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003221{
3222 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003223 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003224
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003225 target_to_host_sock_type(&type);
3226
pbrook1be9e1d2006-11-19 15:26:04 +00003227 ret = get_errno(socketpair(domain, type, protocol, tab));
3228 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003229 if (put_user_s32(tab[0], target_tab_addr)
3230 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3231 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003232 }
3233 return ret;
3234}
3235
ths0da46a62007-10-20 20:23:07 +00003236/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003237static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3238 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003239{
3240 void *addr;
3241 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003242 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003243
Blue Swirl38724252010-09-18 05:53:14 +00003244 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003245 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003246 }
aurel328f7aeaf2009-01-30 19:47:57 +00003247
bellard579a97f2007-11-11 14:26:47 +00003248 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3249 if (!host_msg)
3250 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003251 if (fd_trans_target_to_host_data(fd)) {
3252 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3253 if (ret < 0) {
3254 unlock_user(host_msg, msg, 0);
3255 return ret;
3256 }
3257 }
pbrook1be9e1d2006-11-19 15:26:04 +00003258 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003259 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003260 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003261 if (ret) {
3262 unlock_user(host_msg, msg, 0);
3263 return ret;
3264 }
Peter Maydell66687532016-06-06 19:58:04 +01003265 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003266 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003267 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003268 }
3269 unlock_user(host_msg, msg, 0);
3270 return ret;
3271}
3272
ths0da46a62007-10-20 20:23:07 +00003273/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003274static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3275 abi_ulong target_addr,
3276 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003277{
3278 socklen_t addrlen;
3279 void *addr;
3280 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003281 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003282
bellard579a97f2007-11-11 14:26:47 +00003283 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3284 if (!host_msg)
3285 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003286 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003287 if (get_user_u32(addrlen, target_addrlen)) {
3288 ret = -TARGET_EFAULT;
3289 goto fail;
3290 }
Blue Swirl38724252010-09-18 05:53:14 +00003291 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003292 ret = -TARGET_EINVAL;
3293 goto fail;
3294 }
pbrook1be9e1d2006-11-19 15:26:04 +00003295 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003296 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3297 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003298 } else {
3299 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003300 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003301 }
3302 if (!is_error(ret)) {
3303 if (target_addr) {
3304 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003305 if (put_user_u32(addrlen, target_addrlen)) {
3306 ret = -TARGET_EFAULT;
3307 goto fail;
3308 }
pbrook1be9e1d2006-11-19 15:26:04 +00003309 }
3310 unlock_user(host_msg, msg, len);
3311 } else {
bellard2f619692007-11-16 10:46:05 +00003312fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003313 unlock_user(host_msg, msg, 0);
3314 }
3315 return ret;
3316}
3317
j_mayer32407102007-09-26 23:01:49 +00003318#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003319/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003320static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003321{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003322 static const unsigned ac[] = { /* number of arguments per call */
3323 [SOCKOP_socket] = 3, /* domain, type, protocol */
3324 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3325 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3326 [SOCKOP_listen] = 2, /* sockfd, backlog */
3327 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3328 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3329 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3330 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3331 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3332 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3333 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3334 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3335 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3336 [SOCKOP_shutdown] = 2, /* sockfd, how */
3337 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3338 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003339 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3340 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003341 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3342 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3343 };
3344 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003345
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003346 /* first, collect the arguments in a[] according to ac[] */
3347 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3348 unsigned i;
3349 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3350 for (i = 0; i < ac[num]; ++i) {
3351 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003352 return -TARGET_EFAULT;
3353 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003354 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003355 }
bellard2f619692007-11-16 10:46:05 +00003356
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003357 /* now when we have the args, actually handle the call */
3358 switch (num) {
3359 case SOCKOP_socket: /* domain, type, protocol */
3360 return do_socket(a[0], a[1], a[2]);
3361 case SOCKOP_bind: /* sockfd, addr, addrlen */
3362 return do_bind(a[0], a[1], a[2]);
3363 case SOCKOP_connect: /* sockfd, addr, addrlen */
3364 return do_connect(a[0], a[1], a[2]);
3365 case SOCKOP_listen: /* sockfd, backlog */
3366 return get_errno(listen(a[0], a[1]));
3367 case SOCKOP_accept: /* sockfd, addr, addrlen */
3368 return do_accept4(a[0], a[1], a[2], 0);
3369 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3370 return do_accept4(a[0], a[1], a[2], a[3]);
3371 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3372 return do_getsockname(a[0], a[1], a[2]);
3373 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3374 return do_getpeername(a[0], a[1], a[2]);
3375 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3376 return do_socketpair(a[0], a[1], a[2], a[3]);
3377 case SOCKOP_send: /* sockfd, msg, len, flags */
3378 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3379 case SOCKOP_recv: /* sockfd, msg, len, flags */
3380 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3381 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3382 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3383 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3384 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3385 case SOCKOP_shutdown: /* sockfd, how */
3386 return get_errno(shutdown(a[0], a[1]));
3387 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3388 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3389 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3390 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003391 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3392 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3393 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3394 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003395 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3396 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3397 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3398 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003399 default:
3400 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003401 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003402 }
bellard31e31b82003-02-18 22:55:36 +00003403}
j_mayer32407102007-09-26 23:01:49 +00003404#endif
bellard31e31b82003-02-18 22:55:36 +00003405
bellard8853f862004-02-22 14:57:26 +00003406#define N_SHM_REGIONS 32
3407
3408static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003409 abi_ulong start;
3410 abi_ulong size;
3411 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003412} shm_regions[N_SHM_REGIONS];
3413
ths3eb6b042007-06-03 14:26:27 +00003414struct target_semid_ds
3415{
3416 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003417 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003418#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003419 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003420#endif
blueswir1992f48a2007-10-14 16:27:31 +00003421 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003422#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003423 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003424#endif
blueswir1992f48a2007-10-14 16:27:31 +00003425 abi_ulong sem_nsems;
3426 abi_ulong __unused3;
3427 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003428};
3429
bellard579a97f2007-11-11 14:26:47 +00003430static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3431 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003432{
3433 struct target_ipc_perm *target_ip;
3434 struct target_semid_ds *target_sd;
3435
bellard579a97f2007-11-11 14:26:47 +00003436 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3437 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003438 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003439 host_ip->__key = tswap32(target_ip->__key);
3440 host_ip->uid = tswap32(target_ip->uid);
3441 host_ip->gid = tswap32(target_ip->gid);
3442 host_ip->cuid = tswap32(target_ip->cuid);
3443 host_ip->cgid = tswap32(target_ip->cgid);
3444#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3445 host_ip->mode = tswap32(target_ip->mode);
3446#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003447 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003448#endif
3449#if defined(TARGET_PPC)
3450 host_ip->__seq = tswap32(target_ip->__seq);
3451#else
3452 host_ip->__seq = tswap16(target_ip->__seq);
3453#endif
ths3eb6b042007-06-03 14:26:27 +00003454 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003455 return 0;
ths3eb6b042007-06-03 14:26:27 +00003456}
3457
bellard579a97f2007-11-11 14:26:47 +00003458static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3459 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003460{
3461 struct target_ipc_perm *target_ip;
3462 struct target_semid_ds *target_sd;
3463
bellard579a97f2007-11-11 14:26:47 +00003464 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3465 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003466 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003467 target_ip->__key = tswap32(host_ip->__key);
3468 target_ip->uid = tswap32(host_ip->uid);
3469 target_ip->gid = tswap32(host_ip->gid);
3470 target_ip->cuid = tswap32(host_ip->cuid);
3471 target_ip->cgid = tswap32(host_ip->cgid);
3472#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3473 target_ip->mode = tswap32(host_ip->mode);
3474#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003475 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003476#endif
3477#if defined(TARGET_PPC)
3478 target_ip->__seq = tswap32(host_ip->__seq);
3479#else
3480 target_ip->__seq = tswap16(host_ip->__seq);
3481#endif
ths3eb6b042007-06-03 14:26:27 +00003482 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003483 return 0;
ths3eb6b042007-06-03 14:26:27 +00003484}
3485
bellard579a97f2007-11-11 14:26:47 +00003486static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3487 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003488{
3489 struct target_semid_ds *target_sd;
3490
bellard579a97f2007-11-11 14:26:47 +00003491 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3492 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003493 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3494 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003495 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3496 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3497 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003498 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003499 return 0;
ths3eb6b042007-06-03 14:26:27 +00003500}
3501
bellard579a97f2007-11-11 14:26:47 +00003502static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3503 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003504{
3505 struct target_semid_ds *target_sd;
3506
bellard579a97f2007-11-11 14:26:47 +00003507 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3508 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003509 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003510 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003511 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3512 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3513 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003514 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003515 return 0;
ths3eb6b042007-06-03 14:26:27 +00003516}
3517
aurel32e5289082009-04-18 16:16:12 +00003518struct target_seminfo {
3519 int semmap;
3520 int semmni;
3521 int semmns;
3522 int semmnu;
3523 int semmsl;
3524 int semopm;
3525 int semume;
3526 int semusz;
3527 int semvmx;
3528 int semaem;
3529};
3530
3531static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3532 struct seminfo *host_seminfo)
3533{
3534 struct target_seminfo *target_seminfo;
3535 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3536 return -TARGET_EFAULT;
3537 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3538 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3539 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3540 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3541 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3542 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3543 __put_user(host_seminfo->semume, &target_seminfo->semume);
3544 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3545 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3546 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3547 unlock_user_struct(target_seminfo, target_addr, 1);
3548 return 0;
3549}
3550
thsfa294812007-02-02 22:05:00 +00003551union semun {
3552 int val;
ths3eb6b042007-06-03 14:26:27 +00003553 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003554 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003555 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003556};
3557
ths3eb6b042007-06-03 14:26:27 +00003558union target_semun {
3559 int val;
aurel32e5289082009-04-18 16:16:12 +00003560 abi_ulong buf;
3561 abi_ulong array;
3562 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003563};
3564
aurel32e5289082009-04-18 16:16:12 +00003565static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3566 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003567{
aurel32e5289082009-04-18 16:16:12 +00003568 int nsems;
3569 unsigned short *array;
3570 union semun semun;
3571 struct semid_ds semid_ds;
3572 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003573
aurel32e5289082009-04-18 16:16:12 +00003574 semun.buf = &semid_ds;
3575
3576 ret = semctl(semid, 0, IPC_STAT, semun);
3577 if (ret == -1)
3578 return get_errno(ret);
3579
3580 nsems = semid_ds.sem_nsems;
3581
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303582 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003583 if (!*host_array) {
3584 return -TARGET_ENOMEM;
3585 }
aurel32e5289082009-04-18 16:16:12 +00003586 array = lock_user(VERIFY_READ, target_addr,
3587 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003588 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303589 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003590 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003591 }
aurel32e5289082009-04-18 16:16:12 +00003592
3593 for(i=0; i<nsems; i++) {
3594 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003595 }
aurel32e5289082009-04-18 16:16:12 +00003596 unlock_user(array, target_addr, 0);
3597
bellard579a97f2007-11-11 14:26:47 +00003598 return 0;
ths3eb6b042007-06-03 14:26:27 +00003599}
3600
aurel32e5289082009-04-18 16:16:12 +00003601static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3602 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003603{
aurel32e5289082009-04-18 16:16:12 +00003604 int nsems;
3605 unsigned short *array;
3606 union semun semun;
3607 struct semid_ds semid_ds;
3608 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003609
aurel32e5289082009-04-18 16:16:12 +00003610 semun.buf = &semid_ds;
3611
3612 ret = semctl(semid, 0, IPC_STAT, semun);
3613 if (ret == -1)
3614 return get_errno(ret);
3615
3616 nsems = semid_ds.sem_nsems;
3617
3618 array = lock_user(VERIFY_WRITE, target_addr,
3619 nsems*sizeof(unsigned short), 0);
3620 if (!array)
3621 return -TARGET_EFAULT;
3622
3623 for(i=0; i<nsems; i++) {
3624 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003625 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303626 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003627 unlock_user(array, target_addr, 1);
3628
bellard579a97f2007-11-11 14:26:47 +00003629 return 0;
ths3eb6b042007-06-03 14:26:27 +00003630}
3631
aurel32e5289082009-04-18 16:16:12 +00003632static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003633 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003634{
Stefan Weild1c002b2015-02-08 15:40:58 +01003635 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003636 union semun arg;
3637 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303638 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003639 struct seminfo seminfo;
3640 abi_long ret = -TARGET_EINVAL;
3641 abi_long err;
3642 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003643
3644 switch( cmd ) {
3645 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003646 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003647 /* In 64 bit cross-endian situations, we will erroneously pick up
3648 * the wrong half of the union for the "val" element. To rectify
3649 * this, the entire 8-byte structure is byteswapped, followed by
3650 * a swap of the 4 byte val field. In other cases, the data is
3651 * already in proper host byte order. */
3652 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3653 target_su.buf = tswapal(target_su.buf);
3654 arg.val = tswap32(target_su.val);
3655 } else {
3656 arg.val = target_su.val;
3657 }
aurel32e5289082009-04-18 16:16:12 +00003658 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003659 break;
3660 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003661 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003662 err = target_to_host_semarray(semid, &array, target_su.array);
3663 if (err)
3664 return err;
3665 arg.array = array;
3666 ret = get_errno(semctl(semid, semnum, cmd, arg));
3667 err = host_to_target_semarray(semid, target_su.array, &array);
3668 if (err)
3669 return err;
ths3eb6b042007-06-03 14:26:27 +00003670 break;
3671 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003672 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003673 case SEM_STAT:
3674 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3675 if (err)
3676 return err;
3677 arg.buf = &dsarg;
3678 ret = get_errno(semctl(semid, semnum, cmd, arg));
3679 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3680 if (err)
3681 return err;
ths3eb6b042007-06-03 14:26:27 +00003682 break;
aurel32e5289082009-04-18 16:16:12 +00003683 case IPC_INFO:
3684 case SEM_INFO:
3685 arg.__buf = &seminfo;
3686 ret = get_errno(semctl(semid, semnum, cmd, arg));
3687 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3688 if (err)
3689 return err;
3690 break;
3691 case IPC_RMID:
3692 case GETPID:
3693 case GETNCNT:
3694 case GETZCNT:
3695 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3696 break;
ths3eb6b042007-06-03 14:26:27 +00003697 }
3698
3699 return ret;
3700}
3701
aurel32e5289082009-04-18 16:16:12 +00003702struct target_sembuf {
3703 unsigned short sem_num;
3704 short sem_op;
3705 short sem_flg;
3706};
3707
3708static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3709 abi_ulong target_addr,
3710 unsigned nsops)
3711{
3712 struct target_sembuf *target_sembuf;
3713 int i;
3714
3715 target_sembuf = lock_user(VERIFY_READ, target_addr,
3716 nsops*sizeof(struct target_sembuf), 1);
3717 if (!target_sembuf)
3718 return -TARGET_EFAULT;
3719
3720 for(i=0; i<nsops; i++) {
3721 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3722 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3723 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3724 }
3725
3726 unlock_user(target_sembuf, target_addr, 0);
3727
3728 return 0;
3729}
3730
3731static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3732{
3733 struct sembuf sops[nsops];
3734
3735 if (target_to_host_sembuf(sops, ptr, nsops))
3736 return -TARGET_EFAULT;
3737
Peter Maydellffb7ee72016-06-06 19:58:12 +01003738 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00003739}
3740
ths1bc012f2007-06-03 14:27:49 +00003741struct target_msqid_ds
3742{
aurel321c54ff92008-10-13 21:08:44 +00003743 struct target_ipc_perm msg_perm;
3744 abi_ulong msg_stime;
3745#if TARGET_ABI_BITS == 32
3746 abi_ulong __unused1;
3747#endif
3748 abi_ulong msg_rtime;
3749#if TARGET_ABI_BITS == 32
3750 abi_ulong __unused2;
3751#endif
3752 abi_ulong msg_ctime;
3753#if TARGET_ABI_BITS == 32
3754 abi_ulong __unused3;
3755#endif
3756 abi_ulong __msg_cbytes;
3757 abi_ulong msg_qnum;
3758 abi_ulong msg_qbytes;
3759 abi_ulong msg_lspid;
3760 abi_ulong msg_lrpid;
3761 abi_ulong __unused4;
3762 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003763};
3764
bellard579a97f2007-11-11 14:26:47 +00003765static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3766 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003767{
3768 struct target_msqid_ds *target_md;
3769
bellard579a97f2007-11-11 14:26:47 +00003770 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3771 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003772 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3773 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003774 host_md->msg_stime = tswapal(target_md->msg_stime);
3775 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3776 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3777 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3778 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3779 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3780 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3781 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003782 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003783 return 0;
ths1bc012f2007-06-03 14:27:49 +00003784}
3785
bellard579a97f2007-11-11 14:26:47 +00003786static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3787 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003788{
3789 struct target_msqid_ds *target_md;
3790
bellard579a97f2007-11-11 14:26:47 +00003791 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3792 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003793 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3794 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003795 target_md->msg_stime = tswapal(host_md->msg_stime);
3796 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3797 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3798 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3799 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3800 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3801 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3802 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003803 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003804 return 0;
ths1bc012f2007-06-03 14:27:49 +00003805}
3806
aurel321c54ff92008-10-13 21:08:44 +00003807struct target_msginfo {
3808 int msgpool;
3809 int msgmap;
3810 int msgmax;
3811 int msgmnb;
3812 int msgmni;
3813 int msgssz;
3814 int msgtql;
3815 unsigned short int msgseg;
3816};
3817
3818static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3819 struct msginfo *host_msginfo)
3820{
3821 struct target_msginfo *target_msginfo;
3822 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3823 return -TARGET_EFAULT;
3824 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3825 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3826 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3827 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3828 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3829 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3830 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3831 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3832 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003833 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003834}
3835
3836static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003837{
3838 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003839 struct msginfo msginfo;
3840 abi_long ret = -TARGET_EINVAL;
3841
3842 cmd &= 0xff;
3843
3844 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003845 case IPC_STAT:
3846 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003847 case MSG_STAT:
3848 if (target_to_host_msqid_ds(&dsarg,ptr))
3849 return -TARGET_EFAULT;
3850 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3851 if (host_to_target_msqid_ds(ptr,&dsarg))
3852 return -TARGET_EFAULT;
3853 break;
3854 case IPC_RMID:
3855 ret = get_errno(msgctl(msgid, cmd, NULL));
3856 break;
3857 case IPC_INFO:
3858 case MSG_INFO:
3859 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3860 if (host_to_target_msginfo(ptr, &msginfo))
3861 return -TARGET_EFAULT;
3862 break;
ths1bc012f2007-06-03 14:27:49 +00003863 }
aurel321c54ff92008-10-13 21:08:44 +00003864
ths1bc012f2007-06-03 14:27:49 +00003865 return ret;
3866}
3867
3868struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003869 abi_long mtype;
3870 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003871};
3872
blueswir1992f48a2007-10-14 16:27:31 +00003873static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003874 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003875{
3876 struct target_msgbuf *target_mb;
3877 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003878 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003879
Tom Mustaedcc5f92014-08-12 13:53:37 -05003880 if (msgsz < 0) {
3881 return -TARGET_EINVAL;
3882 }
3883
bellard579a97f2007-11-11 14:26:47 +00003884 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3885 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303886 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003887 if (!host_mb) {
3888 unlock_user_struct(target_mb, msgp, 0);
3889 return -TARGET_ENOMEM;
3890 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003891 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003892 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01003893 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303894 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003895 unlock_user_struct(target_mb, msgp, 0);
3896
3897 return ret;
3898}
3899
blueswir1992f48a2007-10-14 16:27:31 +00003900static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003901 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003902 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003903{
3904 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003905 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003906 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003907 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003908
Peter Maydell99874f62016-05-20 19:00:56 +01003909 if (msgsz < 0) {
3910 return -TARGET_EINVAL;
3911 }
3912
bellard579a97f2007-11-11 14:26:47 +00003913 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3914 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003915
Peter Maydell415d8472016-05-20 19:00:57 +01003916 host_mb = g_try_malloc(msgsz + sizeof(long));
3917 if (!host_mb) {
3918 ret = -TARGET_ENOMEM;
3919 goto end;
3920 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01003921 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003922
bellard579a97f2007-11-11 14:26:47 +00003923 if (ret > 0) {
3924 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3925 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3926 if (!target_mtext) {
3927 ret = -TARGET_EFAULT;
3928 goto end;
3929 }
aurel321c54ff92008-10-13 21:08:44 +00003930 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003931 unlock_user(target_mtext, target_mtext_addr, ret);
3932 }
aurel321c54ff92008-10-13 21:08:44 +00003933
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003934 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003935
bellard579a97f2007-11-11 14:26:47 +00003936end:
3937 if (target_mb)
3938 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003939 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003940 return ret;
3941}
3942
Riku Voipio88a8c982009-04-03 10:42:00 +03003943static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3944 abi_ulong target_addr)
3945{
3946 struct target_shmid_ds *target_sd;
3947
3948 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3949 return -TARGET_EFAULT;
3950 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3951 return -TARGET_EFAULT;
3952 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3953 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3954 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3955 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3956 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3957 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3958 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3959 unlock_user_struct(target_sd, target_addr, 0);
3960 return 0;
3961}
3962
3963static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3964 struct shmid_ds *host_sd)
3965{
3966 struct target_shmid_ds *target_sd;
3967
3968 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3969 return -TARGET_EFAULT;
3970 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3971 return -TARGET_EFAULT;
3972 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3973 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3974 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3975 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3976 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3977 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3978 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3979 unlock_user_struct(target_sd, target_addr, 1);
3980 return 0;
3981}
3982
3983struct target_shminfo {
3984 abi_ulong shmmax;
3985 abi_ulong shmmin;
3986 abi_ulong shmmni;
3987 abi_ulong shmseg;
3988 abi_ulong shmall;
3989};
3990
3991static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3992 struct shminfo *host_shminfo)
3993{
3994 struct target_shminfo *target_shminfo;
3995 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3996 return -TARGET_EFAULT;
3997 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3998 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3999 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4000 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4001 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4002 unlock_user_struct(target_shminfo, target_addr, 1);
4003 return 0;
4004}
4005
4006struct target_shm_info {
4007 int used_ids;
4008 abi_ulong shm_tot;
4009 abi_ulong shm_rss;
4010 abi_ulong shm_swp;
4011 abi_ulong swap_attempts;
4012 abi_ulong swap_successes;
4013};
4014
4015static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4016 struct shm_info *host_shm_info)
4017{
4018 struct target_shm_info *target_shm_info;
4019 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4020 return -TARGET_EFAULT;
4021 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4022 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4023 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4024 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4025 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4026 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4027 unlock_user_struct(target_shm_info, target_addr, 1);
4028 return 0;
4029}
4030
4031static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4032{
4033 struct shmid_ds dsarg;
4034 struct shminfo shminfo;
4035 struct shm_info shm_info;
4036 abi_long ret = -TARGET_EINVAL;
4037
4038 cmd &= 0xff;
4039
4040 switch(cmd) {
4041 case IPC_STAT:
4042 case IPC_SET:
4043 case SHM_STAT:
4044 if (target_to_host_shmid_ds(&dsarg, buf))
4045 return -TARGET_EFAULT;
4046 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4047 if (host_to_target_shmid_ds(buf, &dsarg))
4048 return -TARGET_EFAULT;
4049 break;
4050 case IPC_INFO:
4051 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4052 if (host_to_target_shminfo(buf, &shminfo))
4053 return -TARGET_EFAULT;
4054 break;
4055 case SHM_INFO:
4056 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4057 if (host_to_target_shm_info(buf, &shm_info))
4058 return -TARGET_EFAULT;
4059 break;
4060 case IPC_RMID:
4061 case SHM_LOCK:
4062 case SHM_UNLOCK:
4063 ret = get_errno(shmctl(shmid, cmd, NULL));
4064 break;
4065 }
4066
4067 return ret;
4068}
4069
4070static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4071{
4072 abi_long raddr;
4073 void *host_raddr;
4074 struct shmid_ds shm_info;
4075 int i,ret;
4076
4077 /* find out the length of the shared memory segment */
4078 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4079 if (is_error(ret)) {
4080 /* can't get length, bail out */
4081 return ret;
4082 }
4083
4084 mmap_lock();
4085
4086 if (shmaddr)
4087 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4088 else {
4089 abi_ulong mmap_start;
4090
4091 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4092
4093 if (mmap_start == -1) {
4094 errno = ENOMEM;
4095 host_raddr = (void *)-1;
4096 } else
4097 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4098 }
4099
4100 if (host_raddr == (void *)-1) {
4101 mmap_unlock();
4102 return get_errno((long)host_raddr);
4103 }
4104 raddr=h2g((unsigned long)host_raddr);
4105
4106 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4107 PAGE_VALID | PAGE_READ |
4108 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4109
4110 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004111 if (!shm_regions[i].in_use) {
4112 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004113 shm_regions[i].start = raddr;
4114 shm_regions[i].size = shm_info.shm_segsz;
4115 break;
4116 }
4117 }
4118
4119 mmap_unlock();
4120 return raddr;
4121
4122}
4123
4124static inline abi_long do_shmdt(abi_ulong shmaddr)
4125{
4126 int i;
4127
4128 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004129 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4130 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004131 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004132 break;
4133 }
4134 }
4135
4136 return get_errno(shmdt(g2h(shmaddr)));
4137}
4138
aurel321c54ff92008-10-13 21:08:44 +00004139#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004140/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004141/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004142static abi_long do_ipc(unsigned int call, abi_long first,
4143 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004144 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004145{
4146 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004147 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004148
4149 version = call >> 16;
4150 call &= 0xffff;
4151
4152 switch (call) {
thsfa294812007-02-02 22:05:00 +00004153 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004154 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004155 break;
4156
4157 case IPCOP_semget:
4158 ret = get_errno(semget(first, second, third));
4159 break;
4160
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004161 case IPCOP_semctl: {
4162 /* The semun argument to semctl is passed by value, so dereference the
4163 * ptr argument. */
4164 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004165 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004166 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004167 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004168 }
thsd96372e2007-02-02 22:05:44 +00004169
aurel321c54ff92008-10-13 21:08:44 +00004170 case IPCOP_msgget:
4171 ret = get_errno(msgget(first, second));
4172 break;
thsd96372e2007-02-02 22:05:44 +00004173
aurel321c54ff92008-10-13 21:08:44 +00004174 case IPCOP_msgsnd:
4175 ret = do_msgsnd(first, ptr, second, third);
4176 break;
thsd96372e2007-02-02 22:05:44 +00004177
aurel321c54ff92008-10-13 21:08:44 +00004178 case IPCOP_msgctl:
4179 ret = do_msgctl(first, second, ptr);
4180 break;
thsd96372e2007-02-02 22:05:44 +00004181
aurel321c54ff92008-10-13 21:08:44 +00004182 case IPCOP_msgrcv:
4183 switch (version) {
4184 case 0:
4185 {
4186 struct target_ipc_kludge {
4187 abi_long msgp;
4188 abi_long msgtyp;
4189 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004190
aurel321c54ff92008-10-13 21:08:44 +00004191 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4192 ret = -TARGET_EFAULT;
4193 break;
ths1bc012f2007-06-03 14:27:49 +00004194 }
aurel321c54ff92008-10-13 21:08:44 +00004195
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004196 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004197
4198 unlock_user_struct(tmp, ptr, 0);
4199 break;
4200 }
4201 default:
4202 ret = do_msgrcv(first, ptr, second, fifth, third);
4203 }
4204 break;
thsd96372e2007-02-02 22:05:44 +00004205
bellard8853f862004-02-22 14:57:26 +00004206 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004207 switch (version) {
4208 default:
bellard5a4a8982007-11-11 17:39:18 +00004209 {
4210 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004211 raddr = do_shmat(first, ptr, second);
4212 if (is_error(raddr))
4213 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004214 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004215 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004216 break;
4217 }
4218 case 1:
4219 ret = -TARGET_EINVAL;
4220 break;
bellard5a4a8982007-11-11 17:39:18 +00004221 }
bellard8853f862004-02-22 14:57:26 +00004222 break;
4223 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004224 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004225 break;
4226
4227 case IPCOP_shmget:
4228 /* IPC_* flag values are the same on all linux platforms */
4229 ret = get_errno(shmget(first, second, third));
4230 break;
4231
4232 /* IPC_* and SHM_* command values are the same on all linux platforms */
4233 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004234 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004235 break;
4236 default:
j_mayer32407102007-09-26 23:01:49 +00004237 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004238 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004239 break;
4240 }
4241 return ret;
4242}
j_mayer32407102007-09-26 23:01:49 +00004243#endif
bellard8853f862004-02-22 14:57:26 +00004244
bellard31e31b82003-02-18 22:55:36 +00004245/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004246
Blue Swirl001faf32009-05-13 17:53:17 +00004247#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004248#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4249enum {
4250#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004251STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004252};
4253#undef STRUCT
4254#undef STRUCT_SPECIAL
4255
Blue Swirl001faf32009-05-13 17:53:17 +00004256#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004257#define STRUCT_SPECIAL(name)
4258#include "syscall_types.h"
4259#undef STRUCT
4260#undef STRUCT_SPECIAL
4261
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004262typedef struct IOCTLEntry IOCTLEntry;
4263
4264typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004265 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004266
4267struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004268 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004269 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004270 const char *name;
4271 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004272 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004273 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004274};
bellard31e31b82003-02-18 22:55:36 +00004275
4276#define IOC_R 0x0001
4277#define IOC_W 0x0002
4278#define IOC_RW (IOC_R | IOC_W)
4279
4280#define MAX_STRUCT_SIZE 4096
4281
Peter Maydelldace20d2011-01-10 13:11:24 +00004282#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004283/* So fiemap access checks don't overflow on 32 bit systems.
4284 * This is very slightly smaller than the limit imposed by
4285 * the underlying kernel.
4286 */
4287#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4288 / sizeof(struct fiemap_extent))
4289
4290static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004291 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004292{
4293 /* The parameter for this ioctl is a struct fiemap followed
4294 * by an array of struct fiemap_extent whose size is set
4295 * in fiemap->fm_extent_count. The array is filled in by the
4296 * ioctl.
4297 */
4298 int target_size_in, target_size_out;
4299 struct fiemap *fm;
4300 const argtype *arg_type = ie->arg_type;
4301 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4302 void *argptr, *p;
4303 abi_long ret;
4304 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4305 uint32_t outbufsz;
4306 int free_fm = 0;
4307
4308 assert(arg_type[0] == TYPE_PTR);
4309 assert(ie->access == IOC_RW);
4310 arg_type++;
4311 target_size_in = thunk_type_size(arg_type, 0);
4312 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4313 if (!argptr) {
4314 return -TARGET_EFAULT;
4315 }
4316 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4317 unlock_user(argptr, arg, 0);
4318 fm = (struct fiemap *)buf_temp;
4319 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4320 return -TARGET_EINVAL;
4321 }
4322
4323 outbufsz = sizeof (*fm) +
4324 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4325
4326 if (outbufsz > MAX_STRUCT_SIZE) {
4327 /* We can't fit all the extents into the fixed size buffer.
4328 * Allocate one that is large enough and use it instead.
4329 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304330 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004331 if (!fm) {
4332 return -TARGET_ENOMEM;
4333 }
4334 memcpy(fm, buf_temp, sizeof(struct fiemap));
4335 free_fm = 1;
4336 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004337 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004338 if (!is_error(ret)) {
4339 target_size_out = target_size_in;
4340 /* An extent_count of 0 means we were only counting the extents
4341 * so there are no structs to copy
4342 */
4343 if (fm->fm_extent_count != 0) {
4344 target_size_out += fm->fm_mapped_extents * extent_size;
4345 }
4346 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4347 if (!argptr) {
4348 ret = -TARGET_EFAULT;
4349 } else {
4350 /* Convert the struct fiemap */
4351 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4352 if (fm->fm_extent_count != 0) {
4353 p = argptr + target_size_in;
4354 /* ...and then all the struct fiemap_extents */
4355 for (i = 0; i < fm->fm_mapped_extents; i++) {
4356 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4357 THUNK_TARGET);
4358 p += extent_size;
4359 }
4360 }
4361 unlock_user(argptr, arg, target_size_out);
4362 }
4363 }
4364 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304365 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004366 }
4367 return ret;
4368}
Peter Maydelldace20d2011-01-10 13:11:24 +00004369#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004370
Laurent Vivier059c2f22011-03-30 00:12:12 +02004371static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004372 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004373{
4374 const argtype *arg_type = ie->arg_type;
4375 int target_size;
4376 void *argptr;
4377 int ret;
4378 struct ifconf *host_ifconf;
4379 uint32_t outbufsz;
4380 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4381 int target_ifreq_size;
4382 int nb_ifreq;
4383 int free_buf = 0;
4384 int i;
4385 int target_ifc_len;
4386 abi_long target_ifc_buf;
4387 int host_ifc_len;
4388 char *host_ifc_buf;
4389
4390 assert(arg_type[0] == TYPE_PTR);
4391 assert(ie->access == IOC_RW);
4392
4393 arg_type++;
4394 target_size = thunk_type_size(arg_type, 0);
4395
4396 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4397 if (!argptr)
4398 return -TARGET_EFAULT;
4399 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4400 unlock_user(argptr, arg, 0);
4401
4402 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4403 target_ifc_len = host_ifconf->ifc_len;
4404 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4405
4406 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4407 nb_ifreq = target_ifc_len / target_ifreq_size;
4408 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4409
4410 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4411 if (outbufsz > MAX_STRUCT_SIZE) {
4412 /* We can't fit all the extents into the fixed size buffer.
4413 * Allocate one that is large enough and use it instead.
4414 */
4415 host_ifconf = malloc(outbufsz);
4416 if (!host_ifconf) {
4417 return -TARGET_ENOMEM;
4418 }
4419 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4420 free_buf = 1;
4421 }
4422 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4423
4424 host_ifconf->ifc_len = host_ifc_len;
4425 host_ifconf->ifc_buf = host_ifc_buf;
4426
Peter Maydell49ca6f32016-06-06 19:58:14 +01004427 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004428 if (!is_error(ret)) {
4429 /* convert host ifc_len to target ifc_len */
4430
4431 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4432 target_ifc_len = nb_ifreq * target_ifreq_size;
4433 host_ifconf->ifc_len = target_ifc_len;
4434
4435 /* restore target ifc_buf */
4436
4437 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4438
4439 /* copy struct ifconf to target user */
4440
4441 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4442 if (!argptr)
4443 return -TARGET_EFAULT;
4444 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4445 unlock_user(argptr, arg, target_size);
4446
4447 /* copy ifreq[] to target user */
4448
4449 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4450 for (i = 0; i < nb_ifreq ; i++) {
4451 thunk_convert(argptr + i * target_ifreq_size,
4452 host_ifc_buf + i * sizeof(struct ifreq),
4453 ifreq_arg_type, THUNK_TARGET);
4454 }
4455 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4456 }
4457
4458 if (free_buf) {
4459 free(host_ifconf);
4460 }
4461
4462 return ret;
4463}
4464
Alexander Graf56e904e2012-01-31 18:42:06 +01004465static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004466 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004467{
4468 void *argptr;
4469 struct dm_ioctl *host_dm;
4470 abi_long guest_data;
4471 uint32_t guest_data_size;
4472 int target_size;
4473 const argtype *arg_type = ie->arg_type;
4474 abi_long ret;
4475 void *big_buf = NULL;
4476 char *host_data;
4477
4478 arg_type++;
4479 target_size = thunk_type_size(arg_type, 0);
4480 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4481 if (!argptr) {
4482 ret = -TARGET_EFAULT;
4483 goto out;
4484 }
4485 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4486 unlock_user(argptr, arg, 0);
4487
4488 /* buf_temp is too small, so fetch things into a bigger buffer */
4489 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4490 memcpy(big_buf, buf_temp, target_size);
4491 buf_temp = big_buf;
4492 host_dm = big_buf;
4493
4494 guest_data = arg + host_dm->data_start;
4495 if ((guest_data - arg) < 0) {
4496 ret = -EINVAL;
4497 goto out;
4498 }
4499 guest_data_size = host_dm->data_size - host_dm->data_start;
4500 host_data = (char*)host_dm + host_dm->data_start;
4501
4502 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4503 switch (ie->host_cmd) {
4504 case DM_REMOVE_ALL:
4505 case DM_LIST_DEVICES:
4506 case DM_DEV_CREATE:
4507 case DM_DEV_REMOVE:
4508 case DM_DEV_SUSPEND:
4509 case DM_DEV_STATUS:
4510 case DM_DEV_WAIT:
4511 case DM_TABLE_STATUS:
4512 case DM_TABLE_CLEAR:
4513 case DM_TABLE_DEPS:
4514 case DM_LIST_VERSIONS:
4515 /* no input data */
4516 break;
4517 case DM_DEV_RENAME:
4518 case DM_DEV_SET_GEOMETRY:
4519 /* data contains only strings */
4520 memcpy(host_data, argptr, guest_data_size);
4521 break;
4522 case DM_TARGET_MSG:
4523 memcpy(host_data, argptr, guest_data_size);
4524 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4525 break;
4526 case DM_TABLE_LOAD:
4527 {
4528 void *gspec = argptr;
4529 void *cur_data = host_data;
4530 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4531 int spec_size = thunk_type_size(arg_type, 0);
4532 int i;
4533
4534 for (i = 0; i < host_dm->target_count; i++) {
4535 struct dm_target_spec *spec = cur_data;
4536 uint32_t next;
4537 int slen;
4538
4539 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4540 slen = strlen((char*)gspec + spec_size) + 1;
4541 next = spec->next;
4542 spec->next = sizeof(*spec) + slen;
4543 strcpy((char*)&spec[1], gspec + spec_size);
4544 gspec += next;
4545 cur_data += spec->next;
4546 }
4547 break;
4548 }
4549 default:
4550 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004551 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004552 goto out;
4553 }
4554 unlock_user(argptr, guest_data, 0);
4555
Peter Maydell49ca6f32016-06-06 19:58:14 +01004556 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01004557 if (!is_error(ret)) {
4558 guest_data = arg + host_dm->data_start;
4559 guest_data_size = host_dm->data_size - host_dm->data_start;
4560 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4561 switch (ie->host_cmd) {
4562 case DM_REMOVE_ALL:
4563 case DM_DEV_CREATE:
4564 case DM_DEV_REMOVE:
4565 case DM_DEV_RENAME:
4566 case DM_DEV_SUSPEND:
4567 case DM_DEV_STATUS:
4568 case DM_TABLE_LOAD:
4569 case DM_TABLE_CLEAR:
4570 case DM_TARGET_MSG:
4571 case DM_DEV_SET_GEOMETRY:
4572 /* no return data */
4573 break;
4574 case DM_LIST_DEVICES:
4575 {
4576 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4577 uint32_t remaining_data = guest_data_size;
4578 void *cur_data = argptr;
4579 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4580 int nl_size = 12; /* can't use thunk_size due to alignment */
4581
4582 while (1) {
4583 uint32_t next = nl->next;
4584 if (next) {
4585 nl->next = nl_size + (strlen(nl->name) + 1);
4586 }
4587 if (remaining_data < nl->next) {
4588 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4589 break;
4590 }
4591 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4592 strcpy(cur_data + nl_size, nl->name);
4593 cur_data += nl->next;
4594 remaining_data -= nl->next;
4595 if (!next) {
4596 break;
4597 }
4598 nl = (void*)nl + next;
4599 }
4600 break;
4601 }
4602 case DM_DEV_WAIT:
4603 case DM_TABLE_STATUS:
4604 {
4605 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4606 void *cur_data = argptr;
4607 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4608 int spec_size = thunk_type_size(arg_type, 0);
4609 int i;
4610
4611 for (i = 0; i < host_dm->target_count; i++) {
4612 uint32_t next = spec->next;
4613 int slen = strlen((char*)&spec[1]) + 1;
4614 spec->next = (cur_data - argptr) + spec_size + slen;
4615 if (guest_data_size < spec->next) {
4616 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4617 break;
4618 }
4619 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4620 strcpy(cur_data + spec_size, (char*)&spec[1]);
4621 cur_data = argptr + spec->next;
4622 spec = (void*)host_dm + host_dm->data_start + next;
4623 }
4624 break;
4625 }
4626 case DM_TABLE_DEPS:
4627 {
4628 void *hdata = (void*)host_dm + host_dm->data_start;
4629 int count = *(uint32_t*)hdata;
4630 uint64_t *hdev = hdata + 8;
4631 uint64_t *gdev = argptr + 8;
4632 int i;
4633
4634 *(uint32_t*)argptr = tswap32(count);
4635 for (i = 0; i < count; i++) {
4636 *gdev = tswap64(*hdev);
4637 gdev++;
4638 hdev++;
4639 }
4640 break;
4641 }
4642 case DM_LIST_VERSIONS:
4643 {
4644 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4645 uint32_t remaining_data = guest_data_size;
4646 void *cur_data = argptr;
4647 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4648 int vers_size = thunk_type_size(arg_type, 0);
4649
4650 while (1) {
4651 uint32_t next = vers->next;
4652 if (next) {
4653 vers->next = vers_size + (strlen(vers->name) + 1);
4654 }
4655 if (remaining_data < vers->next) {
4656 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4657 break;
4658 }
4659 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4660 strcpy(cur_data + vers_size, vers->name);
4661 cur_data += vers->next;
4662 remaining_data -= vers->next;
4663 if (!next) {
4664 break;
4665 }
4666 vers = (void*)vers + next;
4667 }
4668 break;
4669 }
4670 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004671 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004672 ret = -TARGET_EINVAL;
4673 goto out;
4674 }
4675 unlock_user(argptr, guest_data, guest_data_size);
4676
4677 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4678 if (!argptr) {
4679 ret = -TARGET_EFAULT;
4680 goto out;
4681 }
4682 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4683 unlock_user(argptr, arg, target_size);
4684 }
4685out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004686 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004687 return ret;
4688}
4689
Alexander Grafa59b5e32014-08-22 13:15:50 +02004690static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004691 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004692{
4693 void *argptr;
4694 int target_size;
4695 const argtype *arg_type = ie->arg_type;
4696 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4697 abi_long ret;
4698
4699 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4700 struct blkpg_partition host_part;
4701
4702 /* Read and convert blkpg */
4703 arg_type++;
4704 target_size = thunk_type_size(arg_type, 0);
4705 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4706 if (!argptr) {
4707 ret = -TARGET_EFAULT;
4708 goto out;
4709 }
4710 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4711 unlock_user(argptr, arg, 0);
4712
4713 switch (host_blkpg->op) {
4714 case BLKPG_ADD_PARTITION:
4715 case BLKPG_DEL_PARTITION:
4716 /* payload is struct blkpg_partition */
4717 break;
4718 default:
4719 /* Unknown opcode */
4720 ret = -TARGET_EINVAL;
4721 goto out;
4722 }
4723
4724 /* Read and convert blkpg->data */
4725 arg = (abi_long)(uintptr_t)host_blkpg->data;
4726 target_size = thunk_type_size(part_arg_type, 0);
4727 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4728 if (!argptr) {
4729 ret = -TARGET_EFAULT;
4730 goto out;
4731 }
4732 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4733 unlock_user(argptr, arg, 0);
4734
4735 /* Swizzle the data pointer to our local copy and call! */
4736 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01004737 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02004738
4739out:
4740 return ret;
4741}
4742
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004743static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004744 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004745{
4746 const argtype *arg_type = ie->arg_type;
4747 const StructEntry *se;
4748 const argtype *field_types;
4749 const int *dst_offsets, *src_offsets;
4750 int target_size;
4751 void *argptr;
4752 abi_ulong *target_rt_dev_ptr;
4753 unsigned long *host_rt_dev_ptr;
4754 abi_long ret;
4755 int i;
4756
4757 assert(ie->access == IOC_W);
4758 assert(*arg_type == TYPE_PTR);
4759 arg_type++;
4760 assert(*arg_type == TYPE_STRUCT);
4761 target_size = thunk_type_size(arg_type, 0);
4762 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4763 if (!argptr) {
4764 return -TARGET_EFAULT;
4765 }
4766 arg_type++;
4767 assert(*arg_type == (int)STRUCT_rtentry);
4768 se = struct_entries + *arg_type++;
4769 assert(se->convert[0] == NULL);
4770 /* convert struct here to be able to catch rt_dev string */
4771 field_types = se->field_types;
4772 dst_offsets = se->field_offsets[THUNK_HOST];
4773 src_offsets = se->field_offsets[THUNK_TARGET];
4774 for (i = 0; i < se->nb_fields; i++) {
4775 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4776 assert(*field_types == TYPE_PTRVOID);
4777 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4778 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4779 if (*target_rt_dev_ptr != 0) {
4780 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4781 tswapal(*target_rt_dev_ptr));
4782 if (!*host_rt_dev_ptr) {
4783 unlock_user(argptr, arg, 0);
4784 return -TARGET_EFAULT;
4785 }
4786 } else {
4787 *host_rt_dev_ptr = 0;
4788 }
4789 field_types++;
4790 continue;
4791 }
4792 field_types = thunk_convert(buf_temp + dst_offsets[i],
4793 argptr + src_offsets[i],
4794 field_types, THUNK_HOST);
4795 }
4796 unlock_user(argptr, arg, 0);
4797
Peter Maydell49ca6f32016-06-06 19:58:14 +01004798 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004799 if (*host_rt_dev_ptr != 0) {
4800 unlock_user((void *)*host_rt_dev_ptr,
4801 *target_rt_dev_ptr, 0);
4802 }
4803 return ret;
4804}
4805
Paul Burtonca56f5b2014-06-22 11:25:47 +01004806static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004807 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004808{
4809 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004810 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01004811}
4812
blueswir19f106a72008-10-05 10:52:52 +00004813static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004814#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004815 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4816#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4817 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004818#include "ioctls.h"
4819 { 0, 0, },
4820};
4821
pbrook53a59602006-03-25 19:31:22 +00004822/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004823/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004824static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004825{
4826 const IOCTLEntry *ie;
4827 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004828 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004829 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004830 int target_size;
4831 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004832
4833 ie = ioctl_entries;
4834 for(;;) {
4835 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004836 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004837 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004838 }
4839 if (ie->target_cmd == cmd)
4840 break;
4841 ie++;
4842 }
4843 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004844#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004845 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004846#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004847 if (ie->do_ioctl) {
4848 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4849 }
4850
bellard31e31b82003-02-18 22:55:36 +00004851 switch(arg_type[0]) {
4852 case TYPE_NULL:
4853 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01004854 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00004855 break;
4856 case TYPE_PTRVOID:
4857 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004858 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00004859 break;
4860 case TYPE_PTR:
4861 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004862 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004863 switch(ie->access) {
4864 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004865 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004866 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004867 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4868 if (!argptr)
4869 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004870 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4871 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004872 }
4873 break;
4874 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004875 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4876 if (!argptr)
4877 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004878 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4879 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004880 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004881 break;
4882 default:
4883 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004884 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4885 if (!argptr)
4886 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004887 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4888 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004889 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004890 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004891 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4892 if (!argptr)
4893 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004894 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4895 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004896 }
4897 break;
4898 }
4899 break;
4900 default:
j_mayer32407102007-09-26 23:01:49 +00004901 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4902 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004903 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004904 break;
4905 }
4906 return ret;
4907}
4908
blueswir1b39bc502008-10-05 10:51:10 +00004909static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004910 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4911 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4912 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4913 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4914 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4915 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4916 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4917 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4918 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4919 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4920 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4921 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4922 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4923 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4924 { 0, 0, 0, 0 }
4925};
4926
blueswir1b39bc502008-10-05 10:51:10 +00004927static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004928 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4929 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4930 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4931 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4932 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4933 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4934 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4935 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4936 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4937 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4938 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4939 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4940 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4941 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4942 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4943 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4944 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4945 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4946 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4947 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4948 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4949 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4950 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4951 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4952 { 0, 0, 0, 0 }
4953};
4954
blueswir1b39bc502008-10-05 10:51:10 +00004955static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004956 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4957 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4958 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4959 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4960 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4961 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4962 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4963 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4964 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4965 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4966 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4967 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4968 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4969 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4970 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4971 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4972 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4973 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4974 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4975 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4976 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4977 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4978 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4979 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4980 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4981 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4982 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4983 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4984 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4985 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4986 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4987 { 0, 0, 0, 0 }
4988};
4989
blueswir1b39bc502008-10-05 10:51:10 +00004990static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004991 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4992 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4993 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4994 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4995 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4996 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4997 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4998 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4999 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5000 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5001 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5002 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5003 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5004 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5005 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5006 { 0, 0, 0, 0 }
5007};
5008
5009static void target_to_host_termios (void *dst, const void *src)
5010{
5011 struct host_termios *host = dst;
5012 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005013
ths5fafdf22007-09-16 21:08:06 +00005014 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005015 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005016 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005017 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005018 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005019 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005020 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005021 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5022 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005023
Arnaud Patard44607122009-04-21 17:39:08 +03005024 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005025 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5026 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005027 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005028 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005029 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005030 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005031 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005032 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005033 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005034 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5035 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005036 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5037 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5038 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5039 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5040 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005041 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005042}
ths3b46e622007-09-17 08:09:54 +00005043
bellard31e31b82003-02-18 22:55:36 +00005044static void host_to_target_termios (void *dst, const void *src)
5045{
5046 struct target_termios *target = dst;
5047 const struct host_termios *host = src;
5048
ths5fafdf22007-09-16 21:08:06 +00005049 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005050 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005051 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005052 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005053 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005054 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005055 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005056 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5057 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005058
Arnaud Patard44607122009-04-21 17:39:08 +03005059 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005060 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5061 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5062 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5063 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5064 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5065 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5066 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5067 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5068 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5069 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5070 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5071 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5072 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5073 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5074 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5075 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5076 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5077}
5078
blueswir18e853dc2008-10-05 10:49:32 +00005079static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005080 .convert = { host_to_target_termios, target_to_host_termios },
5081 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5082 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5083};
5084
bellard5286db72003-06-05 00:57:30 +00005085static bitmask_transtbl mmap_flags_tbl[] = {
5086 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5087 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5088 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5089 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5090 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5091 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5092 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5093 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005094 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5095 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005096 { 0, 0, 0, 0 }
5097};
5098
bellard2ab83ea2003-06-15 19:56:46 +00005099#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005100
5101/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005102static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005103
bellard03acab62007-11-11 14:57:14 +00005104static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005105{
5106 int size;
pbrook53a59602006-03-25 19:31:22 +00005107 void *p;
bellard6dbad632003-03-16 18:05:05 +00005108
5109 if (!ldt_table)
5110 return 0;
5111 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5112 if (size > bytecount)
5113 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005114 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5115 if (!p)
bellard03acab62007-11-11 14:57:14 +00005116 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005117 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005118 memcpy(p, ldt_table, size);
5119 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005120 return size;
5121}
5122
5123/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005124static abi_long write_ldt(CPUX86State *env,
5125 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005126{
5127 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005128 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005129 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005130 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005131 uint32_t *lp, entry_1, entry_2;
5132
5133 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005134 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005135 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005136 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005137 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005138 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005139 ldt_info.limit = tswap32(target_ldt_info->limit);
5140 ldt_info.flags = tswap32(target_ldt_info->flags);
5141 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005142
bellard6dbad632003-03-16 18:05:05 +00005143 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005144 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005145 seg_32bit = ldt_info.flags & 1;
5146 contents = (ldt_info.flags >> 1) & 3;
5147 read_exec_only = (ldt_info.flags >> 3) & 1;
5148 limit_in_pages = (ldt_info.flags >> 4) & 1;
5149 seg_not_present = (ldt_info.flags >> 5) & 1;
5150 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005151#ifdef TARGET_ABI32
5152 lm = 0;
5153#else
5154 lm = (ldt_info.flags >> 7) & 1;
5155#endif
bellard6dbad632003-03-16 18:05:05 +00005156 if (contents == 3) {
5157 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005158 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005159 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005160 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005161 }
5162 /* allocate the LDT */
5163 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005164 env->ldt.base = target_mmap(0,
5165 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5166 PROT_READ|PROT_WRITE,
5167 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5168 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005169 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005170 memset(g2h(env->ldt.base), 0,
5171 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005172 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005173 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005174 }
5175
5176 /* NOTE: same code as Linux kernel */
5177 /* Allow LDTs to be cleared by the user. */
5178 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5179 if (oldmode ||
5180 (contents == 0 &&
5181 read_exec_only == 1 &&
5182 seg_32bit == 0 &&
5183 limit_in_pages == 0 &&
5184 seg_not_present == 1 &&
5185 useable == 0 )) {
5186 entry_1 = 0;
5187 entry_2 = 0;
5188 goto install;
5189 }
5190 }
ths3b46e622007-09-17 08:09:54 +00005191
bellard6dbad632003-03-16 18:05:05 +00005192 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5193 (ldt_info.limit & 0x0ffff);
5194 entry_2 = (ldt_info.base_addr & 0xff000000) |
5195 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5196 (ldt_info.limit & 0xf0000) |
5197 ((read_exec_only ^ 1) << 9) |
5198 (contents << 10) |
5199 ((seg_not_present ^ 1) << 15) |
5200 (seg_32bit << 22) |
5201 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005202 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005203 0x7000;
5204 if (!oldmode)
5205 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005206
bellard6dbad632003-03-16 18:05:05 +00005207 /* Install the new entry ... */
5208install:
5209 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5210 lp[0] = tswap32(entry_1);
5211 lp[1] = tswap32(entry_2);
5212 return 0;
5213}
5214
5215/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005216static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5217 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005218{
bellard03acab62007-11-11 14:57:14 +00005219 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005220
bellard6dbad632003-03-16 18:05:05 +00005221 switch (func) {
5222 case 0:
5223 ret = read_ldt(ptr, bytecount);
5224 break;
5225 case 1:
5226 ret = write_ldt(env, ptr, bytecount, 1);
5227 break;
5228 case 0x11:
5229 ret = write_ldt(env, ptr, bytecount, 0);
5230 break;
bellard03acab62007-11-11 14:57:14 +00005231 default:
5232 ret = -TARGET_ENOSYS;
5233 break;
bellard6dbad632003-03-16 18:05:05 +00005234 }
5235 return ret;
5236}
bellard1b6b0292003-03-22 17:31:38 +00005237
blueswir14583f582008-08-24 10:35:55 +00005238#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005239abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005240{
5241 uint64_t *gdt_table = g2h(env->gdt.base);
5242 struct target_modify_ldt_ldt_s ldt_info;
5243 struct target_modify_ldt_ldt_s *target_ldt_info;
5244 int seg_32bit, contents, read_exec_only, limit_in_pages;
5245 int seg_not_present, useable, lm;
5246 uint32_t *lp, entry_1, entry_2;
5247 int i;
5248
5249 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5250 if (!target_ldt_info)
5251 return -TARGET_EFAULT;
5252 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005253 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005254 ldt_info.limit = tswap32(target_ldt_info->limit);
5255 ldt_info.flags = tswap32(target_ldt_info->flags);
5256 if (ldt_info.entry_number == -1) {
5257 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5258 if (gdt_table[i] == 0) {
5259 ldt_info.entry_number = i;
5260 target_ldt_info->entry_number = tswap32(i);
5261 break;
5262 }
5263 }
5264 }
5265 unlock_user_struct(target_ldt_info, ptr, 1);
5266
5267 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5268 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5269 return -TARGET_EINVAL;
5270 seg_32bit = ldt_info.flags & 1;
5271 contents = (ldt_info.flags >> 1) & 3;
5272 read_exec_only = (ldt_info.flags >> 3) & 1;
5273 limit_in_pages = (ldt_info.flags >> 4) & 1;
5274 seg_not_present = (ldt_info.flags >> 5) & 1;
5275 useable = (ldt_info.flags >> 6) & 1;
5276#ifdef TARGET_ABI32
5277 lm = 0;
5278#else
5279 lm = (ldt_info.flags >> 7) & 1;
5280#endif
5281
5282 if (contents == 3) {
5283 if (seg_not_present == 0)
5284 return -TARGET_EINVAL;
5285 }
5286
5287 /* NOTE: same code as Linux kernel */
5288 /* Allow LDTs to be cleared by the user. */
5289 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5290 if ((contents == 0 &&
5291 read_exec_only == 1 &&
5292 seg_32bit == 0 &&
5293 limit_in_pages == 0 &&
5294 seg_not_present == 1 &&
5295 useable == 0 )) {
5296 entry_1 = 0;
5297 entry_2 = 0;
5298 goto install;
5299 }
5300 }
5301
5302 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5303 (ldt_info.limit & 0x0ffff);
5304 entry_2 = (ldt_info.base_addr & 0xff000000) |
5305 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5306 (ldt_info.limit & 0xf0000) |
5307 ((read_exec_only ^ 1) << 9) |
5308 (contents << 10) |
5309 ((seg_not_present ^ 1) << 15) |
5310 (seg_32bit << 22) |
5311 (limit_in_pages << 23) |
5312 (useable << 20) |
5313 (lm << 21) |
5314 0x7000;
5315
5316 /* Install the new entry ... */
5317install:
5318 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5319 lp[0] = tswap32(entry_1);
5320 lp[1] = tswap32(entry_2);
5321 return 0;
5322}
5323
blueswir18fcd3692008-08-17 20:26:25 +00005324static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005325{
5326 struct target_modify_ldt_ldt_s *target_ldt_info;
5327 uint64_t *gdt_table = g2h(env->gdt.base);
5328 uint32_t base_addr, limit, flags;
5329 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5330 int seg_not_present, useable, lm;
5331 uint32_t *lp, entry_1, entry_2;
5332
5333 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5334 if (!target_ldt_info)
5335 return -TARGET_EFAULT;
5336 idx = tswap32(target_ldt_info->entry_number);
5337 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5338 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5339 unlock_user_struct(target_ldt_info, ptr, 1);
5340 return -TARGET_EINVAL;
5341 }
5342 lp = (uint32_t *)(gdt_table + idx);
5343 entry_1 = tswap32(lp[0]);
5344 entry_2 = tswap32(lp[1]);
5345
5346 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5347 contents = (entry_2 >> 10) & 3;
5348 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5349 seg_32bit = (entry_2 >> 22) & 1;
5350 limit_in_pages = (entry_2 >> 23) & 1;
5351 useable = (entry_2 >> 20) & 1;
5352#ifdef TARGET_ABI32
5353 lm = 0;
5354#else
5355 lm = (entry_2 >> 21) & 1;
5356#endif
5357 flags = (seg_32bit << 0) | (contents << 1) |
5358 (read_exec_only << 3) | (limit_in_pages << 4) |
5359 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5360 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5361 base_addr = (entry_1 >> 16) |
5362 (entry_2 & 0xff000000) |
5363 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005364 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005365 target_ldt_info->limit = tswap32(limit);
5366 target_ldt_info->flags = tswap32(flags);
5367 unlock_user_struct(target_ldt_info, ptr, 1);
5368 return 0;
5369}
blueswir14583f582008-08-24 10:35:55 +00005370#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005371
bellardd2fd1af2007-11-14 18:08:56 +00005372#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005373abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005374{
Juan Quintela1add8692011-06-16 17:37:09 +01005375 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005376 abi_ulong val;
5377 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005378
bellardd2fd1af2007-11-14 18:08:56 +00005379 switch(code) {
5380 case TARGET_ARCH_SET_GS:
5381 case TARGET_ARCH_SET_FS:
5382 if (code == TARGET_ARCH_SET_GS)
5383 idx = R_GS;
5384 else
5385 idx = R_FS;
5386 cpu_x86_load_seg(env, idx, 0);
5387 env->segs[idx].base = addr;
5388 break;
5389 case TARGET_ARCH_GET_GS:
5390 case TARGET_ARCH_GET_FS:
5391 if (code == TARGET_ARCH_GET_GS)
5392 idx = R_GS;
5393 else
5394 idx = R_FS;
5395 val = env->segs[idx].base;
5396 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005397 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005398 break;
5399 default:
5400 ret = -TARGET_EINVAL;
5401 break;
5402 }
Juan Quintela1add8692011-06-16 17:37:09 +01005403 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005404}
5405#endif
5406
bellard2ab83ea2003-06-15 19:56:46 +00005407#endif /* defined(TARGET_I386) */
5408
Riku Voipio05098a92011-03-04 15:27:29 +02005409#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005410
pbrookd865bab2008-06-07 22:12:17 +00005411
5412static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5413typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005414 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005415 pthread_mutex_t mutex;
5416 pthread_cond_t cond;
5417 pthread_t thread;
5418 uint32_t tid;
5419 abi_ulong child_tidptr;
5420 abi_ulong parent_tidptr;
5421 sigset_t sigmask;
5422} new_thread_info;
5423
5424static void *clone_func(void *arg)
5425{
5426 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005427 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005428 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005429 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005430
Emilio G. Cota70903762015-08-23 20:23:41 -04005431 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005432 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005433 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005434 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005435 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005436 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005437 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005438 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005439 if (info->child_tidptr)
5440 put_user_u32(info->tid, info->child_tidptr);
5441 if (info->parent_tidptr)
5442 put_user_u32(info->tid, info->parent_tidptr);
5443 /* Enable signals. */
5444 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5445 /* Signal to the parent that we're ready. */
5446 pthread_mutex_lock(&info->mutex);
5447 pthread_cond_broadcast(&info->cond);
5448 pthread_mutex_unlock(&info->mutex);
5449 /* Wait until the parent has finshed initializing the tls state. */
5450 pthread_mutex_lock(&clone_lock);
5451 pthread_mutex_unlock(&clone_lock);
5452 cpu_loop(env);
5453 /* never exits */
5454 return NULL;
5455}
bellard1b6b0292003-03-22 17:31:38 +00005456
ths0da46a62007-10-20 20:23:07 +00005457/* do_fork() Must return host values and target errnos (unlike most
5458 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005459static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005460 abi_ulong parent_tidptr, target_ulong newtls,
5461 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005462{
Andreas Färber0429a972013-08-26 18:14:44 +02005463 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005464 int ret;
bellard5cd43932003-03-29 16:54:36 +00005465 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005466 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005467 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005468 unsigned int nptl_flags;
5469 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005470
balrog436d1242008-09-21 02:39:45 +00005471 /* Emulate vfork() with fork() */
5472 if (flags & CLONE_VFORK)
5473 flags &= ~(CLONE_VFORK | CLONE_VM);
5474
bellard1b6b0292003-03-22 17:31:38 +00005475 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005476 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005477 new_thread_info info;
5478 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005479
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005480 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005481 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005482 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005483 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005484 /* Init regs that differ from the parent. */
5485 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005486 new_cpu = ENV_GET_CPU(new_env);
5487 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005488 ts->bprm = parent_ts->bprm;
5489 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005490 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005491 nptl_flags = flags;
5492 flags &= ~CLONE_NPTL_FLAGS2;
5493
pbrookc2764712009-03-07 15:24:59 +00005494 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5495 ts->child_tidptr = child_tidptr;
5496 }
5497
pbrookd865bab2008-06-07 22:12:17 +00005498 if (nptl_flags & CLONE_SETTLS)
5499 cpu_set_tls (new_env, newtls);
5500
5501 /* Grab a mutex so that thread setup appears atomic. */
5502 pthread_mutex_lock(&clone_lock);
5503
5504 memset(&info, 0, sizeof(info));
5505 pthread_mutex_init(&info.mutex, NULL);
5506 pthread_mutex_lock(&info.mutex);
5507 pthread_cond_init(&info.cond, NULL);
5508 info.env = new_env;
5509 if (nptl_flags & CLONE_CHILD_SETTID)
5510 info.child_tidptr = child_tidptr;
5511 if (nptl_flags & CLONE_PARENT_SETTID)
5512 info.parent_tidptr = parent_tidptr;
5513
5514 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005515 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5516 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005517 /* It is not safe to deliver signals until the child has finished
5518 initializing, so temporarily block all signals. */
5519 sigfillset(&sigmask);
5520 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5521
5522 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005523 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005524
5525 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5526 pthread_attr_destroy(&attr);
5527 if (ret == 0) {
5528 /* Wait for the child to initialize. */
5529 pthread_cond_wait(&info.cond, &info.mutex);
5530 ret = info.tid;
5531 if (flags & CLONE_PARENT_SETTID)
5532 put_user_u32(ret, parent_tidptr);
5533 } else {
5534 ret = -1;
5535 }
5536 pthread_mutex_unlock(&info.mutex);
5537 pthread_cond_destroy(&info.cond);
5538 pthread_mutex_destroy(&info.mutex);
5539 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005540 } else {
5541 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005542 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5543 return -TARGET_EINVAL;
5544 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005545
5546 if (block_signals()) {
5547 return -TARGET_ERESTARTSYS;
5548 }
5549
pbrookd865bab2008-06-07 22:12:17 +00005550 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005551 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005552 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005553 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005554 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005555 cpu_clone_regs(env, newsp);
5556 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005557 /* There is a race condition here. The parent process could
5558 theoretically read the TID in the child process before the child
5559 tid is set. This would require using either ptrace
5560 (not implemented) or having *_tidptr to point at a shared memory
5561 mapping. We can't repeat the spinlock hack used above because
5562 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005563 if (flags & CLONE_CHILD_SETTID)
5564 put_user_u32(gettid(), child_tidptr);
5565 if (flags & CLONE_PARENT_SETTID)
5566 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005567 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005568 if (flags & CLONE_SETTLS)
5569 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005570 if (flags & CLONE_CHILD_CLEARTID)
5571 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005572 } else {
5573 fork_end(0);
5574 }
bellard1b6b0292003-03-22 17:31:38 +00005575 }
5576 return ret;
5577}
5578
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005579/* warning : doesn't handle linux specific flags... */
5580static int target_to_host_fcntl_cmd(int cmd)
5581{
5582 switch(cmd) {
5583 case TARGET_F_DUPFD:
5584 case TARGET_F_GETFD:
5585 case TARGET_F_SETFD:
5586 case TARGET_F_GETFL:
5587 case TARGET_F_SETFL:
5588 return cmd;
5589 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005590 return F_GETLK64;
5591 case TARGET_F_SETLK:
5592 return F_SETLK64;
5593 case TARGET_F_SETLKW:
5594 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005595 case TARGET_F_GETOWN:
5596 return F_GETOWN;
5597 case TARGET_F_SETOWN:
5598 return F_SETOWN;
5599 case TARGET_F_GETSIG:
5600 return F_GETSIG;
5601 case TARGET_F_SETSIG:
5602 return F_SETSIG;
5603#if TARGET_ABI_BITS == 32
5604 case TARGET_F_GETLK64:
5605 return F_GETLK64;
5606 case TARGET_F_SETLK64:
5607 return F_SETLK64;
5608 case TARGET_F_SETLKW64:
5609 return F_SETLKW64;
5610#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005611 case TARGET_F_SETLEASE:
5612 return F_SETLEASE;
5613 case TARGET_F_GETLEASE:
5614 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005615#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005616 case TARGET_F_DUPFD_CLOEXEC:
5617 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005618#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005619 case TARGET_F_NOTIFY:
5620 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005621#ifdef F_GETOWN_EX
5622 case TARGET_F_GETOWN_EX:
5623 return F_GETOWN_EX;
5624#endif
5625#ifdef F_SETOWN_EX
5626 case TARGET_F_SETOWN_EX:
5627 return F_SETOWN_EX;
5628#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01005629#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005630 case TARGET_F_SETPIPE_SZ:
5631 return F_SETPIPE_SZ;
5632 case TARGET_F_GETPIPE_SZ:
5633 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01005634#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005635 default:
5636 return -TARGET_EINVAL;
5637 }
5638 return -TARGET_EINVAL;
5639}
5640
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005641#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5642static const bitmask_transtbl flock_tbl[] = {
5643 TRANSTBL_CONVERT(F_RDLCK),
5644 TRANSTBL_CONVERT(F_WRLCK),
5645 TRANSTBL_CONVERT(F_UNLCK),
5646 TRANSTBL_CONVERT(F_EXLCK),
5647 TRANSTBL_CONVERT(F_SHLCK),
5648 { 0, 0, 0, 0 }
5649};
5650
Peter Maydell213d3e92016-06-13 11:22:05 +01005651static inline abi_long copy_from_user_flock(struct flock64 *fl,
5652 abi_ulong target_flock_addr)
5653{
5654 struct target_flock *target_fl;
5655 short l_type;
5656
5657 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5658 return -TARGET_EFAULT;
5659 }
5660
5661 __get_user(l_type, &target_fl->l_type);
5662 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5663 __get_user(fl->l_whence, &target_fl->l_whence);
5664 __get_user(fl->l_start, &target_fl->l_start);
5665 __get_user(fl->l_len, &target_fl->l_len);
5666 __get_user(fl->l_pid, &target_fl->l_pid);
5667 unlock_user_struct(target_fl, target_flock_addr, 0);
5668 return 0;
5669}
5670
5671static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
5672 const struct flock64 *fl)
5673{
5674 struct target_flock *target_fl;
5675 short l_type;
5676
5677 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5678 return -TARGET_EFAULT;
5679 }
5680
5681 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5682 __put_user(l_type, &target_fl->l_type);
5683 __put_user(fl->l_whence, &target_fl->l_whence);
5684 __put_user(fl->l_start, &target_fl->l_start);
5685 __put_user(fl->l_len, &target_fl->l_len);
5686 __put_user(fl->l_pid, &target_fl->l_pid);
5687 unlock_user_struct(target_fl, target_flock_addr, 1);
5688 return 0;
5689}
5690
5691typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
5692typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
5693
5694#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
5695static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
5696 abi_ulong target_flock_addr)
5697{
5698 struct target_eabi_flock64 *target_fl;
5699 short l_type;
5700
5701 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5702 return -TARGET_EFAULT;
5703 }
5704
5705 __get_user(l_type, &target_fl->l_type);
5706 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5707 __get_user(fl->l_whence, &target_fl->l_whence);
5708 __get_user(fl->l_start, &target_fl->l_start);
5709 __get_user(fl->l_len, &target_fl->l_len);
5710 __get_user(fl->l_pid, &target_fl->l_pid);
5711 unlock_user_struct(target_fl, target_flock_addr, 0);
5712 return 0;
5713}
5714
5715static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
5716 const struct flock64 *fl)
5717{
5718 struct target_eabi_flock64 *target_fl;
5719 short l_type;
5720
5721 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5722 return -TARGET_EFAULT;
5723 }
5724
5725 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5726 __put_user(l_type, &target_fl->l_type);
5727 __put_user(fl->l_whence, &target_fl->l_whence);
5728 __put_user(fl->l_start, &target_fl->l_start);
5729 __put_user(fl->l_len, &target_fl->l_len);
5730 __put_user(fl->l_pid, &target_fl->l_pid);
5731 unlock_user_struct(target_fl, target_flock_addr, 1);
5732 return 0;
5733}
5734#endif
5735
5736static inline abi_long copy_from_user_flock64(struct flock64 *fl,
5737 abi_ulong target_flock_addr)
5738{
5739 struct target_flock64 *target_fl;
5740 short l_type;
5741
5742 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5743 return -TARGET_EFAULT;
5744 }
5745
5746 __get_user(l_type, &target_fl->l_type);
5747 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5748 __get_user(fl->l_whence, &target_fl->l_whence);
5749 __get_user(fl->l_start, &target_fl->l_start);
5750 __get_user(fl->l_len, &target_fl->l_len);
5751 __get_user(fl->l_pid, &target_fl->l_pid);
5752 unlock_user_struct(target_fl, target_flock_addr, 0);
5753 return 0;
5754}
5755
5756static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
5757 const struct flock64 *fl)
5758{
5759 struct target_flock64 *target_fl;
5760 short l_type;
5761
5762 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5763 return -TARGET_EFAULT;
5764 }
5765
5766 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5767 __put_user(l_type, &target_fl->l_type);
5768 __put_user(fl->l_whence, &target_fl->l_whence);
5769 __put_user(fl->l_start, &target_fl->l_start);
5770 __put_user(fl->l_len, &target_fl->l_len);
5771 __put_user(fl->l_pid, &target_fl->l_pid);
5772 unlock_user_struct(target_fl, target_flock_addr, 1);
5773 return 0;
5774}
5775
blueswir1992f48a2007-10-14 16:27:31 +00005776static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005777{
ths43f238d2007-01-05 20:55:49 +00005778 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005779#ifdef F_GETOWN_EX
5780 struct f_owner_ex fox;
5781 struct target_f_owner_ex *target_fox;
5782#endif
blueswir1992f48a2007-10-14 16:27:31 +00005783 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005784 int host_cmd = target_to_host_fcntl_cmd(cmd);
5785
5786 if (host_cmd == -TARGET_EINVAL)
5787 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005788
bellard7775e9e2003-05-14 22:46:48 +00005789 switch(cmd) {
5790 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005791 ret = copy_from_user_flock(&fl64, arg);
5792 if (ret) {
5793 return ret;
5794 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005795 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005796 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005797 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00005798 }
5799 break;
ths3b46e622007-09-17 08:09:54 +00005800
bellard7775e9e2003-05-14 22:46:48 +00005801 case TARGET_F_SETLK:
5802 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01005803 ret = copy_from_user_flock(&fl64, arg);
5804 if (ret) {
5805 return ret;
5806 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005807 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005808 break;
ths3b46e622007-09-17 08:09:54 +00005809
bellard7775e9e2003-05-14 22:46:48 +00005810 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005811 ret = copy_from_user_flock64(&fl64, arg);
5812 if (ret) {
5813 return ret;
5814 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005815 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005816 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005817 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00005818 }
bellard9ee1fa22007-11-11 15:11:19 +00005819 break;
bellard7775e9e2003-05-14 22:46:48 +00005820 case TARGET_F_SETLK64:
5821 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005822 ret = copy_from_user_flock64(&fl64, arg);
5823 if (ret) {
5824 return ret;
5825 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005826 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005827 break;
5828
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005829 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005830 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005831 if (ret >= 0) {
5832 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5833 }
bellardffa65c32004-01-04 23:57:22 +00005834 break;
5835
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005836 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005837 ret = get_errno(safe_fcntl(fd, host_cmd,
5838 target_to_host_bitmask(arg,
5839 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005840 break;
5841
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005842#ifdef F_GETOWN_EX
5843 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01005844 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005845 if (ret >= 0) {
5846 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5847 return -TARGET_EFAULT;
5848 target_fox->type = tswap32(fox.type);
5849 target_fox->pid = tswap32(fox.pid);
5850 unlock_user_struct(target_fox, arg, 1);
5851 }
5852 break;
5853#endif
5854
5855#ifdef F_SETOWN_EX
5856 case TARGET_F_SETOWN_EX:
5857 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5858 return -TARGET_EFAULT;
5859 fox.type = tswap32(target_fox->type);
5860 fox.pid = tswap32(target_fox->pid);
5861 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01005862 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005863 break;
5864#endif
5865
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005866 case TARGET_F_SETOWN:
5867 case TARGET_F_GETOWN:
5868 case TARGET_F_SETSIG:
5869 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005870 case TARGET_F_SETLEASE:
5871 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005872 case TARGET_F_SETPIPE_SZ:
5873 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01005874 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005875 break;
5876
bellard7775e9e2003-05-14 22:46:48 +00005877 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01005878 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005879 break;
5880 }
5881 return ret;
5882}
5883
bellard67867302003-11-23 17:05:30 +00005884#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005885
bellard67867302003-11-23 17:05:30 +00005886static inline int high2lowuid(int uid)
5887{
5888 if (uid > 65535)
5889 return 65534;
5890 else
5891 return uid;
5892}
5893
5894static inline int high2lowgid(int gid)
5895{
5896 if (gid > 65535)
5897 return 65534;
5898 else
5899 return gid;
5900}
5901
5902static inline int low2highuid(int uid)
5903{
5904 if ((int16_t)uid == -1)
5905 return -1;
5906 else
5907 return uid;
5908}
5909
5910static inline int low2highgid(int gid)
5911{
5912 if ((int16_t)gid == -1)
5913 return -1;
5914 else
5915 return gid;
5916}
Riku Voipio0c866a72011-04-18 15:23:06 +03005917static inline int tswapid(int id)
5918{
5919 return tswap16(id);
5920}
Peter Maydell76ca3102014-03-02 19:36:41 +00005921
5922#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5923
Riku Voipio0c866a72011-04-18 15:23:06 +03005924#else /* !USE_UID16 */
5925static inline int high2lowuid(int uid)
5926{
5927 return uid;
5928}
5929static inline int high2lowgid(int gid)
5930{
5931 return gid;
5932}
5933static inline int low2highuid(int uid)
5934{
5935 return uid;
5936}
5937static inline int low2highgid(int gid)
5938{
5939 return gid;
5940}
5941static inline int tswapid(int id)
5942{
5943 return tswap32(id);
5944}
Peter Maydell76ca3102014-03-02 19:36:41 +00005945
5946#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5947
bellard67867302003-11-23 17:05:30 +00005948#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005949
Peter Maydellfd6f7792016-03-01 16:33:02 +00005950/* We must do direct syscalls for setting UID/GID, because we want to
5951 * implement the Linux system call semantics of "change only for this thread",
5952 * not the libc/POSIX semantics of "change for all threads in process".
5953 * (See http://ewontfix.com/17/ for more details.)
5954 * We use the 32-bit version of the syscalls if present; if it is not
5955 * then either the host architecture supports 32-bit UIDs natively with
5956 * the standard syscall, or the 16-bit UID is the best we can do.
5957 */
5958#ifdef __NR_setuid32
5959#define __NR_sys_setuid __NR_setuid32
5960#else
5961#define __NR_sys_setuid __NR_setuid
5962#endif
5963#ifdef __NR_setgid32
5964#define __NR_sys_setgid __NR_setgid32
5965#else
5966#define __NR_sys_setgid __NR_setgid
5967#endif
5968#ifdef __NR_setresuid32
5969#define __NR_sys_setresuid __NR_setresuid32
5970#else
5971#define __NR_sys_setresuid __NR_setresuid
5972#endif
5973#ifdef __NR_setresgid32
5974#define __NR_sys_setresgid __NR_setresgid32
5975#else
5976#define __NR_sys_setresgid __NR_setresgid
5977#endif
5978
5979_syscall1(int, sys_setuid, uid_t, uid)
5980_syscall1(int, sys_setgid, gid_t, gid)
5981_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
5982_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
5983
bellard31e31b82003-02-18 22:55:36 +00005984void syscall_init(void)
5985{
bellard2ab83ea2003-06-15 19:56:46 +00005986 IOCTLEntry *ie;
5987 const argtype *arg_type;
5988 int size;
thsb92c47c2007-11-01 00:07:38 +00005989 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005990
Alexander Graf8be656b2015-05-06 23:47:32 +02005991 thunk_init(STRUCT_MAX);
5992
Blue Swirl001faf32009-05-13 17:53:17 +00005993#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005994#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005995#include "syscall_types.h"
5996#undef STRUCT
5997#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005998
Peter Maydelldd6e9572012-07-23 08:07:22 +00005999 /* Build target_to_host_errno_table[] table from
6000 * host_to_target_errno_table[]. */
6001 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6002 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6003 }
6004
bellard2ab83ea2003-06-15 19:56:46 +00006005 /* we patch the ioctl size if necessary. We rely on the fact that
6006 no ioctl has all the bits at '1' in the size field */
6007 ie = ioctl_entries;
6008 while (ie->target_cmd != 0) {
6009 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6010 TARGET_IOC_SIZEMASK) {
6011 arg_type = ie->arg_type;
6012 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006013 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006014 ie->target_cmd);
6015 exit(1);
6016 }
6017 arg_type++;
6018 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006019 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006020 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6021 (size << TARGET_IOC_SIZESHIFT);
6022 }
thsb92c47c2007-11-01 00:07:38 +00006023
bellard2ab83ea2003-06-15 19:56:46 +00006024 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006025#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6026 (defined(__x86_64__) && defined(TARGET_X86_64))
6027 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6028 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6029 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006030 }
6031#endif
6032 ie++;
6033 }
bellard31e31b82003-02-18 22:55:36 +00006034}
bellardc573ff62004-01-04 15:51:36 +00006035
blueswir1992f48a2007-10-14 16:27:31 +00006036#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006037static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6038{
thsaf325d32008-06-10 15:29:15 +00006039#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006040 return ((uint64_t)word0 << 32) | word1;
6041#else
6042 return ((uint64_t)word1 << 32) | word0;
6043#endif
6044}
blueswir1992f48a2007-10-14 16:27:31 +00006045#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006046static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6047{
6048 return word0;
6049}
blueswir1992f48a2007-10-14 16:27:31 +00006050#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006051
6052#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006053static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6054 abi_long arg2,
6055 abi_long arg3,
6056 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006057{
Riku Voipio48e515d2011-07-12 15:40:51 +03006058 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006059 arg2 = arg3;
6060 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006061 }
pbrookce4defa2006-02-09 16:49:55 +00006062 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6063}
6064#endif
6065
6066#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006067static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6068 abi_long arg2,
6069 abi_long arg3,
6070 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006071{
Riku Voipio48e515d2011-07-12 15:40:51 +03006072 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006073 arg2 = arg3;
6074 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006075 }
pbrookce4defa2006-02-09 16:49:55 +00006076 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6077}
6078#endif
6079
bellard579a97f2007-11-11 14:26:47 +00006080static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6081 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006082{
6083 struct target_timespec *target_ts;
6084
bellard579a97f2007-11-11 14:26:47 +00006085 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6086 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006087 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6088 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006089 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006090 return 0;
pbrook53a59602006-03-25 19:31:22 +00006091}
6092
bellard579a97f2007-11-11 14:26:47 +00006093static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6094 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006095{
6096 struct target_timespec *target_ts;
6097
bellard579a97f2007-11-11 14:26:47 +00006098 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6099 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006100 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6101 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006102 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006103 return 0;
pbrook53a59602006-03-25 19:31:22 +00006104}
6105
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006106static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6107 abi_ulong target_addr)
6108{
6109 struct target_itimerspec *target_itspec;
6110
6111 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6112 return -TARGET_EFAULT;
6113 }
6114
6115 host_itspec->it_interval.tv_sec =
6116 tswapal(target_itspec->it_interval.tv_sec);
6117 host_itspec->it_interval.tv_nsec =
6118 tswapal(target_itspec->it_interval.tv_nsec);
6119 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6120 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6121
6122 unlock_user_struct(target_itspec, target_addr, 1);
6123 return 0;
6124}
6125
6126static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6127 struct itimerspec *host_its)
6128{
6129 struct target_itimerspec *target_itspec;
6130
6131 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6132 return -TARGET_EFAULT;
6133 }
6134
6135 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6136 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6137
6138 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6139 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6140
6141 unlock_user_struct(target_itspec, target_addr, 0);
6142 return 0;
6143}
6144
Peter Maydellc0659762014-08-09 15:42:32 +01006145static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6146 abi_ulong target_addr)
6147{
6148 struct target_sigevent *target_sevp;
6149
6150 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6151 return -TARGET_EFAULT;
6152 }
6153
6154 /* This union is awkward on 64 bit systems because it has a 32 bit
6155 * integer and a pointer in it; we follow the conversion approach
6156 * used for handling sigval types in signal.c so the guest should get
6157 * the correct value back even if we did a 64 bit byteswap and it's
6158 * using the 32 bit integer.
6159 */
6160 host_sevp->sigev_value.sival_ptr =
6161 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6162 host_sevp->sigev_signo =
6163 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6164 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6165 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6166
6167 unlock_user_struct(target_sevp, target_addr, 1);
6168 return 0;
6169}
6170
Tom Musta6f6a4032014-08-12 13:53:42 -05006171#if defined(TARGET_NR_mlockall)
6172static inline int target_to_host_mlockall_arg(int arg)
6173{
6174 int result = 0;
6175
6176 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6177 result |= MCL_CURRENT;
6178 }
6179 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6180 result |= MCL_FUTURE;
6181 }
6182 return result;
6183}
6184#endif
6185
balrog6a24a772008-09-20 02:23:36 +00006186static inline abi_long host_to_target_stat64(void *cpu_env,
6187 abi_ulong target_addr,
6188 struct stat *host_st)
6189{
Alexander Graf09701192013-09-03 20:12:15 +01006190#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006191 if (((CPUARMState *)cpu_env)->eabi) {
6192 struct target_eabi_stat64 *target_st;
6193
6194 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6195 return -TARGET_EFAULT;
6196 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6197 __put_user(host_st->st_dev, &target_st->st_dev);
6198 __put_user(host_st->st_ino, &target_st->st_ino);
6199#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6200 __put_user(host_st->st_ino, &target_st->__st_ino);
6201#endif
6202 __put_user(host_st->st_mode, &target_st->st_mode);
6203 __put_user(host_st->st_nlink, &target_st->st_nlink);
6204 __put_user(host_st->st_uid, &target_st->st_uid);
6205 __put_user(host_st->st_gid, &target_st->st_gid);
6206 __put_user(host_st->st_rdev, &target_st->st_rdev);
6207 __put_user(host_st->st_size, &target_st->st_size);
6208 __put_user(host_st->st_blksize, &target_st->st_blksize);
6209 __put_user(host_st->st_blocks, &target_st->st_blocks);
6210 __put_user(host_st->st_atime, &target_st->target_st_atime);
6211 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6212 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6213 unlock_user_struct(target_st, target_addr, 1);
6214 } else
6215#endif
6216 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006217#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006218 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006219#else
6220 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006221#endif
balrog6a24a772008-09-20 02:23:36 +00006222
6223 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6224 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006225 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006226 __put_user(host_st->st_dev, &target_st->st_dev);
6227 __put_user(host_st->st_ino, &target_st->st_ino);
6228#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6229 __put_user(host_st->st_ino, &target_st->__st_ino);
6230#endif
6231 __put_user(host_st->st_mode, &target_st->st_mode);
6232 __put_user(host_st->st_nlink, &target_st->st_nlink);
6233 __put_user(host_st->st_uid, &target_st->st_uid);
6234 __put_user(host_st->st_gid, &target_st->st_gid);
6235 __put_user(host_st->st_rdev, &target_st->st_rdev);
6236 /* XXX: better use of kernel struct */
6237 __put_user(host_st->st_size, &target_st->st_size);
6238 __put_user(host_st->st_blksize, &target_st->st_blksize);
6239 __put_user(host_st->st_blocks, &target_st->st_blocks);
6240 __put_user(host_st->st_atime, &target_st->target_st_atime);
6241 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6242 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6243 unlock_user_struct(target_st, target_addr, 1);
6244 }
6245
6246 return 0;
6247}
balrog6a24a772008-09-20 02:23:36 +00006248
pbrookbd0c5662008-05-29 14:34:11 +00006249/* ??? Using host futex calls even when target atomic operations
6250 are not really atomic probably breaks things. However implementing
6251 futexes locally would make futexes shared between multiple processes
6252 tricky. However they're probably useless because guest atomic
6253 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006254static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6255 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006256{
6257 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006258 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006259
6260 /* ??? We assume FUTEX_* constants are the same on both host
6261 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006262#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006263 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006264#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006265 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006266#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006267 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006268 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006269 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006270 if (timeout) {
6271 pts = &ts;
6272 target_to_host_timespec(pts, timeout);
6273 } else {
6274 pts = NULL;
6275 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006276 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006277 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006278 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006279 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006280 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006281 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006282 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006283 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006284 case FUTEX_WAKE_OP:
6285 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6286 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6287 But the prototype takes a `struct timespec *'; insert casts
6288 to satisfy the compiler. We do not need to tswap TIMEOUT
6289 since it's not compared to guest memory. */
6290 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006291 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6292 g2h(uaddr2),
6293 (base_op == FUTEX_CMP_REQUEUE
6294 ? tswap32(val3)
6295 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006296 default:
6297 return -TARGET_ENOSYS;
6298 }
6299}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006300#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6301static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6302 abi_long handle, abi_long mount_id,
6303 abi_long flags)
6304{
6305 struct file_handle *target_fh;
6306 struct file_handle *fh;
6307 int mid = 0;
6308 abi_long ret;
6309 char *name;
6310 unsigned int size, total_size;
6311
6312 if (get_user_s32(size, handle)) {
6313 return -TARGET_EFAULT;
6314 }
6315
6316 name = lock_user_string(pathname);
6317 if (!name) {
6318 return -TARGET_EFAULT;
6319 }
6320
6321 total_size = sizeof(struct file_handle) + size;
6322 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6323 if (!target_fh) {
6324 unlock_user(name, pathname, 0);
6325 return -TARGET_EFAULT;
6326 }
6327
6328 fh = g_malloc0(total_size);
6329 fh->handle_bytes = size;
6330
6331 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6332 unlock_user(name, pathname, 0);
6333
6334 /* man name_to_handle_at(2):
6335 * Other than the use of the handle_bytes field, the caller should treat
6336 * the file_handle structure as an opaque data type
6337 */
6338
6339 memcpy(target_fh, fh, total_size);
6340 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6341 target_fh->handle_type = tswap32(fh->handle_type);
6342 g_free(fh);
6343 unlock_user(target_fh, handle, total_size);
6344
6345 if (put_user_s32(mid, mount_id)) {
6346 return -TARGET_EFAULT;
6347 }
6348
6349 return ret;
6350
6351}
6352#endif
6353
6354#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6355static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6356 abi_long flags)
6357{
6358 struct file_handle *target_fh;
6359 struct file_handle *fh;
6360 unsigned int size, total_size;
6361 abi_long ret;
6362
6363 if (get_user_s32(size, handle)) {
6364 return -TARGET_EFAULT;
6365 }
6366
6367 total_size = sizeof(struct file_handle) + size;
6368 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6369 if (!target_fh) {
6370 return -TARGET_EFAULT;
6371 }
6372
Thomas Huthe9d49d52015-10-09 17:56:38 +02006373 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006374 fh->handle_bytes = size;
6375 fh->handle_type = tswap32(target_fh->handle_type);
6376
6377 ret = get_errno(open_by_handle_at(mount_fd, fh,
6378 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6379
6380 g_free(fh);
6381
6382 unlock_user(target_fh, handle, total_size);
6383
6384 return ret;
6385}
6386#endif
pbrookbd0c5662008-05-29 14:34:11 +00006387
Laurent Viviere36800c2015-10-02 14:48:09 +02006388#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6389
6390/* signalfd siginfo conversion */
6391
6392static void
6393host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6394 const struct signalfd_siginfo *info)
6395{
6396 int sig = host_to_target_signal(info->ssi_signo);
6397
6398 /* linux/signalfd.h defines a ssi_addr_lsb
6399 * not defined in sys/signalfd.h but used by some kernels
6400 */
6401
6402#ifdef BUS_MCEERR_AO
6403 if (tinfo->ssi_signo == SIGBUS &&
6404 (tinfo->ssi_code == BUS_MCEERR_AR ||
6405 tinfo->ssi_code == BUS_MCEERR_AO)) {
6406 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6407 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6408 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6409 }
6410#endif
6411
6412 tinfo->ssi_signo = tswap32(sig);
6413 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6414 tinfo->ssi_code = tswap32(info->ssi_code);
6415 tinfo->ssi_pid = tswap32(info->ssi_pid);
6416 tinfo->ssi_uid = tswap32(info->ssi_uid);
6417 tinfo->ssi_fd = tswap32(info->ssi_fd);
6418 tinfo->ssi_tid = tswap32(info->ssi_tid);
6419 tinfo->ssi_band = tswap32(info->ssi_band);
6420 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6421 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6422 tinfo->ssi_status = tswap32(info->ssi_status);
6423 tinfo->ssi_int = tswap32(info->ssi_int);
6424 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6425 tinfo->ssi_utime = tswap64(info->ssi_utime);
6426 tinfo->ssi_stime = tswap64(info->ssi_stime);
6427 tinfo->ssi_addr = tswap64(info->ssi_addr);
6428}
6429
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006430static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006431{
6432 int i;
6433
6434 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6435 host_to_target_signalfd_siginfo(buf + i, buf + i);
6436 }
6437
6438 return len;
6439}
6440
6441static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006442 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006443};
6444
6445static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6446{
6447 int host_flags;
6448 target_sigset_t *target_mask;
6449 sigset_t host_mask;
6450 abi_long ret;
6451
6452 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6453 return -TARGET_EINVAL;
6454 }
6455 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6456 return -TARGET_EFAULT;
6457 }
6458
6459 target_to_host_sigset(&host_mask, target_mask);
6460
6461 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6462
6463 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6464 if (ret >= 0) {
6465 fd_trans_register(ret, &target_signalfd_trans);
6466 }
6467
6468 unlock_user_struct(target_mask, mask, 0);
6469
6470 return ret;
6471}
6472#endif
6473
pbrook1d9d8b52009-04-16 15:17:02 +00006474/* Map host to target signal numbers for the wait family of syscalls.
6475 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006476int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006477{
6478 if (WIFSIGNALED(status)) {
6479 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6480 }
6481 if (WIFSTOPPED(status)) {
6482 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6483 | (status & 0xff);
6484 }
6485 return status;
6486}
6487
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006488static int open_self_cmdline(void *cpu_env, int fd)
6489{
6490 int fd_orig = -1;
6491 bool word_skipped = false;
6492
6493 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6494 if (fd_orig < 0) {
6495 return fd_orig;
6496 }
6497
6498 while (true) {
6499 ssize_t nb_read;
6500 char buf[128];
6501 char *cp_buf = buf;
6502
6503 nb_read = read(fd_orig, buf, sizeof(buf));
6504 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006505 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006506 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006507 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006508 return -1;
6509 } else if (nb_read == 0) {
6510 break;
6511 }
6512
6513 if (!word_skipped) {
6514 /* Skip the first string, which is the path to qemu-*-static
6515 instead of the actual command. */
6516 cp_buf = memchr(buf, 0, sizeof(buf));
6517 if (cp_buf) {
6518 /* Null byte found, skip one string */
6519 cp_buf++;
6520 nb_read -= cp_buf - buf;
6521 word_skipped = true;
6522 }
6523 }
6524
6525 if (word_skipped) {
6526 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006527 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006528 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006529 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006530 return -1;
6531 }
6532 }
6533 }
6534
6535 return close(fd_orig);
6536}
6537
Alexander Graf36c08d42011-11-02 20:23:24 +01006538static int open_self_maps(void *cpu_env, int fd)
6539{
Andreas Färber0429a972013-08-26 18:14:44 +02006540 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6541 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006542 FILE *fp;
6543 char *line = NULL;
6544 size_t len = 0;
6545 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006546
Alexander Graf1a49ef22012-05-01 16:30:28 +01006547 fp = fopen("/proc/self/maps", "r");
6548 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006549 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006550 }
6551
6552 while ((read = getline(&line, &len, fp)) != -1) {
6553 int fields, dev_maj, dev_min, inode;
6554 uint64_t min, max, offset;
6555 char flag_r, flag_w, flag_x, flag_p;
6556 char path[512] = "";
6557 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6558 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6559 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6560
6561 if ((fields < 10) || (fields > 11)) {
6562 continue;
6563 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006564 if (h2g_valid(min)) {
6565 int flags = page_get_flags(h2g(min));
6566 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6567 if (page_check_range(h2g(min), max - min, flags) == -1) {
6568 continue;
6569 }
6570 if (h2g(min) == ts->info->stack_limit) {
6571 pstrcpy(path, sizeof(path), " [stack]");
6572 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006573 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006574 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006575 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006576 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006577 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006578 }
6579 }
6580
6581 free(line);
6582 fclose(fp);
6583
Alexander Graf36c08d42011-11-02 20:23:24 +01006584 return 0;
6585}
6586
Alexander Graf480b8e72011-11-02 20:23:25 +01006587static int open_self_stat(void *cpu_env, int fd)
6588{
Andreas Färber0429a972013-08-26 18:14:44 +02006589 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6590 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006591 abi_ulong start_stack = ts->info->start_stack;
6592 int i;
6593
6594 for (i = 0; i < 44; i++) {
6595 char buf[128];
6596 int len;
6597 uint64_t val = 0;
6598
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006599 if (i == 0) {
6600 /* pid */
6601 val = getpid();
6602 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6603 } else if (i == 1) {
6604 /* app name */
6605 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6606 } else if (i == 27) {
6607 /* stack bottom */
6608 val = start_stack;
6609 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6610 } else {
6611 /* for the rest, there is MasterCard */
6612 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006613 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006614
Alexander Graf480b8e72011-11-02 20:23:25 +01006615 len = strlen(buf);
6616 if (write(fd, buf, len) != len) {
6617 return -1;
6618 }
6619 }
6620
6621 return 0;
6622}
6623
Alexander Graf257450e2011-11-02 20:23:26 +01006624static int open_self_auxv(void *cpu_env, int fd)
6625{
Andreas Färber0429a972013-08-26 18:14:44 +02006626 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6627 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006628 abi_ulong auxv = ts->info->saved_auxv;
6629 abi_ulong len = ts->info->auxv_len;
6630 char *ptr;
6631
6632 /*
6633 * Auxiliary vector is stored in target process stack.
6634 * read in whole auxv vector and copy it to file
6635 */
6636 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6637 if (ptr != NULL) {
6638 while (len > 0) {
6639 ssize_t r;
6640 r = write(fd, ptr, len);
6641 if (r <= 0) {
6642 break;
6643 }
6644 len -= r;
6645 ptr += r;
6646 }
6647 lseek(fd, 0, SEEK_SET);
6648 unlock_user(ptr, auxv, len);
6649 }
6650
6651 return 0;
6652}
6653
Andreas Schwab463d8e72013-07-02 14:04:12 +01006654static int is_proc_myself(const char *filename, const char *entry)
6655{
6656 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6657 filename += strlen("/proc/");
6658 if (!strncmp(filename, "self/", strlen("self/"))) {
6659 filename += strlen("self/");
6660 } else if (*filename >= '1' && *filename <= '9') {
6661 char myself[80];
6662 snprintf(myself, sizeof(myself), "%d/", getpid());
6663 if (!strncmp(filename, myself, strlen(myself))) {
6664 filename += strlen(myself);
6665 } else {
6666 return 0;
6667 }
6668 } else {
6669 return 0;
6670 }
6671 if (!strcmp(filename, entry)) {
6672 return 1;
6673 }
6674 }
6675 return 0;
6676}
6677
Laurent Vivierde6b9932013-08-30 01:46:40 +02006678#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6679static int is_proc(const char *filename, const char *entry)
6680{
6681 return strcmp(filename, entry) == 0;
6682}
6683
6684static int open_net_route(void *cpu_env, int fd)
6685{
6686 FILE *fp;
6687 char *line = NULL;
6688 size_t len = 0;
6689 ssize_t read;
6690
6691 fp = fopen("/proc/net/route", "r");
6692 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006693 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006694 }
6695
6696 /* read header */
6697
6698 read = getline(&line, &len, fp);
6699 dprintf(fd, "%s", line);
6700
6701 /* read routes */
6702
6703 while ((read = getline(&line, &len, fp)) != -1) {
6704 char iface[16];
6705 uint32_t dest, gw, mask;
6706 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6707 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6708 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6709 &mask, &mtu, &window, &irtt);
6710 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6711 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6712 metric, tswap32(mask), mtu, window, irtt);
6713 }
6714
6715 free(line);
6716 fclose(fp);
6717
6718 return 0;
6719}
6720#endif
6721
Riku Voipio0b2effd2014-08-06 10:36:37 +03006722static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006723{
6724 struct fake_open {
6725 const char *filename;
6726 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006727 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006728 };
6729 const struct fake_open *fake_open;
6730 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006731 { "maps", open_self_maps, is_proc_myself },
6732 { "stat", open_self_stat, is_proc_myself },
6733 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006734 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006735#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6736 { "/proc/net/route", open_net_route, is_proc },
6737#endif
6738 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006739 };
6740
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006741 if (is_proc_myself(pathname, "exe")) {
6742 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006743 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006744 }
6745
Alexander Graf3be14d02011-11-02 20:23:23 +01006746 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006747 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006748 break;
6749 }
6750 }
6751
6752 if (fake_open->filename) {
6753 const char *tmpdir;
6754 char filename[PATH_MAX];
6755 int fd, r;
6756
6757 /* create temporary file to map stat to */
6758 tmpdir = getenv("TMPDIR");
6759 if (!tmpdir)
6760 tmpdir = "/tmp";
6761 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6762 fd = mkstemp(filename);
6763 if (fd < 0) {
6764 return fd;
6765 }
6766 unlink(filename);
6767
6768 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006769 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006770 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006771 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006772 return r;
6773 }
6774 lseek(fd, 0, SEEK_SET);
6775
6776 return fd;
6777 }
6778
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006779 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006780}
6781
Alexander Grafaecc8862014-11-10 21:33:03 +01006782#define TIMER_MAGIC 0x0caf0000
6783#define TIMER_MAGIC_MASK 0xffff0000
6784
6785/* Convert QEMU provided timer ID back to internal 16bit index format */
6786static target_timer_t get_timer_id(abi_long arg)
6787{
6788 target_timer_t timerid = arg;
6789
6790 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6791 return -TARGET_EINVAL;
6792 }
6793
6794 timerid &= 0xffff;
6795
6796 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6797 return -TARGET_EINVAL;
6798 }
6799
6800 return timerid;
6801}
6802
ths0da46a62007-10-20 20:23:07 +00006803/* do_syscall() should always have a single exit point at the end so
6804 that actions, such as logging of syscall results, can be performed.
6805 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006806abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6807 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006808 abi_long arg5, abi_long arg6, abi_long arg7,
6809 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006810{
Andreas Färber182735e2013-05-29 22:29:20 +02006811 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006812 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006813 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006814 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006815 void *p;
ths3b46e622007-09-17 08:09:54 +00006816
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006817#if defined(DEBUG_ERESTARTSYS)
6818 /* Debug-only code for exercising the syscall-restart code paths
6819 * in the per-architecture cpu main loops: restart every syscall
6820 * the guest makes once before letting it through.
6821 */
6822 {
6823 static int flag;
6824
6825 flag = !flag;
6826 if (flag) {
6827 return -TARGET_ERESTARTSYS;
6828 }
6829 }
6830#endif
6831
bellard72f03902003-02-18 23:33:18 +00006832#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006833 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006834#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02006835 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00006836 if(do_strace)
6837 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6838
bellard31e31b82003-02-18 22:55:36 +00006839 switch(num) {
6840 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006841 /* In old applications this may be used to implement _exit(2).
6842 However in threaded applictions it is used for thread termination,
6843 and _exit_group is used for application termination.
6844 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01006845
6846 if (block_signals()) {
6847 ret = -TARGET_ERESTARTSYS;
6848 break;
6849 }
6850
Andreas Färberbdc44642013-06-24 23:50:24 +02006851 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006852 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006853
Andreas Färber9b056fc2013-06-24 23:53:10 +02006854 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006855 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006856 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006857 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006858 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006859 if (ts->child_tidptr) {
6860 put_user_u32(0, ts->child_tidptr);
6861 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6862 NULL, NULL, 0);
6863 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006864 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006865 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006866 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006867 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006868 pthread_exit(NULL);
6869 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006870#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006871 _mcleanup();
6872#endif
bellarde9009672005-04-26 20:42:36 +00006873 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006874 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006875 ret = 0; /* avoid warning */
6876 break;
6877 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006878 if (arg3 == 0)
6879 ret = 0;
6880 else {
6881 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6882 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006883 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006884 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006885 fd_trans_host_to_target_data(arg1)) {
6886 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006887 }
aurel3238d840e2009-01-30 19:48:17 +00006888 unlock_user(p, arg2, ret);
6889 }
bellard31e31b82003-02-18 22:55:36 +00006890 break;
6891 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006892 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6893 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006894 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006895 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006896 break;
Chen Gang704eff62015-08-21 05:37:33 +08006897#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006898 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006899 if (!(p = lock_user_string(arg1)))
6900 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006901 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6902 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6903 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006904 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006905 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006906 break;
Chen Gang704eff62015-08-21 05:37:33 +08006907#endif
ths82424832007-09-24 09:21:55 +00006908 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006909 if (!(p = lock_user_string(arg2)))
6910 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006911 ret = get_errno(do_openat(cpu_env, arg1, p,
6912 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6913 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006914 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006915 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006916 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006917#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6918 case TARGET_NR_name_to_handle_at:
6919 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6920 break;
6921#endif
6922#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6923 case TARGET_NR_open_by_handle_at:
6924 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006925 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006926 break;
6927#endif
bellard31e31b82003-02-18 22:55:36 +00006928 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006929 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006930 ret = get_errno(close(arg1));
6931 break;
6932 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006933 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006934 break;
Chen Gang704eff62015-08-21 05:37:33 +08006935#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006936 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006937 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006938 break;
Chen Gang704eff62015-08-21 05:37:33 +08006939#endif
thse5febef2007-04-01 18:31:35 +00006940#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006941 case TARGET_NR_waitpid:
6942 {
pbrook53a59602006-03-25 19:31:22 +00006943 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006944 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006945 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006946 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006947 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006948 }
6949 break;
thse5febef2007-04-01 18:31:35 +00006950#endif
pbrookf0cbb612008-05-30 18:20:05 +00006951#ifdef TARGET_NR_waitid
6952 case TARGET_NR_waitid:
6953 {
6954 siginfo_t info;
6955 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006956 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006957 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006958 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006959 goto efault;
6960 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006961 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006962 }
6963 }
6964 break;
6965#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006966#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006967 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006968 if (!(p = lock_user_string(arg1)))
6969 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006970 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006971 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006972 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006973 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006974#endif
Chen Gang704eff62015-08-21 05:37:33 +08006975#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006976 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006977 {
6978 void * p2;
6979 p = lock_user_string(arg1);
6980 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006981 if (!p || !p2)
6982 ret = -TARGET_EFAULT;
6983 else
6984 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006985 unlock_user(p2, arg2, 0);
6986 unlock_user(p, arg1, 0);
6987 }
bellard31e31b82003-02-18 22:55:36 +00006988 break;
Chen Gang704eff62015-08-21 05:37:33 +08006989#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006990#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006991 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006992 {
6993 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006994 if (!arg2 || !arg4)
6995 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006996 p = lock_user_string(arg2);
6997 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006998 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006999 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007000 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007001 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007002 unlock_user(p, arg2, 0);
7003 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007004 }
7005 break;
7006#endif
Chen Gang704eff62015-08-21 05:37:33 +08007007#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007008 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007009 if (!(p = lock_user_string(arg1)))
7010 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007011 ret = get_errno(unlink(p));
7012 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007013 break;
Chen Gang704eff62015-08-21 05:37:33 +08007014#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007015#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007016 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007017 if (!(p = lock_user_string(arg2)))
7018 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007019 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007020 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007021 break;
balrogb7d35e62007-12-12 00:40:24 +00007022#endif
bellard31e31b82003-02-18 22:55:36 +00007023 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007024 {
7025 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007026 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007027 abi_ulong gp;
7028 abi_ulong guest_argp;
7029 abi_ulong guest_envp;
7030 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007031 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007032 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007033
bellardf7341ff2003-03-30 21:00:25 +00007034 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007035 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007036 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007037 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007038 goto efault;
ths03aa1972007-12-02 06:28:08 +00007039 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007040 break;
bellard7854b052003-03-29 17:22:23 +00007041 argc++;
bellard2f619692007-11-16 10:46:05 +00007042 }
bellardf7341ff2003-03-30 21:00:25 +00007043 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007044 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007045 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007046 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007047 goto efault;
ths03aa1972007-12-02 06:28:08 +00007048 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007049 break;
bellard7854b052003-03-29 17:22:23 +00007050 envc++;
bellard2f619692007-11-16 10:46:05 +00007051 }
bellard7854b052003-03-29 17:22:23 +00007052
bellardf7341ff2003-03-30 21:00:25 +00007053 argp = alloca((argc + 1) * sizeof(void *));
7054 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007055
pbrookda94d262008-05-30 18:24:00 +00007056 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007057 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007058 if (get_user_ual(addr, gp))
7059 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007060 if (!addr)
7061 break;
bellard2f619692007-11-16 10:46:05 +00007062 if (!(*q = lock_user_string(addr)))
7063 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007064 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007065 }
bellardf7341ff2003-03-30 21:00:25 +00007066 *q = NULL;
7067
pbrookda94d262008-05-30 18:24:00 +00007068 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007069 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007070 if (get_user_ual(addr, gp))
7071 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007072 if (!addr)
7073 break;
bellard2f619692007-11-16 10:46:05 +00007074 if (!(*q = lock_user_string(addr)))
7075 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007076 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007077 }
bellardf7341ff2003-03-30 21:00:25 +00007078 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007079
bellard2f619692007-11-16 10:46:05 +00007080 if (!(p = lock_user_string(arg1)))
7081 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007082 /* Although execve() is not an interruptible syscall it is
7083 * a special case where we must use the safe_syscall wrapper:
7084 * if we allow a signal to happen before we make the host
7085 * syscall then we will 'lose' it, because at the point of
7086 * execve the process leaves QEMU's control. So we use the
7087 * safe syscall wrapper to ensure that we either take the
7088 * signal as a guest signal, or else it does not happen
7089 * before the execve completes and makes it the other
7090 * program's problem.
7091 */
7092 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007093 unlock_user(p, arg1, 0);
7094
bellard2f619692007-11-16 10:46:05 +00007095 goto execve_end;
7096
7097 execve_efault:
7098 ret = -TARGET_EFAULT;
7099
7100 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007101 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007102 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007103 if (get_user_ual(addr, gp)
7104 || !addr)
7105 break;
pbrook53a59602006-03-25 19:31:22 +00007106 unlock_user(*q, addr, 0);
7107 }
7108 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007109 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007110 if (get_user_ual(addr, gp)
7111 || !addr)
7112 break;
pbrook53a59602006-03-25 19:31:22 +00007113 unlock_user(*q, addr, 0);
7114 }
bellard7854b052003-03-29 17:22:23 +00007115 }
bellard31e31b82003-02-18 22:55:36 +00007116 break;
7117 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007118 if (!(p = lock_user_string(arg1)))
7119 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007120 ret = get_errno(chdir(p));
7121 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007122 break;
bellarda315a142005-01-30 22:59:18 +00007123#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007124 case TARGET_NR_time:
7125 {
pbrook53a59602006-03-25 19:31:22 +00007126 time_t host_time;
7127 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007128 if (!is_error(ret)
7129 && arg1
7130 && put_user_sal(host_time, arg1))
7131 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007132 }
7133 break;
bellarda315a142005-01-30 22:59:18 +00007134#endif
Chen Gang704eff62015-08-21 05:37:33 +08007135#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007136 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007137 if (!(p = lock_user_string(arg1)))
7138 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007139 ret = get_errno(mknod(p, arg2, arg3));
7140 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007141 break;
Chen Gang704eff62015-08-21 05:37:33 +08007142#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007143#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007144 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007145 if (!(p = lock_user_string(arg2)))
7146 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007147 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007148 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007149 break;
7150#endif
Chen Gang704eff62015-08-21 05:37:33 +08007151#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007152 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007153 if (!(p = lock_user_string(arg1)))
7154 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007155 ret = get_errno(chmod(p, arg2));
7156 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007157 break;
Chen Gang704eff62015-08-21 05:37:33 +08007158#endif
bellardebc05482003-09-30 21:08:41 +00007159#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007160 case TARGET_NR_break:
7161 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007162#endif
7163#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007164 case TARGET_NR_oldstat:
7165 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007166#endif
bellard31e31b82003-02-18 22:55:36 +00007167 case TARGET_NR_lseek:
7168 ret = get_errno(lseek(arg1, arg2, arg3));
7169 break;
Richard Henderson92317332010-05-03 10:07:53 -07007170#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7171 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007172 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007173 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007174 ret = get_errno(getpid());
7175 break;
Richard Henderson92317332010-05-03 10:07:53 -07007176#endif
7177#ifdef TARGET_NR_getpid
7178 case TARGET_NR_getpid:
7179 ret = get_errno(getpid());
7180 break;
7181#endif
bellard31e31b82003-02-18 22:55:36 +00007182 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007183 {
7184 /* need to look at the data field */
7185 void *p2, *p3;
7186
7187 if (arg1) {
7188 p = lock_user_string(arg1);
7189 if (!p) {
7190 goto efault;
7191 }
7192 } else {
7193 p = NULL;
7194 }
7195
7196 p2 = lock_user_string(arg2);
7197 if (!p2) {
7198 if (arg1) {
7199 unlock_user(p, arg1, 0);
7200 }
7201 goto efault;
7202 }
7203
7204 if (arg3) {
7205 p3 = lock_user_string(arg3);
7206 if (!p3) {
7207 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007208 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007209 }
7210 unlock_user(p2, arg2, 0);
7211 goto efault;
7212 }
7213 } else {
7214 p3 = NULL;
7215 }
7216
7217 /* FIXME - arg5 should be locked, but it isn't clear how to
7218 * do that since it's not guaranteed to be a NULL-terminated
7219 * string.
7220 */
7221 if (!arg5) {
7222 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7223 } else {
7224 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7225 }
7226 ret = get_errno(ret);
7227
7228 if (arg1) {
7229 unlock_user(p, arg1, 0);
7230 }
7231 unlock_user(p2, arg2, 0);
7232 if (arg3) {
7233 unlock_user(p3, arg3, 0);
7234 }
7235 }
7236 break;
thse5febef2007-04-01 18:31:35 +00007237#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007238 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007239 if (!(p = lock_user_string(arg1)))
7240 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007241 ret = get_errno(umount(p));
7242 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007243 break;
thse5febef2007-04-01 18:31:35 +00007244#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007245#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007246 case TARGET_NR_stime:
7247 {
pbrook53a59602006-03-25 19:31:22 +00007248 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007249 if (get_user_sal(host_time, arg1))
7250 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007251 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007252 }
7253 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007254#endif
bellard31e31b82003-02-18 22:55:36 +00007255 case TARGET_NR_ptrace:
7256 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007257#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007258 case TARGET_NR_alarm:
7259 ret = alarm(arg1);
7260 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007261#endif
bellardebc05482003-09-30 21:08:41 +00007262#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007263 case TARGET_NR_oldfstat:
7264 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007265#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007266#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007267 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007268 if (!block_signals()) {
7269 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7270 }
7271 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007272 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007273#endif
thse5febef2007-04-01 18:31:35 +00007274#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007275 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007276 {
pbrook53a59602006-03-25 19:31:22 +00007277 struct utimbuf tbuf, *host_tbuf;
7278 struct target_utimbuf *target_tbuf;
7279 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007280 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7281 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007282 tbuf.actime = tswapal(target_tbuf->actime);
7283 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007284 unlock_user_struct(target_tbuf, arg2, 0);
7285 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007286 } else {
pbrook53a59602006-03-25 19:31:22 +00007287 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007288 }
bellard579a97f2007-11-11 14:26:47 +00007289 if (!(p = lock_user_string(arg1)))
7290 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007291 ret = get_errno(utime(p, host_tbuf));
7292 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007293 }
7294 break;
thse5febef2007-04-01 18:31:35 +00007295#endif
Chen Gang704eff62015-08-21 05:37:33 +08007296#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007297 case TARGET_NR_utimes:
7298 {
bellard978a66f2004-12-06 22:58:05 +00007299 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007300 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007301 if (copy_from_user_timeval(&tv[0], arg2)
7302 || copy_from_user_timeval(&tv[1],
7303 arg2 + sizeof(struct target_timeval)))
7304 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007305 tvp = tv;
7306 } else {
7307 tvp = NULL;
7308 }
bellard579a97f2007-11-11 14:26:47 +00007309 if (!(p = lock_user_string(arg1)))
7310 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007311 ret = get_errno(utimes(p, tvp));
7312 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007313 }
7314 break;
Chen Gang704eff62015-08-21 05:37:33 +08007315#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007316#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007317 case TARGET_NR_futimesat:
7318 {
7319 struct timeval *tvp, tv[2];
7320 if (arg3) {
7321 if (copy_from_user_timeval(&tv[0], arg3)
7322 || copy_from_user_timeval(&tv[1],
7323 arg3 + sizeof(struct target_timeval)))
7324 goto efault;
7325 tvp = tv;
7326 } else {
7327 tvp = NULL;
7328 }
7329 if (!(p = lock_user_string(arg2)))
7330 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007331 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007332 unlock_user(p, arg2, 0);
7333 }
7334 break;
7335#endif
bellardebc05482003-09-30 21:08:41 +00007336#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007337 case TARGET_NR_stty:
7338 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007339#endif
7340#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007341 case TARGET_NR_gtty:
7342 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007343#endif
Chen Gang704eff62015-08-21 05:37:33 +08007344#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007345 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007346 if (!(p = lock_user_string(arg1)))
7347 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007348 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007349 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007350 break;
Chen Gang704eff62015-08-21 05:37:33 +08007351#endif
ths92a34c12007-09-24 09:27:49 +00007352#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7353 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007354 if (!(p = lock_user_string(arg2)))
7355 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007356 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007357 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007358 break;
7359#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007360#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007361 case TARGET_NR_nice:
7362 ret = get_errno(nice(arg1));
7363 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007364#endif
bellardebc05482003-09-30 21:08:41 +00007365#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007366 case TARGET_NR_ftime:
7367 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007368#endif
bellard31e31b82003-02-18 22:55:36 +00007369 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007370 sync();
7371 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007372 break;
7373 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007374 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007375 break;
Chen Gang704eff62015-08-21 05:37:33 +08007376#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007377 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007378 {
7379 void *p2;
7380 p = lock_user_string(arg1);
7381 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007382 if (!p || !p2)
7383 ret = -TARGET_EFAULT;
7384 else
7385 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007386 unlock_user(p2, arg2, 0);
7387 unlock_user(p, arg1, 0);
7388 }
bellard31e31b82003-02-18 22:55:36 +00007389 break;
Chen Gang704eff62015-08-21 05:37:33 +08007390#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007391#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007392 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007393 {
bellard579a97f2007-11-11 14:26:47 +00007394 void *p2;
ths722183f2007-09-24 09:24:37 +00007395 p = lock_user_string(arg2);
7396 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007397 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007398 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007399 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007400 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007401 unlock_user(p2, arg4, 0);
7402 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007403 }
7404 break;
7405#endif
Chen Gang704eff62015-08-21 05:37:33 +08007406#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007407 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007408 if (!(p = lock_user_string(arg1)))
7409 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007410 ret = get_errno(mkdir(p, arg2));
7411 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007412 break;
Chen Gang704eff62015-08-21 05:37:33 +08007413#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007414#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007415 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007416 if (!(p = lock_user_string(arg2)))
7417 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007418 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007419 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007420 break;
7421#endif
Chen Gang704eff62015-08-21 05:37:33 +08007422#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007423 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007424 if (!(p = lock_user_string(arg1)))
7425 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007426 ret = get_errno(rmdir(p));
7427 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007428 break;
Chen Gang704eff62015-08-21 05:37:33 +08007429#endif
bellard31e31b82003-02-18 22:55:36 +00007430 case TARGET_NR_dup:
7431 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007432 if (ret >= 0) {
7433 fd_trans_dup(arg1, ret);
7434 }
bellard31e31b82003-02-18 22:55:36 +00007435 break;
Chen Gang704eff62015-08-21 05:37:33 +08007436#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007437 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007438 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007439 break;
Chen Gang704eff62015-08-21 05:37:33 +08007440#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007441#ifdef TARGET_NR_pipe2
7442 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007443 ret = do_pipe(cpu_env, arg1,
7444 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007445 break;
7446#endif
bellard31e31b82003-02-18 22:55:36 +00007447 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007448 {
pbrook53a59602006-03-25 19:31:22 +00007449 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007450 struct tms tms;
7451 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007452 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007453 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7454 if (!tmsp)
7455 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007456 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7457 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7458 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7459 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007460 }
bellardc596ed12003-07-13 17:32:31 +00007461 if (!is_error(ret))
7462 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007463 }
7464 break;
bellardebc05482003-09-30 21:08:41 +00007465#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007466 case TARGET_NR_prof:
7467 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007468#endif
thse5febef2007-04-01 18:31:35 +00007469#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007470 case TARGET_NR_signal:
7471 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007472#endif
bellard31e31b82003-02-18 22:55:36 +00007473 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007474 if (arg1 == 0) {
7475 ret = get_errno(acct(NULL));
7476 } else {
7477 if (!(p = lock_user_string(arg1)))
7478 goto efault;
7479 ret = get_errno(acct(path(p)));
7480 unlock_user(p, arg1, 0);
7481 }
pbrook24836682006-04-16 14:14:53 +00007482 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007483#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007484 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007485 if (!(p = lock_user_string(arg1)))
7486 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007487 ret = get_errno(umount2(p, arg2));
7488 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007489 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007490#endif
bellardebc05482003-09-30 21:08:41 +00007491#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007492 case TARGET_NR_lock:
7493 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007494#endif
bellard31e31b82003-02-18 22:55:36 +00007495 case TARGET_NR_ioctl:
7496 ret = do_ioctl(arg1, arg2, arg3);
7497 break;
7498 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007499 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007500 break;
bellardebc05482003-09-30 21:08:41 +00007501#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007502 case TARGET_NR_mpx:
7503 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007504#endif
bellard31e31b82003-02-18 22:55:36 +00007505 case TARGET_NR_setpgid:
7506 ret = get_errno(setpgid(arg1, arg2));
7507 break;
bellardebc05482003-09-30 21:08:41 +00007508#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007509 case TARGET_NR_ulimit:
7510 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007511#endif
7512#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007513 case TARGET_NR_oldolduname:
7514 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007515#endif
bellard31e31b82003-02-18 22:55:36 +00007516 case TARGET_NR_umask:
7517 ret = get_errno(umask(arg1));
7518 break;
7519 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007520 if (!(p = lock_user_string(arg1)))
7521 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007522 ret = get_errno(chroot(p));
7523 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007524 break;
Chen Gang704eff62015-08-21 05:37:33 +08007525#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007526 case TARGET_NR_ustat:
7527 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007528#endif
7529#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007530 case TARGET_NR_dup2:
7531 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007532 if (ret >= 0) {
7533 fd_trans_dup(arg1, arg2);
7534 }
bellard31e31b82003-02-18 22:55:36 +00007535 break;
Chen Gang704eff62015-08-21 05:37:33 +08007536#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007537#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7538 case TARGET_NR_dup3:
7539 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007540 if (ret >= 0) {
7541 fd_trans_dup(arg1, arg2);
7542 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007543 break;
7544#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007545#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007546 case TARGET_NR_getppid:
7547 ret = get_errno(getppid());
7548 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007549#endif
Chen Gang704eff62015-08-21 05:37:33 +08007550#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007551 case TARGET_NR_getpgrp:
7552 ret = get_errno(getpgrp());
7553 break;
Chen Gang704eff62015-08-21 05:37:33 +08007554#endif
bellard31e31b82003-02-18 22:55:36 +00007555 case TARGET_NR_setsid:
7556 ret = get_errno(setsid());
7557 break;
thse5febef2007-04-01 18:31:35 +00007558#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007559 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007560 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007561#if defined(TARGET_ALPHA)
7562 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007563 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007564 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007565 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7566 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007567 act._sa_handler = old_act->_sa_handler;
7568 target_siginitset(&act.sa_mask, old_act->sa_mask);
7569 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007570 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007571 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007572 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007573 }
7574 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007575 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007576 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7577 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007578 old_act->_sa_handler = oact._sa_handler;
7579 old_act->sa_mask = oact.sa_mask.sig[0];
7580 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007581 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007582 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007583#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007584 struct target_sigaction act, oact, *pact, *old_act;
7585
7586 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007587 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7588 goto efault;
bellard106ec872006-06-27 21:08:10 +00007589 act._sa_handler = old_act->_sa_handler;
7590 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7591 act.sa_flags = old_act->sa_flags;
7592 unlock_user_struct(old_act, arg2, 0);
7593 pact = &act;
7594 } else {
7595 pact = NULL;
7596 }
7597
7598 ret = get_errno(do_sigaction(arg1, pact, &oact));
7599
7600 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007601 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7602 goto efault;
bellard106ec872006-06-27 21:08:10 +00007603 old_act->_sa_handler = oact._sa_handler;
7604 old_act->sa_flags = oact.sa_flags;
7605 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7606 old_act->sa_mask.sig[1] = 0;
7607 old_act->sa_mask.sig[2] = 0;
7608 old_act->sa_mask.sig[3] = 0;
7609 unlock_user_struct(old_act, arg3, 1);
7610 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007611#else
7612 struct target_old_sigaction *old_act;
7613 struct target_sigaction act, oact, *pact;
7614 if (arg2) {
7615 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7616 goto efault;
7617 act._sa_handler = old_act->_sa_handler;
7618 target_siginitset(&act.sa_mask, old_act->sa_mask);
7619 act.sa_flags = old_act->sa_flags;
7620 act.sa_restorer = old_act->sa_restorer;
7621 unlock_user_struct(old_act, arg2, 0);
7622 pact = &act;
7623 } else {
7624 pact = NULL;
7625 }
7626 ret = get_errno(do_sigaction(arg1, pact, &oact));
7627 if (!is_error(ret) && arg3) {
7628 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7629 goto efault;
7630 old_act->_sa_handler = oact._sa_handler;
7631 old_act->sa_mask = oact.sa_mask.sig[0];
7632 old_act->sa_flags = oact.sa_flags;
7633 old_act->sa_restorer = oact.sa_restorer;
7634 unlock_user_struct(old_act, arg3, 1);
7635 }
ths388bb212007-05-13 13:58:00 +00007636#endif
bellard31e31b82003-02-18 22:55:36 +00007637 }
7638 break;
thse5febef2007-04-01 18:31:35 +00007639#endif
bellard66fb9762003-03-23 01:06:05 +00007640 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007641 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007642#if defined(TARGET_ALPHA)
7643 struct target_sigaction act, oact, *pact = 0;
7644 struct target_rt_sigaction *rt_act;
7645 /* ??? arg4 == sizeof(sigset_t). */
7646 if (arg2) {
7647 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7648 goto efault;
7649 act._sa_handler = rt_act->_sa_handler;
7650 act.sa_mask = rt_act->sa_mask;
7651 act.sa_flags = rt_act->sa_flags;
7652 act.sa_restorer = arg5;
7653 unlock_user_struct(rt_act, arg2, 0);
7654 pact = &act;
7655 }
7656 ret = get_errno(do_sigaction(arg1, pact, &oact));
7657 if (!is_error(ret) && arg3) {
7658 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7659 goto efault;
7660 rt_act->_sa_handler = oact._sa_handler;
7661 rt_act->sa_mask = oact.sa_mask;
7662 rt_act->sa_flags = oact.sa_flags;
7663 unlock_user_struct(rt_act, arg3, 1);
7664 }
7665#else
pbrook53a59602006-03-25 19:31:22 +00007666 struct target_sigaction *act;
7667 struct target_sigaction *oact;
7668
bellard579a97f2007-11-11 14:26:47 +00007669 if (arg2) {
7670 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7671 goto efault;
7672 } else
pbrook53a59602006-03-25 19:31:22 +00007673 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007674 if (arg3) {
7675 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7676 ret = -TARGET_EFAULT;
7677 goto rt_sigaction_fail;
7678 }
7679 } else
pbrook53a59602006-03-25 19:31:22 +00007680 oact = NULL;
7681 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007682 rt_sigaction_fail:
7683 if (act)
pbrook53a59602006-03-25 19:31:22 +00007684 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007685 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007686 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007687#endif
pbrook53a59602006-03-25 19:31:22 +00007688 }
bellard66fb9762003-03-23 01:06:05 +00007689 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007690#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007691 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007692 {
7693 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007694 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007695 ret = do_sigprocmask(0, NULL, &cur_set);
7696 if (!ret) {
7697 host_to_target_old_sigset(&target_set, &cur_set);
7698 ret = target_set;
7699 }
bellard66fb9762003-03-23 01:06:05 +00007700 }
7701 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007702#endif
7703#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007704 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007705 {
7706 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007707 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007708 /* We only have one word of the new mask so we must read
7709 * the rest of it with do_sigprocmask() and OR in this word.
7710 * We are guaranteed that a do_sigprocmask() that only queries
7711 * the signal mask will not fail.
7712 */
7713 ret = do_sigprocmask(0, NULL, &cur_set);
7714 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00007715 target_to_host_old_sigset(&set, &target_set);
7716 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007717 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7718 if (!ret) {
7719 host_to_target_old_sigset(&target_set, &oset);
7720 ret = target_set;
7721 }
bellard66fb9762003-03-23 01:06:05 +00007722 }
7723 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007724#endif
thse5febef2007-04-01 18:31:35 +00007725#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007726 case TARGET_NR_sigprocmask:
7727 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007728#if defined(TARGET_ALPHA)
7729 sigset_t set, oldset;
7730 abi_ulong mask;
7731 int how;
7732
7733 switch (arg1) {
7734 case TARGET_SIG_BLOCK:
7735 how = SIG_BLOCK;
7736 break;
7737 case TARGET_SIG_UNBLOCK:
7738 how = SIG_UNBLOCK;
7739 break;
7740 case TARGET_SIG_SETMASK:
7741 how = SIG_SETMASK;
7742 break;
7743 default:
7744 ret = -TARGET_EINVAL;
7745 goto fail;
7746 }
7747 mask = arg2;
7748 target_to_host_old_sigset(&set, &mask);
7749
Peter Maydell3d3efba2016-05-27 15:51:49 +01007750 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007751 if (!is_error(ret)) {
7752 host_to_target_old_sigset(&mask, &oldset);
7753 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007754 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007755 }
7756#else
bellard66fb9762003-03-23 01:06:05 +00007757 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007758 int how;
ths3b46e622007-09-17 08:09:54 +00007759
pbrook53a59602006-03-25 19:31:22 +00007760 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007761 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007762 case TARGET_SIG_BLOCK:
7763 how = SIG_BLOCK;
7764 break;
7765 case TARGET_SIG_UNBLOCK:
7766 how = SIG_UNBLOCK;
7767 break;
7768 case TARGET_SIG_SETMASK:
7769 how = SIG_SETMASK;
7770 break;
7771 default:
ths0da46a62007-10-20 20:23:07 +00007772 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007773 goto fail;
7774 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007775 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007776 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007777 target_to_host_old_sigset(&set, p);
7778 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007779 set_ptr = &set;
7780 } else {
7781 how = 0;
7782 set_ptr = NULL;
7783 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007784 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007785 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007786 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007787 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007788 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007789 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007790 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007791#endif
bellard66fb9762003-03-23 01:06:05 +00007792 }
7793 break;
thse5febef2007-04-01 18:31:35 +00007794#endif
bellard66fb9762003-03-23 01:06:05 +00007795 case TARGET_NR_rt_sigprocmask:
7796 {
7797 int how = arg1;
7798 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007799
pbrook53a59602006-03-25 19:31:22 +00007800 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007801 switch(how) {
7802 case TARGET_SIG_BLOCK:
7803 how = SIG_BLOCK;
7804 break;
7805 case TARGET_SIG_UNBLOCK:
7806 how = SIG_UNBLOCK;
7807 break;
7808 case TARGET_SIG_SETMASK:
7809 how = SIG_SETMASK;
7810 break;
7811 default:
ths0da46a62007-10-20 20:23:07 +00007812 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007813 goto fail;
7814 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007815 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007816 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007817 target_to_host_sigset(&set, p);
7818 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007819 set_ptr = &set;
7820 } else {
7821 how = 0;
7822 set_ptr = NULL;
7823 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007824 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007825 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007826 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007827 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007828 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007829 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007830 }
7831 }
7832 break;
thse5febef2007-04-01 18:31:35 +00007833#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007834 case TARGET_NR_sigpending:
7835 {
7836 sigset_t set;
7837 ret = get_errno(sigpending(&set));
7838 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007839 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007840 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007841 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007842 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007843 }
7844 }
7845 break;
thse5febef2007-04-01 18:31:35 +00007846#endif
bellard66fb9762003-03-23 01:06:05 +00007847 case TARGET_NR_rt_sigpending:
7848 {
7849 sigset_t set;
7850 ret = get_errno(sigpending(&set));
7851 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007852 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007853 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007854 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007855 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007856 }
7857 }
7858 break;
thse5febef2007-04-01 18:31:35 +00007859#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007860 case TARGET_NR_sigsuspend:
7861 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007862 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007863#if defined(TARGET_ALPHA)
7864 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007865 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007866#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007867 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007868 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007869 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007870 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007871#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01007872 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7873 SIGSET_T_SIZE));
7874 if (ret != -TARGET_ERESTARTSYS) {
7875 ts->in_sigsuspend = 1;
7876 }
bellard66fb9762003-03-23 01:06:05 +00007877 }
7878 break;
thse5febef2007-04-01 18:31:35 +00007879#endif
bellard66fb9762003-03-23 01:06:05 +00007880 case TARGET_NR_rt_sigsuspend:
7881 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007882 TaskState *ts = cpu->opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05007883 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007884 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007885 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007886 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007887 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7888 SIGSET_T_SIZE));
7889 if (ret != -TARGET_ERESTARTSYS) {
7890 ts->in_sigsuspend = 1;
7891 }
bellard66fb9762003-03-23 01:06:05 +00007892 }
7893 break;
7894 case TARGET_NR_rt_sigtimedwait:
7895 {
bellard66fb9762003-03-23 01:06:05 +00007896 sigset_t set;
7897 struct timespec uts, *puts;
7898 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007899
Anthony Liguoric227f092009-10-01 16:12:16 -05007900 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007901 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007902 target_to_host_sigset(&set, p);
7903 unlock_user(p, arg1, 0);
7904 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007905 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007906 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007907 } else {
7908 puts = NULL;
7909 }
Peter Maydellb3f82332016-06-06 19:58:08 +01007910 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
7911 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007912 if (!is_error(ret)) {
7913 if (arg2) {
7914 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7915 0);
7916 if (!p) {
7917 goto efault;
7918 }
7919 host_to_target_siginfo(p, &uinfo);
7920 unlock_user(p, arg2, sizeof(target_siginfo_t));
7921 }
7922 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007923 }
7924 }
7925 break;
7926 case TARGET_NR_rt_sigqueueinfo:
7927 {
7928 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01007929
7930 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
7931 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00007932 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01007933 }
pbrook53a59602006-03-25 19:31:22 +00007934 target_to_host_siginfo(&uinfo, p);
7935 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007936 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7937 }
7938 break;
thse5febef2007-04-01 18:31:35 +00007939#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007940 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007941 if (block_signals()) {
7942 ret = -TARGET_ERESTARTSYS;
7943 } else {
7944 ret = do_sigreturn(cpu_env);
7945 }
bellard66fb9762003-03-23 01:06:05 +00007946 break;
thse5febef2007-04-01 18:31:35 +00007947#endif
bellard66fb9762003-03-23 01:06:05 +00007948 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007949 if (block_signals()) {
7950 ret = -TARGET_ERESTARTSYS;
7951 } else {
7952 ret = do_rt_sigreturn(cpu_env);
7953 }
bellard66fb9762003-03-23 01:06:05 +00007954 break;
bellard31e31b82003-02-18 22:55:36 +00007955 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007956 if (!(p = lock_user_string(arg1)))
7957 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007958 ret = get_errno(sethostname(p, arg2));
7959 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007960 break;
7961 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007962 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007963 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007964 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007965 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007966 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7967 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007968 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7969 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007970 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007971 ret = get_errno(setrlimit(resource, &rlim));
7972 }
7973 break;
bellard31e31b82003-02-18 22:55:36 +00007974 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007975 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007976 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007977 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007978 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007979
bellard9de5e442003-03-23 16:49:39 +00007980 ret = get_errno(getrlimit(resource, &rlim));
7981 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007982 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7983 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007984 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7985 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007986 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007987 }
7988 }
7989 break;
bellard31e31b82003-02-18 22:55:36 +00007990 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007991 {
7992 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007993 ret = get_errno(getrusage(arg1, &rusage));
7994 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007995 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007996 }
7997 }
7998 break;
bellard31e31b82003-02-18 22:55:36 +00007999 case TARGET_NR_gettimeofday:
8000 {
bellard31e31b82003-02-18 22:55:36 +00008001 struct timeval tv;
8002 ret = get_errno(gettimeofday(&tv, NULL));
8003 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008004 if (copy_to_user_timeval(arg1, &tv))
8005 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008006 }
8007 }
8008 break;
8009 case TARGET_NR_settimeofday:
8010 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008011 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008012 struct timezone tz, *ptz = NULL;
8013
Paul Burtonb67d8032014-06-22 11:25:41 +01008014 if (arg1) {
8015 if (copy_from_user_timeval(&tv, arg1)) {
8016 goto efault;
8017 }
8018 ptv = &tv;
8019 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008020
8021 if (arg2) {
8022 if (copy_from_user_timezone(&tz, arg2)) {
8023 goto efault;
8024 }
8025 ptz = &tz;
8026 }
8027
Paul Burtonb67d8032014-06-22 11:25:41 +01008028 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008029 }
8030 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008031#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008032 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008033#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
8034 ret = do_select(arg1, arg2, arg3, arg4, arg5);
8035#else
bellardf2674e32003-07-09 12:26:09 +00008036 {
pbrook53a59602006-03-25 19:31:22 +00008037 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00008038 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00008039 long nsel;
8040
bellard579a97f2007-11-11 14:26:47 +00008041 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
8042 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008043 nsel = tswapal(sel->n);
8044 inp = tswapal(sel->inp);
8045 outp = tswapal(sel->outp);
8046 exp = tswapal(sel->exp);
8047 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00008048 unlock_user_struct(sel, arg1, 0);
8049 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00008050 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008051#endif
bellardf2674e32003-07-09 12:26:09 +00008052 break;
bellard048f6b42005-11-26 18:47:20 +00008053#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008054#ifdef TARGET_NR_pselect6
8055 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008056 {
8057 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8058 fd_set rfds, wfds, efds;
8059 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8060 struct timespec ts, *ts_ptr;
8061
8062 /*
8063 * The 6th arg is actually two args smashed together,
8064 * so we cannot use the C library.
8065 */
8066 sigset_t set;
8067 struct {
8068 sigset_t *set;
8069 size_t size;
8070 } sig, *sig_ptr;
8071
8072 abi_ulong arg_sigset, arg_sigsize, *arg7;
8073 target_sigset_t *target_sigset;
8074
8075 n = arg1;
8076 rfd_addr = arg2;
8077 wfd_addr = arg3;
8078 efd_addr = arg4;
8079 ts_addr = arg5;
8080
8081 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8082 if (ret) {
8083 goto fail;
8084 }
8085 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8086 if (ret) {
8087 goto fail;
8088 }
8089 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8090 if (ret) {
8091 goto fail;
8092 }
8093
8094 /*
8095 * This takes a timespec, and not a timeval, so we cannot
8096 * use the do_select() helper ...
8097 */
8098 if (ts_addr) {
8099 if (target_to_host_timespec(&ts, ts_addr)) {
8100 goto efault;
8101 }
8102 ts_ptr = &ts;
8103 } else {
8104 ts_ptr = NULL;
8105 }
8106
8107 /* Extract the two packed args for the sigset */
8108 if (arg6) {
8109 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008110 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008111
8112 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8113 if (!arg7) {
8114 goto efault;
8115 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008116 arg_sigset = tswapal(arg7[0]);
8117 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008118 unlock_user(arg7, arg6, 0);
8119
8120 if (arg_sigset) {
8121 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008122 if (arg_sigsize != sizeof(*target_sigset)) {
8123 /* Like the kernel, we enforce correct size sigsets */
8124 ret = -TARGET_EINVAL;
8125 goto fail;
8126 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008127 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8128 sizeof(*target_sigset), 1);
8129 if (!target_sigset) {
8130 goto efault;
8131 }
8132 target_to_host_sigset(&set, target_sigset);
8133 unlock_user(target_sigset, arg_sigset, 0);
8134 } else {
8135 sig.set = NULL;
8136 }
8137 } else {
8138 sig_ptr = NULL;
8139 }
8140
Peter Maydell6df9d382016-05-12 18:47:51 +01008141 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8142 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008143
8144 if (!is_error(ret)) {
8145 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8146 goto efault;
8147 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8148 goto efault;
8149 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8150 goto efault;
8151
8152 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8153 goto efault;
8154 }
8155 }
8156 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008157#endif
Chen Gang704eff62015-08-21 05:37:33 +08008158#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008159 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008160 {
8161 void *p2;
8162 p = lock_user_string(arg1);
8163 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008164 if (!p || !p2)
8165 ret = -TARGET_EFAULT;
8166 else
8167 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008168 unlock_user(p2, arg2, 0);
8169 unlock_user(p, arg1, 0);
8170 }
bellard31e31b82003-02-18 22:55:36 +00008171 break;
Chen Gang704eff62015-08-21 05:37:33 +08008172#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008173#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008174 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008175 {
bellard579a97f2007-11-11 14:26:47 +00008176 void *p2;
thsf0b62432007-09-24 09:25:40 +00008177 p = lock_user_string(arg1);
8178 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008179 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008180 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008181 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008182 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008183 unlock_user(p2, arg3, 0);
8184 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008185 }
8186 break;
8187#endif
bellardebc05482003-09-30 21:08:41 +00008188#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008189 case TARGET_NR_oldlstat:
8190 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008191#endif
Chen Gang704eff62015-08-21 05:37:33 +08008192#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008193 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008194 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008195 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008196 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008197 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008198 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008199 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008200 } else if (!arg3) {
8201 /* Short circuit this for the magic exe check. */
8202 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008203 } else if (is_proc_myself((const char *)p, "exe")) {
8204 char real[PATH_MAX], *temp;
8205 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008206 /* Return value is # of bytes that we wrote to the buffer. */
8207 if (temp == NULL) {
8208 ret = get_errno(-1);
8209 } else {
8210 /* Don't worry about sign mismatch as earlier mapping
8211 * logic would have thrown a bad address error. */
8212 ret = MIN(strlen(real), arg3);
8213 /* We cannot NUL terminate the string. */
8214 memcpy(p2, real, ret);
8215 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008216 } else {
8217 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008218 }
pbrook53a59602006-03-25 19:31:22 +00008219 unlock_user(p2, arg2, ret);
8220 unlock_user(p, arg1, 0);
8221 }
bellard31e31b82003-02-18 22:55:36 +00008222 break;
Chen Gang704eff62015-08-21 05:37:33 +08008223#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008224#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008225 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008226 {
bellard579a97f2007-11-11 14:26:47 +00008227 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008228 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008229 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008230 if (!p || !p2) {
8231 ret = -TARGET_EFAULT;
8232 } else if (is_proc_myself((const char *)p, "exe")) {
8233 char real[PATH_MAX], *temp;
8234 temp = realpath(exec_path, real);
8235 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8236 snprintf((char *)p2, arg4, "%s", real);
8237 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008238 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008239 }
bellard579a97f2007-11-11 14:26:47 +00008240 unlock_user(p2, arg3, ret);
8241 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008242 }
8243 break;
8244#endif
thse5febef2007-04-01 18:31:35 +00008245#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008246 case TARGET_NR_uselib:
8247 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008248#endif
8249#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008250 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008251 if (!(p = lock_user_string(arg1)))
8252 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008253 ret = get_errno(swapon(p, arg2));
8254 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008255 break;
thse5febef2007-04-01 18:31:35 +00008256#endif
bellard31e31b82003-02-18 22:55:36 +00008257 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008258 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8259 /* arg4 must be ignored in all other cases */
8260 p = lock_user_string(arg4);
8261 if (!p) {
8262 goto efault;
8263 }
8264 ret = get_errno(reboot(arg1, arg2, arg3, p));
8265 unlock_user(p, arg4, 0);
8266 } else {
8267 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8268 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008269 break;
thse5febef2007-04-01 18:31:35 +00008270#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008271 case TARGET_NR_readdir:
8272 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008273#endif
8274#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008275 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008276#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8277 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008278 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8279 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008280 {
blueswir1992f48a2007-10-14 16:27:31 +00008281 abi_ulong *v;
8282 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008283 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8284 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008285 v1 = tswapal(v[0]);
8286 v2 = tswapal(v[1]);
8287 v3 = tswapal(v[2]);
8288 v4 = tswapal(v[3]);
8289 v5 = tswapal(v[4]);
8290 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008291 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008292 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008293 target_to_host_bitmask(v4, mmap_flags_tbl),
8294 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008295 }
bellard31e31b82003-02-18 22:55:36 +00008296#else
ths5fafdf22007-09-16 21:08:06 +00008297 ret = get_errno(target_mmap(arg1, arg2, arg3,
8298 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008299 arg5,
8300 arg6));
bellard31e31b82003-02-18 22:55:36 +00008301#endif
bellard6fb883e2003-07-09 17:12:39 +00008302 break;
thse5febef2007-04-01 18:31:35 +00008303#endif
bellarda315a142005-01-30 22:59:18 +00008304#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008305 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008306#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008307#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008308#endif
ths5fafdf22007-09-16 21:08:06 +00008309 ret = get_errno(target_mmap(arg1, arg2, arg3,
8310 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008311 arg5,
bellardc573ff62004-01-04 15:51:36 +00008312 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008313 break;
bellarda315a142005-01-30 22:59:18 +00008314#endif
bellard31e31b82003-02-18 22:55:36 +00008315 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008316 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008317 break;
bellard9de5e442003-03-23 16:49:39 +00008318 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008319 {
Andreas Färber0429a972013-08-26 18:14:44 +02008320 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008321 /* Special hack to detect libc making the stack executable. */
8322 if ((arg3 & PROT_GROWSDOWN)
8323 && arg1 >= ts->info->stack_limit
8324 && arg1 <= ts->info->start_stack) {
8325 arg3 &= ~PROT_GROWSDOWN;
8326 arg2 = arg2 + arg1 - ts->info->stack_limit;
8327 arg1 = ts->info->stack_limit;
8328 }
8329 }
bellard54936002003-05-13 00:25:15 +00008330 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008331 break;
thse5febef2007-04-01 18:31:35 +00008332#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008333 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008334 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008335 break;
thse5febef2007-04-01 18:31:35 +00008336#endif
pbrook53a59602006-03-25 19:31:22 +00008337 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008338#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008339 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008340 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008341 break;
thse5febef2007-04-01 18:31:35 +00008342#endif
8343#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008344 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008345 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008346 break;
thse5febef2007-04-01 18:31:35 +00008347#endif
8348#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008349 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008350 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008351 break;
thse5febef2007-04-01 18:31:35 +00008352#endif
8353#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008354 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008355 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008356 break;
thse5febef2007-04-01 18:31:35 +00008357#endif
8358#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008359 case TARGET_NR_munlockall:
8360 ret = get_errno(munlockall());
8361 break;
thse5febef2007-04-01 18:31:35 +00008362#endif
bellard31e31b82003-02-18 22:55:36 +00008363 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008364 if (!(p = lock_user_string(arg1)))
8365 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008366 ret = get_errno(truncate(p, arg2));
8367 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008368 break;
8369 case TARGET_NR_ftruncate:
8370 ret = get_errno(ftruncate(arg1, arg2));
8371 break;
8372 case TARGET_NR_fchmod:
8373 ret = get_errno(fchmod(arg1, arg2));
8374 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008375#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008376 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008377 if (!(p = lock_user_string(arg2)))
8378 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008379 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008380 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008381 break;
8382#endif
bellard31e31b82003-02-18 22:55:36 +00008383 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008384 /* Note that negative values are valid for getpriority, so we must
8385 differentiate based on errno settings. */
8386 errno = 0;
8387 ret = getpriority(arg1, arg2);
8388 if (ret == -1 && errno != 0) {
8389 ret = -host_to_target_errno(errno);
8390 break;
8391 }
8392#ifdef TARGET_ALPHA
8393 /* Return value is the unbiased priority. Signal no error. */
8394 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8395#else
8396 /* Return value is a biased priority to avoid negative numbers. */
8397 ret = 20 - ret;
8398#endif
bellard31e31b82003-02-18 22:55:36 +00008399 break;
8400 case TARGET_NR_setpriority:
8401 ret = get_errno(setpriority(arg1, arg2, arg3));
8402 break;
bellardebc05482003-09-30 21:08:41 +00008403#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008404 case TARGET_NR_profil:
8405 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008406#endif
bellard31e31b82003-02-18 22:55:36 +00008407 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008408 if (!(p = lock_user_string(arg1)))
8409 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008410 ret = get_errno(statfs(path(p), &stfs));
8411 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008412 convert_statfs:
8413 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008414 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008415
bellard579a97f2007-11-11 14:26:47 +00008416 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8417 goto efault;
8418 __put_user(stfs.f_type, &target_stfs->f_type);
8419 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8420 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8421 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8422 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8423 __put_user(stfs.f_files, &target_stfs->f_files);
8424 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8425 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8426 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8427 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008428 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8429 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008430 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008431 }
8432 break;
8433 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008434 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008435 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008436#ifdef TARGET_NR_statfs64
8437 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008438 if (!(p = lock_user_string(arg1)))
8439 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008440 ret = get_errno(statfs(path(p), &stfs));
8441 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008442 convert_statfs64:
8443 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008444 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008445
bellard579a97f2007-11-11 14:26:47 +00008446 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8447 goto efault;
8448 __put_user(stfs.f_type, &target_stfs->f_type);
8449 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8450 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8451 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8452 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8453 __put_user(stfs.f_files, &target_stfs->f_files);
8454 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8455 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8456 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8457 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008458 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8459 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008460 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008461 }
8462 break;
8463 case TARGET_NR_fstatfs64:
8464 ret = get_errno(fstatfs(arg1, &stfs));
8465 goto convert_statfs64;
8466#endif
bellardebc05482003-09-30 21:08:41 +00008467#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008468 case TARGET_NR_ioperm:
8469 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008470#endif
thse5febef2007-04-01 18:31:35 +00008471#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008472 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008473 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008474 break;
thse5febef2007-04-01 18:31:35 +00008475#endif
bellard3532fa72006-06-24 15:06:03 +00008476#ifdef TARGET_NR_accept
8477 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008478 ret = do_accept4(arg1, arg2, arg3, 0);
8479 break;
8480#endif
8481#ifdef TARGET_NR_accept4
8482 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00008483 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008484 break;
8485#endif
8486#ifdef TARGET_NR_bind
8487 case TARGET_NR_bind:
8488 ret = do_bind(arg1, arg2, arg3);
8489 break;
8490#endif
8491#ifdef TARGET_NR_connect
8492 case TARGET_NR_connect:
8493 ret = do_connect(arg1, arg2, arg3);
8494 break;
8495#endif
8496#ifdef TARGET_NR_getpeername
8497 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008498 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008499 break;
8500#endif
8501#ifdef TARGET_NR_getsockname
8502 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008503 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008504 break;
8505#endif
8506#ifdef TARGET_NR_getsockopt
8507 case TARGET_NR_getsockopt:
8508 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8509 break;
8510#endif
8511#ifdef TARGET_NR_listen
8512 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008513 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008514 break;
8515#endif
8516#ifdef TARGET_NR_recv
8517 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008518 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008519 break;
8520#endif
8521#ifdef TARGET_NR_recvfrom
8522 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008523 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008524 break;
8525#endif
8526#ifdef TARGET_NR_recvmsg
8527 case TARGET_NR_recvmsg:
8528 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8529 break;
8530#endif
8531#ifdef TARGET_NR_send
8532 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008533 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008534 break;
8535#endif
8536#ifdef TARGET_NR_sendmsg
8537 case TARGET_NR_sendmsg:
8538 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8539 break;
8540#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008541#ifdef TARGET_NR_sendmmsg
8542 case TARGET_NR_sendmmsg:
8543 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8544 break;
8545 case TARGET_NR_recvmmsg:
8546 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8547 break;
8548#endif
bellard3532fa72006-06-24 15:06:03 +00008549#ifdef TARGET_NR_sendto
8550 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008551 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008552 break;
8553#endif
8554#ifdef TARGET_NR_shutdown
8555 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008556 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008557 break;
8558#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008559#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8560 case TARGET_NR_getrandom:
8561 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8562 if (!p) {
8563 goto efault;
8564 }
8565 ret = get_errno(getrandom(p, arg2, arg3));
8566 unlock_user(p, arg1, ret);
8567 break;
8568#endif
bellard3532fa72006-06-24 15:06:03 +00008569#ifdef TARGET_NR_socket
8570 case TARGET_NR_socket:
8571 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008572 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008573 break;
8574#endif
8575#ifdef TARGET_NR_socketpair
8576 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008577 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008578 break;
8579#endif
8580#ifdef TARGET_NR_setsockopt
8581 case TARGET_NR_setsockopt:
8582 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8583 break;
8584#endif
ths7494b0f2007-02-11 18:26:53 +00008585
bellard31e31b82003-02-18 22:55:36 +00008586 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008587 if (!(p = lock_user_string(arg2)))
8588 goto efault;
thse5574482007-02-11 20:03:13 +00008589 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8590 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008591 break;
8592
bellard31e31b82003-02-18 22:55:36 +00008593 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008594 {
bellard66fb9762003-03-23 01:06:05 +00008595 struct itimerval value, ovalue, *pvalue;
8596
pbrook53a59602006-03-25 19:31:22 +00008597 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008598 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008599 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8600 || copy_from_user_timeval(&pvalue->it_value,
8601 arg2 + sizeof(struct target_timeval)))
8602 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008603 } else {
8604 pvalue = NULL;
8605 }
8606 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008607 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008608 if (copy_to_user_timeval(arg3,
8609 &ovalue.it_interval)
8610 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8611 &ovalue.it_value))
8612 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008613 }
8614 }
8615 break;
bellard31e31b82003-02-18 22:55:36 +00008616 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008617 {
bellard66fb9762003-03-23 01:06:05 +00008618 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008619
bellard66fb9762003-03-23 01:06:05 +00008620 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008621 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008622 if (copy_to_user_timeval(arg2,
8623 &value.it_interval)
8624 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8625 &value.it_value))
8626 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008627 }
8628 }
8629 break;
Chen Gang704eff62015-08-21 05:37:33 +08008630#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008631 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008632 if (!(p = lock_user_string(arg1)))
8633 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008634 ret = get_errno(stat(path(p), &st));
8635 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008636 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008637#endif
8638#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008639 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008640 if (!(p = lock_user_string(arg1)))
8641 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008642 ret = get_errno(lstat(path(p), &st));
8643 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008644 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008645#endif
bellard31e31b82003-02-18 22:55:36 +00008646 case TARGET_NR_fstat:
8647 {
8648 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008649#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008650 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008651#endif
bellard31e31b82003-02-18 22:55:36 +00008652 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008653 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008654
bellard579a97f2007-11-11 14:26:47 +00008655 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8656 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008657 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008658 __put_user(st.st_dev, &target_st->st_dev);
8659 __put_user(st.st_ino, &target_st->st_ino);
8660 __put_user(st.st_mode, &target_st->st_mode);
8661 __put_user(st.st_uid, &target_st->st_uid);
8662 __put_user(st.st_gid, &target_st->st_gid);
8663 __put_user(st.st_nlink, &target_st->st_nlink);
8664 __put_user(st.st_rdev, &target_st->st_rdev);
8665 __put_user(st.st_size, &target_st->st_size);
8666 __put_user(st.st_blksize, &target_st->st_blksize);
8667 __put_user(st.st_blocks, &target_st->st_blocks);
8668 __put_user(st.st_atime, &target_st->target_st_atime);
8669 __put_user(st.st_mtime, &target_st->target_st_mtime);
8670 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008671 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008672 }
8673 }
8674 break;
bellardebc05482003-09-30 21:08:41 +00008675#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008676 case TARGET_NR_olduname:
8677 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008678#endif
8679#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008680 case TARGET_NR_iopl:
8681 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008682#endif
bellard31e31b82003-02-18 22:55:36 +00008683 case TARGET_NR_vhangup:
8684 ret = get_errno(vhangup());
8685 break;
bellardebc05482003-09-30 21:08:41 +00008686#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008687 case TARGET_NR_idle:
8688 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008689#endif
bellard42ad6ae2005-01-03 22:48:11 +00008690#ifdef TARGET_NR_syscall
8691 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008692 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8693 arg6, arg7, arg8, 0);
8694 break;
bellard42ad6ae2005-01-03 22:48:11 +00008695#endif
bellard31e31b82003-02-18 22:55:36 +00008696 case TARGET_NR_wait4:
8697 {
8698 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008699 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008700 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008701 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008702 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008703 if (target_rusage)
8704 rusage_ptr = &rusage;
8705 else
8706 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008707 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008708 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008709 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008710 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008711 if (put_user_s32(status, status_ptr))
8712 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008713 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008714 if (target_rusage) {
8715 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8716 if (rusage_err) {
8717 ret = rusage_err;
8718 }
8719 }
bellard31e31b82003-02-18 22:55:36 +00008720 }
8721 }
8722 break;
thse5febef2007-04-01 18:31:35 +00008723#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008724 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008725 if (!(p = lock_user_string(arg1)))
8726 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008727 ret = get_errno(swapoff(p));
8728 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008729 break;
thse5febef2007-04-01 18:31:35 +00008730#endif
bellard31e31b82003-02-18 22:55:36 +00008731 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008732 {
pbrook53a59602006-03-25 19:31:22 +00008733 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008734 struct sysinfo value;
8735 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008736 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008737 {
bellard579a97f2007-11-11 14:26:47 +00008738 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8739 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008740 __put_user(value.uptime, &target_value->uptime);
8741 __put_user(value.loads[0], &target_value->loads[0]);
8742 __put_user(value.loads[1], &target_value->loads[1]);
8743 __put_user(value.loads[2], &target_value->loads[2]);
8744 __put_user(value.totalram, &target_value->totalram);
8745 __put_user(value.freeram, &target_value->freeram);
8746 __put_user(value.sharedram, &target_value->sharedram);
8747 __put_user(value.bufferram, &target_value->bufferram);
8748 __put_user(value.totalswap, &target_value->totalswap);
8749 __put_user(value.freeswap, &target_value->freeswap);
8750 __put_user(value.procs, &target_value->procs);
8751 __put_user(value.totalhigh, &target_value->totalhigh);
8752 __put_user(value.freehigh, &target_value->freehigh);
8753 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008754 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008755 }
8756 }
8757 break;
thse5febef2007-04-01 18:31:35 +00008758#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008759 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008760 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8761 break;
thse5febef2007-04-01 18:31:35 +00008762#endif
aurel32e5289082009-04-18 16:16:12 +00008763#ifdef TARGET_NR_semget
8764 case TARGET_NR_semget:
8765 ret = get_errno(semget(arg1, arg2, arg3));
8766 break;
8767#endif
8768#ifdef TARGET_NR_semop
8769 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008770 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008771 break;
8772#endif
8773#ifdef TARGET_NR_semctl
8774 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008775 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008776 break;
8777#endif
aurel32eeb438c2008-10-13 21:08:55 +00008778#ifdef TARGET_NR_msgctl
8779 case TARGET_NR_msgctl:
8780 ret = do_msgctl(arg1, arg2, arg3);
8781 break;
8782#endif
8783#ifdef TARGET_NR_msgget
8784 case TARGET_NR_msgget:
8785 ret = get_errno(msgget(arg1, arg2));
8786 break;
8787#endif
8788#ifdef TARGET_NR_msgrcv
8789 case TARGET_NR_msgrcv:
8790 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8791 break;
8792#endif
8793#ifdef TARGET_NR_msgsnd
8794 case TARGET_NR_msgsnd:
8795 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8796 break;
8797#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008798#ifdef TARGET_NR_shmget
8799 case TARGET_NR_shmget:
8800 ret = get_errno(shmget(arg1, arg2, arg3));
8801 break;
8802#endif
8803#ifdef TARGET_NR_shmctl
8804 case TARGET_NR_shmctl:
8805 ret = do_shmctl(arg1, arg2, arg3);
8806 break;
8807#endif
8808#ifdef TARGET_NR_shmat
8809 case TARGET_NR_shmat:
8810 ret = do_shmat(arg1, arg2, arg3);
8811 break;
8812#endif
8813#ifdef TARGET_NR_shmdt
8814 case TARGET_NR_shmdt:
8815 ret = do_shmdt(arg1);
8816 break;
8817#endif
bellard31e31b82003-02-18 22:55:36 +00008818 case TARGET_NR_fsync:
8819 ret = get_errno(fsync(arg1));
8820 break;
bellard31e31b82003-02-18 22:55:36 +00008821 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008822 /* Linux manages to have three different orderings for its
8823 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8824 * match the kernel's CONFIG_CLONE_* settings.
8825 * Microblaze is further special in that it uses a sixth
8826 * implicit argument to clone for the TLS pointer.
8827 */
8828#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008829 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008830#elif defined(TARGET_CLONE_BACKWARDS)
8831 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8832#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008833 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008834#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008835 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008836#endif
bellard1b6b0292003-03-22 17:31:38 +00008837 break;
bellardec86b0f2003-04-11 00:15:04 +00008838#ifdef __NR_exit_group
8839 /* new thread calls */
8840 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008841#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008842 _mcleanup();
8843#endif
bellarde9009672005-04-26 20:42:36 +00008844 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008845 ret = get_errno(exit_group(arg1));
8846 break;
8847#endif
bellard31e31b82003-02-18 22:55:36 +00008848 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008849 if (!(p = lock_user_string(arg1)))
8850 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008851 ret = get_errno(setdomainname(p, arg2));
8852 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008853 break;
8854 case TARGET_NR_uname:
8855 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008856 {
8857 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008858
bellard579a97f2007-11-11 14:26:47 +00008859 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8860 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008861 ret = get_errno(sys_uname(buf));
8862 if (!is_error(ret)) {
8863 /* Overrite the native machine name with whatever is being
8864 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01008865 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008866 /* Allow the user to override the reported release. */
8867 if (qemu_uname_release && *qemu_uname_release)
8868 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008869 }
pbrook53a59602006-03-25 19:31:22 +00008870 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008871 }
bellard31e31b82003-02-18 22:55:36 +00008872 break;
bellard6dbad632003-03-16 18:05:05 +00008873#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008874 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008875 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008876 break;
j_mayer84409dd2007-04-06 08:56:50 +00008877#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008878 case TARGET_NR_vm86old:
8879 goto unimplemented;
8880 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008881 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008882 break;
8883#endif
j_mayer84409dd2007-04-06 08:56:50 +00008884#endif
bellard31e31b82003-02-18 22:55:36 +00008885 case TARGET_NR_adjtimex:
8886 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008887#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008888 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008889#endif
bellard31e31b82003-02-18 22:55:36 +00008890 case TARGET_NR_init_module:
8891 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008892#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008893 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008894#endif
bellard31e31b82003-02-18 22:55:36 +00008895 goto unimplemented;
8896 case TARGET_NR_quotactl:
8897 goto unimplemented;
8898 case TARGET_NR_getpgid:
8899 ret = get_errno(getpgid(arg1));
8900 break;
8901 case TARGET_NR_fchdir:
8902 ret = get_errno(fchdir(arg1));
8903 break;
j_mayer84409dd2007-04-06 08:56:50 +00008904#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008905 case TARGET_NR_bdflush:
8906 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008907#endif
thse5febef2007-04-01 18:31:35 +00008908#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008909 case TARGET_NR_sysfs:
8910 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008911#endif
bellard31e31b82003-02-18 22:55:36 +00008912 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008913 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008914 break;
thse5febef2007-04-01 18:31:35 +00008915#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008916 case TARGET_NR_afs_syscall:
8917 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008918#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008919#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008920 case TARGET_NR__llseek:
8921 {
8922 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008923#if !defined(__NR_llseek)
8924 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8925 if (res == -1) {
8926 ret = get_errno(res);
8927 } else {
8928 ret = 0;
8929 }
8930#else
bellard31e31b82003-02-18 22:55:36 +00008931 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008932#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008933 if ((ret == 0) && put_user_s64(res, arg4)) {
8934 goto efault;
8935 }
bellard31e31b82003-02-18 22:55:36 +00008936 }
8937 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008938#endif
Chen Gang704eff62015-08-21 05:37:33 +08008939#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008940 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008941#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008942#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008943 {
pbrook53a59602006-03-25 19:31:22 +00008944 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008945 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008946 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008947
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308948 dirp = g_try_malloc(count);
8949 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008950 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008951 goto fail;
8952 }
ths3b46e622007-09-17 08:09:54 +00008953
bellard4add45b2003-06-05 01:52:59 +00008954 ret = get_errno(sys_getdents(arg1, dirp, count));
8955 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008956 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008957 struct target_dirent *tde;
8958 int len = ret;
8959 int reclen, treclen;
8960 int count1, tnamelen;
8961
8962 count1 = 0;
8963 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008964 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8965 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008966 tde = target_dirp;
8967 while (len > 0) {
8968 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008969 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8970 assert(tnamelen >= 0);
8971 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8972 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008973 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008974 tde->d_ino = tswapal(de->d_ino);
8975 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008976 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008977 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008978 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008979 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008980 count1 += treclen;
8981 }
8982 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008983 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008984 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308985 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008986 }
8987#else
bellard31e31b82003-02-18 22:55:36 +00008988 {
aurel326556a832008-10-13 21:08:17 +00008989 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008990 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008991
bellard579a97f2007-11-11 14:26:47 +00008992 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8993 goto efault;
bellard72f03902003-02-18 23:33:18 +00008994 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008995 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008996 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008997 int len = ret;
8998 int reclen;
8999 de = dirp;
9000 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009001 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009002 if (reclen > len)
9003 break;
bellard8083a3e2003-03-24 23:12:16 +00009004 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009005 tswapls(&de->d_ino);
9006 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009007 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009008 len -= reclen;
9009 }
9010 }
pbrook53a59602006-03-25 19:31:22 +00009011 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009012 }
bellard4add45b2003-06-05 01:52:59 +00009013#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009014#else
9015 /* Implement getdents in terms of getdents64 */
9016 {
9017 struct linux_dirent64 *dirp;
9018 abi_long count = arg3;
9019
9020 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9021 if (!dirp) {
9022 goto efault;
9023 }
9024 ret = get_errno(sys_getdents64(arg1, dirp, count));
9025 if (!is_error(ret)) {
9026 /* Convert the dirent64 structs to target dirent. We do this
9027 * in-place, since we can guarantee that a target_dirent is no
9028 * larger than a dirent64; however this means we have to be
9029 * careful to read everything before writing in the new format.
9030 */
9031 struct linux_dirent64 *de;
9032 struct target_dirent *tde;
9033 int len = ret;
9034 int tlen = 0;
9035
9036 de = dirp;
9037 tde = (struct target_dirent *)dirp;
9038 while (len > 0) {
9039 int namelen, treclen;
9040 int reclen = de->d_reclen;
9041 uint64_t ino = de->d_ino;
9042 int64_t off = de->d_off;
9043 uint8_t type = de->d_type;
9044
9045 namelen = strlen(de->d_name);
9046 treclen = offsetof(struct target_dirent, d_name)
9047 + namelen + 2;
9048 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9049
9050 memmove(tde->d_name, de->d_name, namelen + 1);
9051 tde->d_ino = tswapal(ino);
9052 tde->d_off = tswapal(off);
9053 tde->d_reclen = tswap16(treclen);
9054 /* The target_dirent type is in what was formerly a padding
9055 * byte at the end of the structure:
9056 */
9057 *(((char *)tde) + treclen - 1) = type;
9058
9059 de = (struct linux_dirent64 *)((char *)de + reclen);
9060 tde = (struct target_dirent *)((char *)tde + treclen);
9061 len -= reclen;
9062 tlen += treclen;
9063 }
9064 ret = tlen;
9065 }
9066 unlock_user(dirp, arg2, ret);
9067 }
9068#endif
bellard31e31b82003-02-18 22:55:36 +00009069 break;
Chen Gang704eff62015-08-21 05:37:33 +08009070#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009071#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009072 case TARGET_NR_getdents64:
9073 {
aurel326556a832008-10-13 21:08:17 +00009074 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009075 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009076 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9077 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009078 ret = get_errno(sys_getdents64(arg1, dirp, count));
9079 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009080 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009081 int len = ret;
9082 int reclen;
9083 de = dirp;
9084 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009085 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009086 if (reclen > len)
9087 break;
bellard8083a3e2003-03-24 23:12:16 +00009088 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009089 tswap64s((uint64_t *)&de->d_ino);
9090 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009091 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009092 len -= reclen;
9093 }
9094 }
pbrook53a59602006-03-25 19:31:22 +00009095 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009096 }
9097 break;
bellarda541f292004-04-12 20:39:29 +00009098#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009099#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009100 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009101 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009102 break;
thse5febef2007-04-01 18:31:35 +00009103#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009104#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9105# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009106 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009107# endif
9108# ifdef TARGET_NR_ppoll
9109 case TARGET_NR_ppoll:
9110# endif
bellard9de5e442003-03-23 16:49:39 +00009111 {
pbrook53a59602006-03-25 19:31:22 +00009112 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009113 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009114 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009115 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009116
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009117 pfd = NULL;
9118 target_pfd = NULL;
9119 if (nfds) {
9120 target_pfd = lock_user(VERIFY_WRITE, arg1,
9121 sizeof(struct target_pollfd) * nfds, 1);
9122 if (!target_pfd) {
9123 goto efault;
9124 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009125
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009126 pfd = alloca(sizeof(struct pollfd) * nfds);
9127 for (i = 0; i < nfds; i++) {
9128 pfd[i].fd = tswap32(target_pfd[i].fd);
9129 pfd[i].events = tswap16(target_pfd[i].events);
9130 }
bellard9de5e442003-03-23 16:49:39 +00009131 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009132
Peter Maydella6130232016-06-06 19:58:10 +01009133 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009134# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009135 case TARGET_NR_ppoll:
9136 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009137 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9138 target_sigset_t *target_set;
9139 sigset_t _set, *set = &_set;
9140
9141 if (arg3) {
9142 if (target_to_host_timespec(timeout_ts, arg3)) {
9143 unlock_user(target_pfd, arg1, 0);
9144 goto efault;
9145 }
9146 } else {
9147 timeout_ts = NULL;
9148 }
9149
9150 if (arg4) {
9151 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9152 if (!target_set) {
9153 unlock_user(target_pfd, arg1, 0);
9154 goto efault;
9155 }
9156 target_to_host_sigset(set, target_set);
9157 } else {
9158 set = NULL;
9159 }
9160
Peter Maydella6130232016-06-06 19:58:10 +01009161 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9162 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009163
9164 if (!is_error(ret) && arg3) {
9165 host_to_target_timespec(arg3, timeout_ts);
9166 }
9167 if (arg4) {
9168 unlock_user(target_set, arg4, 0);
9169 }
Peter Maydella6130232016-06-06 19:58:10 +01009170 break;
9171 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009172# endif
Peter Maydella6130232016-06-06 19:58:10 +01009173# ifdef TARGET_NR_poll
9174 case TARGET_NR_poll:
9175 {
9176 struct timespec ts, *pts;
9177
9178 if (arg3 >= 0) {
9179 /* Convert ms to secs, ns */
9180 ts.tv_sec = arg3 / 1000;
9181 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9182 pts = &ts;
9183 } else {
9184 /* -ve poll() timeout means "infinite" */
9185 pts = NULL;
9186 }
9187 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9188 break;
9189 }
9190# endif
9191 default:
9192 g_assert_not_reached();
9193 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009194
bellard9de5e442003-03-23 16:49:39 +00009195 if (!is_error(ret)) {
9196 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009197 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009198 }
9199 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009200 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009201 }
9202 break;
thse5febef2007-04-01 18:31:35 +00009203#endif
bellard31e31b82003-02-18 22:55:36 +00009204 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009205 /* NOTE: the flock constant seems to be the same for every
9206 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009207 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009208 break;
9209 case TARGET_NR_readv:
9210 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009211 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9212 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009213 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009214 unlock_iovec(vec, arg2, arg3, 1);
9215 } else {
9216 ret = -host_to_target_errno(errno);
9217 }
bellard31e31b82003-02-18 22:55:36 +00009218 }
9219 break;
9220 case TARGET_NR_writev:
9221 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009222 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9223 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009224 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009225 unlock_iovec(vec, arg2, arg3, 0);
9226 } else {
9227 ret = -host_to_target_errno(errno);
9228 }
bellard31e31b82003-02-18 22:55:36 +00009229 }
9230 break;
9231 case TARGET_NR_getsid:
9232 ret = get_errno(getsid(arg1));
9233 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009234#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009235 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009236 ret = get_errno(fdatasync(arg1));
9237 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009238#endif
Chen Gang704eff62015-08-21 05:37:33 +08009239#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009240 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009241 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009242 return value. */
ths0da46a62007-10-20 20:23:07 +00009243 ret = -TARGET_ENOTDIR;
9244 break;
Chen Gang704eff62015-08-21 05:37:33 +08009245#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009246 case TARGET_NR_sched_getaffinity:
9247 {
9248 unsigned int mask_size;
9249 unsigned long *mask;
9250
9251 /*
9252 * sched_getaffinity needs multiples of ulong, so need to take
9253 * care of mismatches between target ulong and host ulong sizes.
9254 */
9255 if (arg2 & (sizeof(abi_ulong) - 1)) {
9256 ret = -TARGET_EINVAL;
9257 break;
9258 }
9259 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9260
9261 mask = alloca(mask_size);
9262 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9263
9264 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009265 if (ret > arg2) {
9266 /* More data returned than the caller's buffer will fit.
9267 * This only happens if sizeof(abi_long) < sizeof(long)
9268 * and the caller passed us a buffer holding an odd number
9269 * of abi_longs. If the host kernel is actually using the
9270 * extra 4 bytes then fail EINVAL; otherwise we can just
9271 * ignore them and only copy the interesting part.
9272 */
9273 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9274 if (numcpus > arg2 * 8) {
9275 ret = -TARGET_EINVAL;
9276 break;
9277 }
9278 ret = arg2;
9279 }
9280
Mike McCormackcd18f052011-04-18 14:43:36 +09009281 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009282 goto efault;
9283 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009284 }
9285 }
9286 break;
9287 case TARGET_NR_sched_setaffinity:
9288 {
9289 unsigned int mask_size;
9290 unsigned long *mask;
9291
9292 /*
9293 * sched_setaffinity needs multiples of ulong, so need to take
9294 * care of mismatches between target ulong and host ulong sizes.
9295 */
9296 if (arg2 & (sizeof(abi_ulong) - 1)) {
9297 ret = -TARGET_EINVAL;
9298 break;
9299 }
9300 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9301
9302 mask = alloca(mask_size);
9303 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9304 goto efault;
9305 }
9306 memcpy(mask, p, arg2);
9307 unlock_user_struct(p, arg2, 0);
9308
9309 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9310 }
9311 break;
bellard31e31b82003-02-18 22:55:36 +00009312 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009313 {
pbrook53a59602006-03-25 19:31:22 +00009314 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009315 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009316
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009317 if (arg2 == 0) {
9318 return -TARGET_EINVAL;
9319 }
bellard579a97f2007-11-11 14:26:47 +00009320 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9321 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009322 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009323 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009324 ret = get_errno(sched_setparam(arg1, &schp));
9325 }
9326 break;
bellard31e31b82003-02-18 22:55:36 +00009327 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009328 {
pbrook53a59602006-03-25 19:31:22 +00009329 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009330 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009331
9332 if (arg2 == 0) {
9333 return -TARGET_EINVAL;
9334 }
bellard5cd43932003-03-29 16:54:36 +00009335 ret = get_errno(sched_getparam(arg1, &schp));
9336 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009337 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9338 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009339 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009340 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009341 }
9342 }
9343 break;
bellard31e31b82003-02-18 22:55:36 +00009344 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009345 {
pbrook53a59602006-03-25 19:31:22 +00009346 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009347 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009348 if (arg3 == 0) {
9349 return -TARGET_EINVAL;
9350 }
bellard579a97f2007-11-11 14:26:47 +00009351 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9352 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009353 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009354 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009355 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9356 }
9357 break;
bellard31e31b82003-02-18 22:55:36 +00009358 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009359 ret = get_errno(sched_getscheduler(arg1));
9360 break;
bellard31e31b82003-02-18 22:55:36 +00009361 case TARGET_NR_sched_yield:
9362 ret = get_errno(sched_yield());
9363 break;
9364 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009365 ret = get_errno(sched_get_priority_max(arg1));
9366 break;
bellard31e31b82003-02-18 22:55:36 +00009367 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009368 ret = get_errno(sched_get_priority_min(arg1));
9369 break;
bellard31e31b82003-02-18 22:55:36 +00009370 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009371 {
bellard5cd43932003-03-29 16:54:36 +00009372 struct timespec ts;
9373 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9374 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009375 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009376 }
9377 }
9378 break;
bellard31e31b82003-02-18 22:55:36 +00009379 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009380 {
bellard1b6b0292003-03-22 17:31:38 +00009381 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009382 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009383 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009384 if (is_error(ret) && arg2) {
9385 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009386 }
9387 }
9388 break;
thse5febef2007-04-01 18:31:35 +00009389#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009390 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009391 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009392#endif
9393#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009394 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009395 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009396#endif
bellard31e31b82003-02-18 22:55:36 +00009397 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009398 switch (arg1) {
9399 case PR_GET_PDEATHSIG:
9400 {
9401 int deathsig;
9402 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9403 if (!is_error(ret) && arg2
9404 && put_user_ual(deathsig, arg2)) {
9405 goto efault;
thse5574482007-02-11 20:03:13 +00009406 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009407 break;
9408 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009409#ifdef PR_GET_NAME
9410 case PR_GET_NAME:
9411 {
9412 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9413 if (!name) {
9414 goto efault;
9415 }
9416 ret = get_errno(prctl(arg1, (unsigned long)name,
9417 arg3, arg4, arg5));
9418 unlock_user(name, arg2, 16);
9419 break;
9420 }
9421 case PR_SET_NAME:
9422 {
9423 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9424 if (!name) {
9425 goto efault;
9426 }
9427 ret = get_errno(prctl(arg1, (unsigned long)name,
9428 arg3, arg4, arg5));
9429 unlock_user(name, arg2, 0);
9430 break;
9431 }
9432#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009433 default:
9434 /* Most prctl options have no pointer arguments */
9435 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9436 break;
9437 }
ths39b9aae2007-02-11 18:36:44 +00009438 break;
bellardd2fd1af2007-11-14 18:08:56 +00009439#ifdef TARGET_NR_arch_prctl
9440 case TARGET_NR_arch_prctl:
9441#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9442 ret = do_arch_prctl(cpu_env, arg1, arg2);
9443 break;
9444#else
9445 goto unimplemented;
9446#endif
9447#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009448#ifdef TARGET_NR_pread64
9449 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009450 if (regpairs_aligned(cpu_env)) {
9451 arg4 = arg5;
9452 arg5 = arg6;
9453 }
aurel32f2c7ba12008-03-28 22:32:06 +00009454 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9455 goto efault;
9456 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9457 unlock_user(p, arg2, ret);
9458 break;
9459 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009460 if (regpairs_aligned(cpu_env)) {
9461 arg4 = arg5;
9462 arg5 = arg6;
9463 }
aurel32f2c7ba12008-03-28 22:32:06 +00009464 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9465 goto efault;
9466 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9467 unlock_user(p, arg2, 0);
9468 break;
9469#endif
bellard31e31b82003-02-18 22:55:36 +00009470 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009471 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9472 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009473 ret = get_errno(sys_getcwd1(p, arg2));
9474 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009475 break;
9476 case TARGET_NR_capget:
9477 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009478 {
9479 struct target_user_cap_header *target_header;
9480 struct target_user_cap_data *target_data = NULL;
9481 struct __user_cap_header_struct header;
9482 struct __user_cap_data_struct data[2];
9483 struct __user_cap_data_struct *dataptr = NULL;
9484 int i, target_datalen;
9485 int data_items = 1;
9486
9487 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9488 goto efault;
9489 }
9490 header.version = tswap32(target_header->version);
9491 header.pid = tswap32(target_header->pid);
9492
Peter Maydellec864872014-03-19 16:07:30 +00009493 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009494 /* Version 2 and up takes pointer to two user_data structs */
9495 data_items = 2;
9496 }
9497
9498 target_datalen = sizeof(*target_data) * data_items;
9499
9500 if (arg2) {
9501 if (num == TARGET_NR_capget) {
9502 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9503 } else {
9504 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9505 }
9506 if (!target_data) {
9507 unlock_user_struct(target_header, arg1, 0);
9508 goto efault;
9509 }
9510
9511 if (num == TARGET_NR_capset) {
9512 for (i = 0; i < data_items; i++) {
9513 data[i].effective = tswap32(target_data[i].effective);
9514 data[i].permitted = tswap32(target_data[i].permitted);
9515 data[i].inheritable = tswap32(target_data[i].inheritable);
9516 }
9517 }
9518
9519 dataptr = data;
9520 }
9521
9522 if (num == TARGET_NR_capget) {
9523 ret = get_errno(capget(&header, dataptr));
9524 } else {
9525 ret = get_errno(capset(&header, dataptr));
9526 }
9527
9528 /* The kernel always updates version for both capget and capset */
9529 target_header->version = tswap32(header.version);
9530 unlock_user_struct(target_header, arg1, 1);
9531
9532 if (arg2) {
9533 if (num == TARGET_NR_capget) {
9534 for (i = 0; i < data_items; i++) {
9535 target_data[i].effective = tswap32(data[i].effective);
9536 target_data[i].permitted = tswap32(data[i].permitted);
9537 target_data[i].inheritable = tswap32(data[i].inheritable);
9538 }
9539 unlock_user(target_data, arg2, target_datalen);
9540 } else {
9541 unlock_user(target_data, arg2, 0);
9542 }
9543 }
9544 break;
9545 }
bellard31e31b82003-02-18 22:55:36 +00009546 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009547 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009548 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009549
9550#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009551 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009552 {
9553 off_t *offp = NULL;
9554 off_t off;
9555 if (arg3) {
9556 ret = get_user_sal(off, arg3);
9557 if (is_error(ret)) {
9558 break;
9559 }
9560 offp = &off;
9561 }
9562 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9563 if (!is_error(ret) && arg3) {
9564 abi_long ret2 = put_user_sal(off, arg3);
9565 if (is_error(ret2)) {
9566 ret = ret2;
9567 }
9568 }
9569 break;
9570 }
9571#ifdef TARGET_NR_sendfile64
9572 case TARGET_NR_sendfile64:
9573 {
9574 off_t *offp = NULL;
9575 off_t off;
9576 if (arg3) {
9577 ret = get_user_s64(off, arg3);
9578 if (is_error(ret)) {
9579 break;
9580 }
9581 offp = &off;
9582 }
9583 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9584 if (!is_error(ret) && arg3) {
9585 abi_long ret2 = put_user_s64(off, arg3);
9586 if (is_error(ret2)) {
9587 ret = ret2;
9588 }
9589 }
9590 break;
9591 }
9592#endif
9593#else
9594 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009595#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009596 case TARGET_NR_sendfile64:
9597#endif
bellard5cd43932003-03-29 16:54:36 +00009598 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009599#endif
9600
bellardebc05482003-09-30 21:08:41 +00009601#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009602 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009603 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009604#endif
9605#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009606 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009607 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009608#endif
bellard048f6b42005-11-26 18:47:20 +00009609#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009610 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009611 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9612 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009613 break;
bellard048f6b42005-11-26 18:47:20 +00009614#endif
bellardebc05482003-09-30 21:08:41 +00009615#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009616 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009617 {
9618 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009619 int resource = target_to_host_resource(arg1);
9620 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009621 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009622 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009623 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9624 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009625 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9626 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009627 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009628 }
9629 break;
9630 }
bellardebc05482003-09-30 21:08:41 +00009631#endif
bellarda315a142005-01-30 22:59:18 +00009632#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009633 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009634 if (!(p = lock_user_string(arg1)))
9635 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009636 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9637 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009638 break;
bellarda315a142005-01-30 22:59:18 +00009639#endif
9640#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009641 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009642 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009643 break;
bellarda315a142005-01-30 22:59:18 +00009644#endif
9645#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009646 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009647 if (!(p = lock_user_string(arg1)))
9648 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009649 ret = get_errno(stat(path(p), &st));
9650 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009651 if (!is_error(ret))
9652 ret = host_to_target_stat64(cpu_env, arg2, &st);
9653 break;
bellarda315a142005-01-30 22:59:18 +00009654#endif
9655#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009656 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009657 if (!(p = lock_user_string(arg1)))
9658 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009659 ret = get_errno(lstat(path(p), &st));
9660 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009661 if (!is_error(ret))
9662 ret = host_to_target_stat64(cpu_env, arg2, &st);
9663 break;
bellarda315a142005-01-30 22:59:18 +00009664#endif
9665#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009666 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009667 ret = get_errno(fstat(arg1, &st));
9668 if (!is_error(ret))
9669 ret = host_to_target_stat64(cpu_env, arg2, &st);
9670 break;
bellardec86b0f2003-04-11 00:15:04 +00009671#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009672#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009673#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009674 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009675#endif
9676#ifdef TARGET_NR_newfstatat
9677 case TARGET_NR_newfstatat:
9678#endif
balrog6a24a772008-09-20 02:23:36 +00009679 if (!(p = lock_user_string(arg2)))
9680 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009681 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009682 if (!is_error(ret))
9683 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009684 break;
bellarda315a142005-01-30 22:59:18 +00009685#endif
Chen Gang704eff62015-08-21 05:37:33 +08009686#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009687 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009688 if (!(p = lock_user_string(arg1)))
9689 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009690 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9691 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009692 break;
Chen Gang704eff62015-08-21 05:37:33 +08009693#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009694#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009695 case TARGET_NR_getuid:
9696 ret = get_errno(high2lowuid(getuid()));
9697 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009698#endif
9699#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009700 case TARGET_NR_getgid:
9701 ret = get_errno(high2lowgid(getgid()));
9702 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009703#endif
9704#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009705 case TARGET_NR_geteuid:
9706 ret = get_errno(high2lowuid(geteuid()));
9707 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009708#endif
9709#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009710 case TARGET_NR_getegid:
9711 ret = get_errno(high2lowgid(getegid()));
9712 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009713#endif
bellard67867302003-11-23 17:05:30 +00009714 case TARGET_NR_setreuid:
9715 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9716 break;
9717 case TARGET_NR_setregid:
9718 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9719 break;
9720 case TARGET_NR_getgroups:
9721 {
9722 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009723 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009724 gid_t *grouplist;
9725 int i;
9726
9727 grouplist = alloca(gidsetsize * sizeof(gid_t));
9728 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009729 if (gidsetsize == 0)
9730 break;
bellard67867302003-11-23 17:05:30 +00009731 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009732 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009733 if (!target_grouplist)
9734 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009735 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009736 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009737 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009738 }
9739 }
9740 break;
9741 case TARGET_NR_setgroups:
9742 {
9743 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009744 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009745 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009746 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009747 if (gidsetsize) {
9748 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009749 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009750 if (!target_grouplist) {
9751 ret = -TARGET_EFAULT;
9752 goto fail;
9753 }
9754 for (i = 0; i < gidsetsize; i++) {
9755 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9756 }
9757 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009758 }
bellard67867302003-11-23 17:05:30 +00009759 ret = get_errno(setgroups(gidsetsize, grouplist));
9760 }
9761 break;
9762 case TARGET_NR_fchown:
9763 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9764 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009765#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009766 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009767 if (!(p = lock_user_string(arg2)))
9768 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009769 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9770 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009771 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009772 break;
9773#endif
bellard67867302003-11-23 17:05:30 +00009774#ifdef TARGET_NR_setresuid
9775 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009776 ret = get_errno(sys_setresuid(low2highuid(arg1),
9777 low2highuid(arg2),
9778 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009779 break;
9780#endif
9781#ifdef TARGET_NR_getresuid
9782 case TARGET_NR_getresuid:
9783 {
pbrook53a59602006-03-25 19:31:22 +00009784 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009785 ret = get_errno(getresuid(&ruid, &euid, &suid));
9786 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009787 if (put_user_id(high2lowuid(ruid), arg1)
9788 || put_user_id(high2lowuid(euid), arg2)
9789 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009790 goto efault;
bellard67867302003-11-23 17:05:30 +00009791 }
9792 }
9793 break;
9794#endif
9795#ifdef TARGET_NR_getresgid
9796 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009797 ret = get_errno(sys_setresgid(low2highgid(arg1),
9798 low2highgid(arg2),
9799 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009800 break;
9801#endif
9802#ifdef TARGET_NR_getresgid
9803 case TARGET_NR_getresgid:
9804 {
pbrook53a59602006-03-25 19:31:22 +00009805 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009806 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9807 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009808 if (put_user_id(high2lowgid(rgid), arg1)
9809 || put_user_id(high2lowgid(egid), arg2)
9810 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009811 goto efault;
bellard67867302003-11-23 17:05:30 +00009812 }
9813 }
9814 break;
9815#endif
Chen Gang704eff62015-08-21 05:37:33 +08009816#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009817 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009818 if (!(p = lock_user_string(arg1)))
9819 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009820 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9821 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009822 break;
Chen Gang704eff62015-08-21 05:37:33 +08009823#endif
bellard67867302003-11-23 17:05:30 +00009824 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009825 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009826 break;
9827 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009828 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009829 break;
9830 case TARGET_NR_setfsuid:
9831 ret = get_errno(setfsuid(arg1));
9832 break;
9833 case TARGET_NR_setfsgid:
9834 ret = get_errno(setfsgid(arg1));
9835 break;
bellard67867302003-11-23 17:05:30 +00009836
bellarda315a142005-01-30 22:59:18 +00009837#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009838 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009839 if (!(p = lock_user_string(arg1)))
9840 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009841 ret = get_errno(lchown(p, arg2, arg3));
9842 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009843 break;
bellarda315a142005-01-30 22:59:18 +00009844#endif
9845#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009846 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009847 ret = get_errno(getuid());
9848 break;
bellarda315a142005-01-30 22:59:18 +00009849#endif
aurel3264b4d282008-11-14 17:20:15 +00009850
9851#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9852 /* Alpha specific */
9853 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009854 {
9855 uid_t euid;
9856 euid=geteuid();
9857 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9858 }
aurel3264b4d282008-11-14 17:20:15 +00009859 ret = get_errno(getuid());
9860 break;
9861#endif
9862#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9863 /* Alpha specific */
9864 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009865 {
9866 uid_t egid;
9867 egid=getegid();
9868 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9869 }
aurel3264b4d282008-11-14 17:20:15 +00009870 ret = get_errno(getgid());
9871 break;
9872#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009873#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9874 /* Alpha specific */
9875 case TARGET_NR_osf_getsysinfo:
9876 ret = -TARGET_EOPNOTSUPP;
9877 switch (arg1) {
9878 case TARGET_GSI_IEEE_FP_CONTROL:
9879 {
9880 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9881
9882 /* Copied from linux ieee_fpcr_to_swcr. */
9883 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9884 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9885 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9886 | SWCR_TRAP_ENABLE_DZE
9887 | SWCR_TRAP_ENABLE_OVF);
9888 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9889 | SWCR_TRAP_ENABLE_INE);
9890 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9891 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9892
9893 if (put_user_u64 (swcr, arg2))
9894 goto efault;
9895 ret = 0;
9896 }
9897 break;
9898
9899 /* case GSI_IEEE_STATE_AT_SIGNAL:
9900 -- Not implemented in linux kernel.
9901 case GSI_UACPROC:
9902 -- Retrieves current unaligned access state; not much used.
9903 case GSI_PROC_TYPE:
9904 -- Retrieves implver information; surely not used.
9905 case GSI_GET_HWRPB:
9906 -- Grabs a copy of the HWRPB; surely not used.
9907 */
9908 }
9909 break;
9910#endif
9911#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9912 /* Alpha specific */
9913 case TARGET_NR_osf_setsysinfo:
9914 ret = -TARGET_EOPNOTSUPP;
9915 switch (arg1) {
9916 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009917 {
9918 uint64_t swcr, fpcr, orig_fpcr;
9919
Richard Henderson6e06d512012-06-01 09:08:21 -07009920 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009921 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009922 }
9923 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009924 fpcr = orig_fpcr & FPCR_DYN_MASK;
9925
9926 /* Copied from linux ieee_swcr_to_fpcr. */
9927 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9928 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9929 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9930 | SWCR_TRAP_ENABLE_DZE
9931 | SWCR_TRAP_ENABLE_OVF)) << 48;
9932 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9933 | SWCR_TRAP_ENABLE_INE)) << 57;
9934 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9935 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9936
Richard Henderson6e06d512012-06-01 09:08:21 -07009937 cpu_alpha_store_fpcr(cpu_env, fpcr);
9938 ret = 0;
9939 }
9940 break;
9941
9942 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9943 {
9944 uint64_t exc, fpcr, orig_fpcr;
9945 int si_code;
9946
9947 if (get_user_u64(exc, arg2)) {
9948 goto efault;
9949 }
9950
9951 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9952
9953 /* We only add to the exception status here. */
9954 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9955
9956 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009957 ret = 0;
9958
Richard Henderson6e06d512012-06-01 09:08:21 -07009959 /* Old exceptions are not signaled. */
9960 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009961
Richard Henderson6e06d512012-06-01 09:08:21 -07009962 /* If any exceptions set by this call,
9963 and are unmasked, send a signal. */
9964 si_code = 0;
9965 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9966 si_code = TARGET_FPE_FLTRES;
9967 }
9968 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9969 si_code = TARGET_FPE_FLTUND;
9970 }
9971 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9972 si_code = TARGET_FPE_FLTOVF;
9973 }
9974 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9975 si_code = TARGET_FPE_FLTDIV;
9976 }
9977 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9978 si_code = TARGET_FPE_FLTINV;
9979 }
9980 if (si_code != 0) {
9981 target_siginfo_t info;
9982 info.si_signo = SIGFPE;
9983 info.si_errno = 0;
9984 info.si_code = si_code;
9985 info._sifields._sigfault._addr
9986 = ((CPUArchState *)cpu_env)->pc;
9987 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009988 }
9989 }
9990 break;
9991
9992 /* case SSI_NVPAIRS:
9993 -- Used with SSIN_UACPROC to enable unaligned accesses.
9994 case SSI_IEEE_STATE_AT_SIGNAL:
9995 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9996 -- Not implemented in linux kernel
9997 */
9998 }
9999 break;
10000#endif
10001#ifdef TARGET_NR_osf_sigprocmask
10002 /* Alpha specific. */
10003 case TARGET_NR_osf_sigprocmask:
10004 {
10005 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010006 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010007 sigset_t set, oldset;
10008
10009 switch(arg1) {
10010 case TARGET_SIG_BLOCK:
10011 how = SIG_BLOCK;
10012 break;
10013 case TARGET_SIG_UNBLOCK:
10014 how = SIG_UNBLOCK;
10015 break;
10016 case TARGET_SIG_SETMASK:
10017 how = SIG_SETMASK;
10018 break;
10019 default:
10020 ret = -TARGET_EINVAL;
10021 goto fail;
10022 }
10023 mask = arg2;
10024 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010025 ret = do_sigprocmask(how, &set, &oldset);
10026 if (!ret) {
10027 host_to_target_old_sigset(&mask, &oldset);
10028 ret = mask;
10029 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010030 }
10031 break;
10032#endif
aurel3264b4d282008-11-14 17:20:15 +000010033
bellarda315a142005-01-30 22:59:18 +000010034#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010035 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000010036 ret = get_errno(getgid());
10037 break;
bellarda315a142005-01-30 22:59:18 +000010038#endif
10039#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010040 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000010041 ret = get_errno(geteuid());
10042 break;
bellarda315a142005-01-30 22:59:18 +000010043#endif
10044#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010045 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010046 ret = get_errno(getegid());
10047 break;
bellarda315a142005-01-30 22:59:18 +000010048#endif
10049#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010050 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010051 ret = get_errno(setreuid(arg1, arg2));
10052 break;
bellarda315a142005-01-30 22:59:18 +000010053#endif
10054#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010055 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010056 ret = get_errno(setregid(arg1, arg2));
10057 break;
bellarda315a142005-01-30 22:59:18 +000010058#endif
10059#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010060 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010061 {
10062 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010063 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010064 gid_t *grouplist;
10065 int i;
10066
10067 grouplist = alloca(gidsetsize * sizeof(gid_t));
10068 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010069 if (gidsetsize == 0)
10070 break;
bellard99c475a2005-01-31 20:45:13 +000010071 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010072 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10073 if (!target_grouplist) {
10074 ret = -TARGET_EFAULT;
10075 goto fail;
10076 }
balroga2155fc2008-09-20 02:12:08 +000010077 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010078 target_grouplist[i] = tswap32(grouplist[i]);
10079 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010080 }
10081 }
10082 break;
bellarda315a142005-01-30 22:59:18 +000010083#endif
10084#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010085 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010086 {
10087 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010088 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010089 gid_t *grouplist;
10090 int i;
ths3b46e622007-09-17 08:09:54 +000010091
bellard99c475a2005-01-31 20:45:13 +000010092 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010093 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10094 if (!target_grouplist) {
10095 ret = -TARGET_EFAULT;
10096 goto fail;
10097 }
bellard99c475a2005-01-31 20:45:13 +000010098 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010099 grouplist[i] = tswap32(target_grouplist[i]);
10100 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010101 ret = get_errno(setgroups(gidsetsize, grouplist));
10102 }
10103 break;
bellarda315a142005-01-30 22:59:18 +000010104#endif
10105#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010106 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010107 ret = get_errno(fchown(arg1, arg2, arg3));
10108 break;
bellarda315a142005-01-30 22:59:18 +000010109#endif
10110#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010111 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010112 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010113 break;
bellarda315a142005-01-30 22:59:18 +000010114#endif
10115#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010116 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010117 {
pbrook53a59602006-03-25 19:31:22 +000010118 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010119 ret = get_errno(getresuid(&ruid, &euid, &suid));
10120 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010121 if (put_user_u32(ruid, arg1)
10122 || put_user_u32(euid, arg2)
10123 || put_user_u32(suid, arg3))
10124 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010125 }
10126 }
10127 break;
bellarda315a142005-01-30 22:59:18 +000010128#endif
10129#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010130 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010131 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010132 break;
bellarda315a142005-01-30 22:59:18 +000010133#endif
10134#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010135 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010136 {
pbrook53a59602006-03-25 19:31:22 +000010137 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010138 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10139 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010140 if (put_user_u32(rgid, arg1)
10141 || put_user_u32(egid, arg2)
10142 || put_user_u32(sgid, arg3))
10143 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010144 }
10145 }
10146 break;
bellarda315a142005-01-30 22:59:18 +000010147#endif
10148#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010149 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010150 if (!(p = lock_user_string(arg1)))
10151 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010152 ret = get_errno(chown(p, arg2, arg3));
10153 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010154 break;
bellarda315a142005-01-30 22:59:18 +000010155#endif
10156#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010157 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010158 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010159 break;
bellarda315a142005-01-30 22:59:18 +000010160#endif
10161#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010162 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010163 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010164 break;
bellarda315a142005-01-30 22:59:18 +000010165#endif
10166#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010167 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010168 ret = get_errno(setfsuid(arg1));
10169 break;
bellarda315a142005-01-30 22:59:18 +000010170#endif
10171#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010172 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010173 ret = get_errno(setfsgid(arg1));
10174 break;
bellarda315a142005-01-30 22:59:18 +000010175#endif
bellard67867302003-11-23 17:05:30 +000010176
bellard31e31b82003-02-18 22:55:36 +000010177 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010178 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010179#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010180 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010181 {
10182 void *a;
10183 ret = -TARGET_EFAULT;
10184 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10185 goto efault;
10186 if (!(p = lock_user_string(arg3)))
10187 goto mincore_fail;
10188 ret = get_errno(mincore(a, arg2, p));
10189 unlock_user(p, arg3, ret);
10190 mincore_fail:
10191 unlock_user(a, arg1, 0);
10192 }
10193 break;
bellardffa65c32004-01-04 23:57:22 +000010194#endif
aurel32408321b2008-10-01 21:46:32 +000010195#ifdef TARGET_NR_arm_fadvise64_64
10196 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010197 /* arm_fadvise64_64 looks like fadvise64_64 but
10198 * with different argument order: fd, advice, offset, len
10199 * rather than the usual fd, offset, len, advice.
10200 * Note that offset and len are both 64-bit so appear as
10201 * pairs of 32-bit registers.
10202 */
10203 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10204 target_offset64(arg5, arg6), arg2);
10205 ret = -host_to_target_errno(ret);
10206 break;
aurel32408321b2008-10-01 21:46:32 +000010207#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010208
10209#if TARGET_ABI_BITS == 32
10210
10211#ifdef TARGET_NR_fadvise64_64
10212 case TARGET_NR_fadvise64_64:
10213 /* 6 args: fd, offset (high, low), len (high, low), advice */
10214 if (regpairs_aligned(cpu_env)) {
10215 /* offset is in (3,4), len in (5,6) and advice in 7 */
10216 arg2 = arg3;
10217 arg3 = arg4;
10218 arg4 = arg5;
10219 arg5 = arg6;
10220 arg6 = arg7;
10221 }
10222 ret = -host_to_target_errno(posix_fadvise(arg1,
10223 target_offset64(arg2, arg3),
10224 target_offset64(arg4, arg5),
10225 arg6));
10226 break;
10227#endif
10228
10229#ifdef TARGET_NR_fadvise64
10230 case TARGET_NR_fadvise64:
10231 /* 5 args: fd, offset (high, low), len, advice */
10232 if (regpairs_aligned(cpu_env)) {
10233 /* offset is in (3,4), len in 5 and advice in 6 */
10234 arg2 = arg3;
10235 arg3 = arg4;
10236 arg4 = arg5;
10237 arg5 = arg6;
10238 }
10239 ret = -host_to_target_errno(posix_fadvise(arg1,
10240 target_offset64(arg2, arg3),
10241 arg4, arg5));
10242 break;
10243#endif
10244
10245#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010246#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010247#ifdef TARGET_NR_fadvise64_64
10248 case TARGET_NR_fadvise64_64:
10249#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010250#ifdef TARGET_NR_fadvise64
10251 case TARGET_NR_fadvise64:
10252#endif
10253#ifdef TARGET_S390X
10254 switch (arg4) {
10255 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10256 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10257 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10258 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10259 default: break;
10260 }
10261#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010262 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10263 break;
aurel32408321b2008-10-01 21:46:32 +000010264#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010265#endif /* end of 64-bit ABI fadvise handling */
10266
bellardffa65c32004-01-04 23:57:22 +000010267#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010268 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010269 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010270 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010271 This will break MADV_DONTNEED.
10272 This is a hint, so ignoring and returning success is ok. */
10273 ret = get_errno(0);
10274 break;
bellardffa65c32004-01-04 23:57:22 +000010275#endif
blueswir1992f48a2007-10-14 16:27:31 +000010276#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010277 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010278 {
thsb1e341e2007-03-20 21:50:52 +000010279 int cmd;
bellard77e46722003-04-29 20:39:06 +000010280 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010281 from_flock64_fn *copyfrom = copy_from_user_flock64;
10282 to_flock64_fn *copyto = copy_to_user_flock64;
10283
pbrookce4defa2006-02-09 16:49:55 +000010284#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010285 if (((CPUARMState *)cpu_env)->eabi) {
10286 copyfrom = copy_from_user_eabi_flock64;
10287 copyto = copy_to_user_eabi_flock64;
10288 }
pbrookce4defa2006-02-09 16:49:55 +000010289#endif
bellard77e46722003-04-29 20:39:06 +000010290
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010291 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010292 if (cmd == -TARGET_EINVAL) {
10293 ret = cmd;
10294 break;
10295 }
thsb1e341e2007-03-20 21:50:52 +000010296
bellard60cd49d2003-03-16 22:53:56 +000010297 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010298 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010299 ret = copyfrom(&fl, arg3);
10300 if (ret) {
10301 break;
ths58134272007-03-31 18:59:32 +000010302 }
thsb1e341e2007-03-20 21:50:52 +000010303 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010304 if (ret == 0) {
10305 ret = copyto(arg3, &fl);
10306 }
bellard77e46722003-04-29 20:39:06 +000010307 break;
10308
thsb1e341e2007-03-20 21:50:52 +000010309 case TARGET_F_SETLK64:
10310 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010311 ret = copyfrom(&fl, arg3);
10312 if (ret) {
10313 break;
pbrookce4defa2006-02-09 16:49:55 +000010314 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010315 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010316 break;
bellard60cd49d2003-03-16 22:53:56 +000010317 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010318 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010319 break;
10320 }
bellard77e46722003-04-29 20:39:06 +000010321 break;
10322 }
bellard60cd49d2003-03-16 22:53:56 +000010323#endif
ths7d600c82006-12-08 01:32:58 +000010324#ifdef TARGET_NR_cacheflush
10325 case TARGET_NR_cacheflush:
10326 /* self-modifying code is handled automatically, so nothing needed */
10327 ret = 0;
10328 break;
10329#endif
bellardebc05482003-09-30 21:08:41 +000010330#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010331 case TARGET_NR_security:
10332 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010333#endif
bellardc573ff62004-01-04 15:51:36 +000010334#ifdef TARGET_NR_getpagesize
10335 case TARGET_NR_getpagesize:
10336 ret = TARGET_PAGE_SIZE;
10337 break;
10338#endif
bellard31e31b82003-02-18 22:55:36 +000010339 case TARGET_NR_gettid:
10340 ret = get_errno(gettid());
10341 break;
thse5febef2007-04-01 18:31:35 +000010342#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010343 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010344#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010345 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010346 arg2 = arg3;
10347 arg3 = arg4;
10348 arg4 = arg5;
10349 }
aurel322054ac92008-10-13 21:08:07 +000010350 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10351#else
10352 ret = get_errno(readahead(arg1, arg2, arg3));
10353#endif
10354 break;
thse5febef2007-04-01 18:31:35 +000010355#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010356#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010357#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010358 case TARGET_NR_listxattr:
10359 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010360 {
10361 void *p, *b = 0;
10362 if (arg2) {
10363 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10364 if (!b) {
10365 ret = -TARGET_EFAULT;
10366 break;
10367 }
10368 }
10369 p = lock_user_string(arg1);
10370 if (p) {
10371 if (num == TARGET_NR_listxattr) {
10372 ret = get_errno(listxattr(p, b, arg3));
10373 } else {
10374 ret = get_errno(llistxattr(p, b, arg3));
10375 }
10376 } else {
10377 ret = -TARGET_EFAULT;
10378 }
10379 unlock_user(p, arg1, 0);
10380 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010381 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010382 }
10383 case TARGET_NR_flistxattr:
10384 {
10385 void *b = 0;
10386 if (arg2) {
10387 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10388 if (!b) {
10389 ret = -TARGET_EFAULT;
10390 break;
10391 }
10392 }
10393 ret = get_errno(flistxattr(arg1, b, arg3));
10394 unlock_user(b, arg2, arg3);
10395 break;
10396 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010397 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010398 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010399 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010400 void *p, *n, *v = 0;
10401 if (arg3) {
10402 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10403 if (!v) {
10404 ret = -TARGET_EFAULT;
10405 break;
10406 }
10407 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010408 p = lock_user_string(arg1);
10409 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010410 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010411 if (num == TARGET_NR_setxattr) {
10412 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10413 } else {
10414 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10415 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010416 } else {
10417 ret = -TARGET_EFAULT;
10418 }
10419 unlock_user(p, arg1, 0);
10420 unlock_user(n, arg2, 0);
10421 unlock_user(v, arg3, 0);
10422 }
10423 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010424 case TARGET_NR_fsetxattr:
10425 {
10426 void *n, *v = 0;
10427 if (arg3) {
10428 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10429 if (!v) {
10430 ret = -TARGET_EFAULT;
10431 break;
10432 }
10433 }
10434 n = lock_user_string(arg2);
10435 if (n) {
10436 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10437 } else {
10438 ret = -TARGET_EFAULT;
10439 }
10440 unlock_user(n, arg2, 0);
10441 unlock_user(v, arg3, 0);
10442 }
10443 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010444 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010445 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010446 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010447 void *p, *n, *v = 0;
10448 if (arg3) {
10449 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10450 if (!v) {
10451 ret = -TARGET_EFAULT;
10452 break;
10453 }
10454 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010455 p = lock_user_string(arg1);
10456 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010457 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010458 if (num == TARGET_NR_getxattr) {
10459 ret = get_errno(getxattr(p, n, v, arg4));
10460 } else {
10461 ret = get_errno(lgetxattr(p, n, v, arg4));
10462 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010463 } else {
10464 ret = -TARGET_EFAULT;
10465 }
10466 unlock_user(p, arg1, 0);
10467 unlock_user(n, arg2, 0);
10468 unlock_user(v, arg3, arg4);
10469 }
10470 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010471 case TARGET_NR_fgetxattr:
10472 {
10473 void *n, *v = 0;
10474 if (arg3) {
10475 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10476 if (!v) {
10477 ret = -TARGET_EFAULT;
10478 break;
10479 }
10480 }
10481 n = lock_user_string(arg2);
10482 if (n) {
10483 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10484 } else {
10485 ret = -TARGET_EFAULT;
10486 }
10487 unlock_user(n, arg2, 0);
10488 unlock_user(v, arg3, arg4);
10489 }
10490 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010491 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010492 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010493 {
10494 void *p, *n;
10495 p = lock_user_string(arg1);
10496 n = lock_user_string(arg2);
10497 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010498 if (num == TARGET_NR_removexattr) {
10499 ret = get_errno(removexattr(p, n));
10500 } else {
10501 ret = get_errno(lremovexattr(p, n));
10502 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010503 } else {
10504 ret = -TARGET_EFAULT;
10505 }
10506 unlock_user(p, arg1, 0);
10507 unlock_user(n, arg2, 0);
10508 }
10509 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010510 case TARGET_NR_fremovexattr:
10511 {
10512 void *n;
10513 n = lock_user_string(arg2);
10514 if (n) {
10515 ret = get_errno(fremovexattr(arg1, n));
10516 } else {
10517 ret = -TARGET_EFAULT;
10518 }
10519 unlock_user(n, arg2, 0);
10520 }
10521 break;
bellardebc05482003-09-30 21:08:41 +000010522#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010523#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010524#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010525 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010526#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010527 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010528 ret = 0;
10529 break;
edgar_iglef967792009-01-07 14:19:38 +000010530#elif defined(TARGET_CRIS)
10531 if (arg1 & 0xff)
10532 ret = -TARGET_EINVAL;
10533 else {
10534 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10535 ret = 0;
10536 }
10537 break;
bellard8d18e892007-11-14 15:18:40 +000010538#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10539 ret = do_set_thread_area(cpu_env, arg1);
10540 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010541#elif defined(TARGET_M68K)
10542 {
Andreas Färber0429a972013-08-26 18:14:44 +020010543 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010544 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010545 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010546 break;
10547 }
ths6f5b89a2007-03-02 20:48:00 +000010548#else
10549 goto unimplemented_nowarn;
10550#endif
10551#endif
10552#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010553 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010554#if defined(TARGET_I386) && defined(TARGET_ABI32)
10555 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010556 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010557#elif defined(TARGET_M68K)
10558 {
Andreas Färber0429a972013-08-26 18:14:44 +020010559 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010560 ret = ts->tp_value;
10561 break;
10562 }
bellard8d18e892007-11-14 15:18:40 +000010563#else
bellard5cd43932003-03-29 16:54:36 +000010564 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010565#endif
bellard8d18e892007-11-14 15:18:40 +000010566#endif
bellard48dc41e2006-06-21 18:15:50 +000010567#ifdef TARGET_NR_getdomainname
10568 case TARGET_NR_getdomainname:
10569 goto unimplemented_nowarn;
10570#endif
ths6f5b89a2007-03-02 20:48:00 +000010571
thsb5906f92007-03-19 13:32:45 +000010572#ifdef TARGET_NR_clock_gettime
10573 case TARGET_NR_clock_gettime:
10574 {
10575 struct timespec ts;
10576 ret = get_errno(clock_gettime(arg1, &ts));
10577 if (!is_error(ret)) {
10578 host_to_target_timespec(arg2, &ts);
10579 }
10580 break;
10581 }
10582#endif
10583#ifdef TARGET_NR_clock_getres
10584 case TARGET_NR_clock_getres:
10585 {
10586 struct timespec ts;
10587 ret = get_errno(clock_getres(arg1, &ts));
10588 if (!is_error(ret)) {
10589 host_to_target_timespec(arg2, &ts);
10590 }
10591 break;
10592 }
10593#endif
pbrook63d76512008-05-29 13:43:29 +000010594#ifdef TARGET_NR_clock_nanosleep
10595 case TARGET_NR_clock_nanosleep:
10596 {
10597 struct timespec ts;
10598 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010010599 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
10600 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000010601 if (arg4)
10602 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010603
10604#if defined(TARGET_PPC)
10605 /* clock_nanosleep is odd in that it returns positive errno values.
10606 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010010607 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010608 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10609 }
10610#endif
pbrook63d76512008-05-29 13:43:29 +000010611 break;
10612 }
10613#endif
thsb5906f92007-03-19 13:32:45 +000010614
ths6f5b89a2007-03-02 20:48:00 +000010615#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10616 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010617 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10618 break;
ths6f5b89a2007-03-02 20:48:00 +000010619#endif
10620
ths4cae1d12007-07-12 11:06:53 +000010621 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010622 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010623 break;
ths4cae1d12007-07-12 11:06:53 +000010624
ths71455572007-06-21 21:45:30 +000010625 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010626 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000010627 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010010628 break;
ths71455572007-06-21 21:45:30 +000010629
ths4f2b1fe2007-06-21 21:57:12 +000010630#ifdef TARGET_NR_set_robust_list
10631 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010632 case TARGET_NR_get_robust_list:
10633 /* The ABI for supporting robust futexes has userspace pass
10634 * the kernel a pointer to a linked list which is updated by
10635 * userspace after the syscall; the list is walked by the kernel
10636 * when the thread exits. Since the linked list in QEMU guest
10637 * memory isn't a valid linked list for the host and we have
10638 * no way to reliably intercept the thread-death event, we can't
10639 * support these. Silently return ENOSYS so that guest userspace
10640 * falls back to a non-robust futex implementation (which should
10641 * be OK except in the corner case of the guest crashing while
10642 * holding a mutex that is shared with another process via
10643 * shared memory).
10644 */
10645 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010646#endif
10647
Peter Maydell1acae9f2013-07-02 14:04:12 +010010648#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010649 case TARGET_NR_utimensat:
10650 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010651 struct timespec *tsp, ts[2];
10652 if (!arg3) {
10653 tsp = NULL;
10654 } else {
10655 target_to_host_timespec(ts, arg3);
10656 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10657 tsp = ts;
10658 }
ths9007f0e2007-09-25 17:50:37 +000010659 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010660 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010661 else {
bellard579a97f2007-11-11 14:26:47 +000010662 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010663 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010664 goto fail;
10665 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010666 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010667 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010668 }
10669 }
10670 break;
10671#endif
pbrookbd0c5662008-05-29 14:34:11 +000010672 case TARGET_NR_futex:
10673 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10674 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010675#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010676 case TARGET_NR_inotify_init:
10677 ret = get_errno(sys_inotify_init());
10678 break;
10679#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010680#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010681#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10682 case TARGET_NR_inotify_init1:
10683 ret = get_errno(sys_inotify_init1(arg1));
10684 break;
10685#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010686#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010687#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010688 case TARGET_NR_inotify_add_watch:
10689 p = lock_user_string(arg2);
10690 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10691 unlock_user(p, arg2, 0);
10692 break;
10693#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010694#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010695 case TARGET_NR_inotify_rm_watch:
10696 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10697 break;
10698#endif
ths9007f0e2007-09-25 17:50:37 +000010699
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010700#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010701 case TARGET_NR_mq_open:
10702 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010703 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010704
10705 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010706 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010707 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010708 attrp = &posix_mq_attr;
10709 } else {
10710 attrp = 0;
10711 }
10712 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010713 unlock_user (p, arg1, 0);
10714 }
10715 break;
10716
10717 case TARGET_NR_mq_unlink:
10718 p = lock_user_string(arg1 - 1);
10719 ret = get_errno(mq_unlink(p));
10720 unlock_user (p, arg1, 0);
10721 break;
10722
10723 case TARGET_NR_mq_timedsend:
10724 {
10725 struct timespec ts;
10726
10727 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10728 if (arg5 != 0) {
10729 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010730 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000010731 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010732 } else {
10733 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000010734 }
aurel3224e10032009-04-15 16:11:43 +000010735 unlock_user (p, arg2, arg3);
10736 }
10737 break;
10738
10739 case TARGET_NR_mq_timedreceive:
10740 {
10741 struct timespec ts;
10742 unsigned int prio;
10743
10744 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10745 if (arg5 != 0) {
10746 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010747 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10748 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000010749 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010750 } else {
10751 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10752 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000010753 }
aurel3224e10032009-04-15 16:11:43 +000010754 unlock_user (p, arg2, arg3);
10755 if (arg4 != 0)
10756 put_user_u32(prio, arg4);
10757 }
10758 break;
10759
10760 /* Not implemented for now... */
10761/* case TARGET_NR_mq_notify: */
10762/* break; */
10763
10764 case TARGET_NR_mq_getsetattr:
10765 {
10766 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10767 ret = 0;
10768 if (arg3 != 0) {
10769 ret = mq_getattr(arg1, &posix_mq_attr_out);
10770 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10771 }
10772 if (arg2 != 0) {
10773 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10774 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10775 }
10776
10777 }
10778 break;
10779#endif
10780
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010781#ifdef CONFIG_SPLICE
10782#ifdef TARGET_NR_tee
10783 case TARGET_NR_tee:
10784 {
10785 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10786 }
10787 break;
10788#endif
10789#ifdef TARGET_NR_splice
10790 case TARGET_NR_splice:
10791 {
10792 loff_t loff_in, loff_out;
10793 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010794 if (arg2) {
10795 if (get_user_u64(loff_in, arg2)) {
10796 goto efault;
10797 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010798 ploff_in = &loff_in;
10799 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010800 if (arg4) {
10801 if (get_user_u64(loff_out, arg4)) {
10802 goto efault;
10803 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010804 ploff_out = &loff_out;
10805 }
10806 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010807 if (arg2) {
10808 if (put_user_u64(loff_in, arg2)) {
10809 goto efault;
10810 }
10811 }
10812 if (arg4) {
10813 if (put_user_u64(loff_out, arg4)) {
10814 goto efault;
10815 }
10816 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010817 }
10818 break;
10819#endif
10820#ifdef TARGET_NR_vmsplice
10821 case TARGET_NR_vmsplice:
10822 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010823 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10824 if (vec != NULL) {
10825 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10826 unlock_iovec(vec, arg2, arg3, 0);
10827 } else {
10828 ret = -host_to_target_errno(errno);
10829 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010830 }
10831 break;
10832#endif
10833#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010834#ifdef CONFIG_EVENTFD
10835#if defined(TARGET_NR_eventfd)
10836 case TARGET_NR_eventfd:
10837 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010838 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010839 break;
10840#endif
10841#if defined(TARGET_NR_eventfd2)
10842 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010843 {
10844 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10845 if (arg2 & TARGET_O_NONBLOCK) {
10846 host_flags |= O_NONBLOCK;
10847 }
10848 if (arg2 & TARGET_O_CLOEXEC) {
10849 host_flags |= O_CLOEXEC;
10850 }
10851 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010852 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010853 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010854 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010855#endif
10856#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010857#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10858 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010859#if TARGET_ABI_BITS == 32
10860 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10861 target_offset64(arg5, arg6)));
10862#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010863 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010864#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010865 break;
10866#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010867#if defined(CONFIG_SYNC_FILE_RANGE)
10868#if defined(TARGET_NR_sync_file_range)
10869 case TARGET_NR_sync_file_range:
10870#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010871#if defined(TARGET_MIPS)
10872 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10873 target_offset64(arg5, arg6), arg7));
10874#else
Peter Maydellc727f472011-01-06 11:05:10 +000010875 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10876 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010877#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010878#else
10879 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10880#endif
10881 break;
10882#endif
10883#if defined(TARGET_NR_sync_file_range2)
10884 case TARGET_NR_sync_file_range2:
10885 /* This is like sync_file_range but the arguments are reordered */
10886#if TARGET_ABI_BITS == 32
10887 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10888 target_offset64(arg5, arg6), arg2));
10889#else
10890 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10891#endif
10892 break;
10893#endif
10894#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010895#if defined(TARGET_NR_signalfd4)
10896 case TARGET_NR_signalfd4:
10897 ret = do_signalfd4(arg1, arg2, arg4);
10898 break;
10899#endif
10900#if defined(TARGET_NR_signalfd)
10901 case TARGET_NR_signalfd:
10902 ret = do_signalfd4(arg1, arg2, 0);
10903 break;
10904#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010905#if defined(CONFIG_EPOLL)
10906#if defined(TARGET_NR_epoll_create)
10907 case TARGET_NR_epoll_create:
10908 ret = get_errno(epoll_create(arg1));
10909 break;
10910#endif
10911#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10912 case TARGET_NR_epoll_create1:
10913 ret = get_errno(epoll_create1(arg1));
10914 break;
10915#endif
10916#if defined(TARGET_NR_epoll_ctl)
10917 case TARGET_NR_epoll_ctl:
10918 {
10919 struct epoll_event ep;
10920 struct epoll_event *epp = 0;
10921 if (arg4) {
10922 struct target_epoll_event *target_ep;
10923 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10924 goto efault;
10925 }
10926 ep.events = tswap32(target_ep->events);
10927 /* The epoll_data_t union is just opaque data to the kernel,
10928 * so we transfer all 64 bits across and need not worry what
10929 * actual data type it is.
10930 */
10931 ep.data.u64 = tswap64(target_ep->data.u64);
10932 unlock_user_struct(target_ep, arg4, 0);
10933 epp = &ep;
10934 }
10935 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10936 break;
10937 }
10938#endif
10939
Peter Maydell227f0212016-06-06 19:58:11 +010010940#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010941#if defined(TARGET_NR_epoll_wait)
10942 case TARGET_NR_epoll_wait:
10943#endif
Peter Maydell227f0212016-06-06 19:58:11 +010010944#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010945 case TARGET_NR_epoll_pwait:
10946#endif
10947 {
10948 struct target_epoll_event *target_ep;
10949 struct epoll_event *ep;
10950 int epfd = arg1;
10951 int maxevents = arg3;
10952 int timeout = arg4;
10953
10954 target_ep = lock_user(VERIFY_WRITE, arg2,
10955 maxevents * sizeof(struct target_epoll_event), 1);
10956 if (!target_ep) {
10957 goto efault;
10958 }
10959
10960 ep = alloca(maxevents * sizeof(struct epoll_event));
10961
10962 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010010963#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010964 case TARGET_NR_epoll_pwait:
10965 {
10966 target_sigset_t *target_set;
10967 sigset_t _set, *set = &_set;
10968
10969 if (arg5) {
10970 target_set = lock_user(VERIFY_READ, arg5,
10971 sizeof(target_sigset_t), 1);
10972 if (!target_set) {
10973 unlock_user(target_ep, arg2, 0);
10974 goto efault;
10975 }
10976 target_to_host_sigset(set, target_set);
10977 unlock_user(target_set, arg5, 0);
10978 } else {
10979 set = NULL;
10980 }
10981
Peter Maydell227f0212016-06-06 19:58:11 +010010982 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10983 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010984 break;
10985 }
10986#endif
10987#if defined(TARGET_NR_epoll_wait)
10988 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010010989 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
10990 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000010991 break;
10992#endif
10993 default:
10994 ret = -TARGET_ENOSYS;
10995 }
10996 if (!is_error(ret)) {
10997 int i;
10998 for (i = 0; i < ret; i++) {
10999 target_ep[i].events = tswap32(ep[i].events);
11000 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11001 }
11002 }
11003 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
11004 break;
11005 }
11006#endif
11007#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011008#ifdef TARGET_NR_prlimit64
11009 case TARGET_NR_prlimit64:
11010 {
11011 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11012 struct target_rlimit64 *target_rnew, *target_rold;
11013 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011014 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011015 if (arg3) {
11016 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
11017 goto efault;
11018 }
11019 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11020 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11021 unlock_user_struct(target_rnew, arg3, 0);
11022 rnewp = &rnew;
11023 }
11024
Felix Janda95018012014-12-02 22:11:17 +010011025 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011026 if (!is_error(ret) && arg4) {
11027 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
11028 goto efault;
11029 }
11030 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11031 target_rold->rlim_max = tswap64(rold.rlim_max);
11032 unlock_user_struct(target_rold, arg4, 1);
11033 }
11034 break;
11035 }
11036#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011037#ifdef TARGET_NR_gethostname
11038 case TARGET_NR_gethostname:
11039 {
11040 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11041 if (name) {
11042 ret = get_errno(gethostname(name, arg2));
11043 unlock_user(name, arg1, arg2);
11044 } else {
11045 ret = -TARGET_EFAULT;
11046 }
11047 break;
11048 }
11049#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011050#ifdef TARGET_NR_atomic_cmpxchg_32
11051 case TARGET_NR_atomic_cmpxchg_32:
11052 {
11053 /* should use start_exclusive from main.c */
11054 abi_ulong mem_value;
11055 if (get_user_u32(mem_value, arg6)) {
11056 target_siginfo_t info;
11057 info.si_signo = SIGSEGV;
11058 info.si_errno = 0;
11059 info.si_code = TARGET_SEGV_MAPERR;
11060 info._sifields._sigfault._addr = arg6;
11061 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11062 ret = 0xdeadbeef;
11063
11064 }
11065 if (mem_value == arg2)
11066 put_user_u32(arg1, arg6);
11067 ret = mem_value;
11068 break;
11069 }
11070#endif
11071#ifdef TARGET_NR_atomic_barrier
11072 case TARGET_NR_atomic_barrier:
11073 {
11074 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011075 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011076 break;
11077 }
11078#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011079
11080#ifdef TARGET_NR_timer_create
11081 case TARGET_NR_timer_create:
11082 {
11083 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11084
11085 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011086
11087 int clkid = arg1;
11088 int timer_index = next_free_host_timer();
11089
11090 if (timer_index < 0) {
11091 ret = -TARGET_EAGAIN;
11092 } else {
11093 timer_t *phtimer = g_posix_timers + timer_index;
11094
11095 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011096 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011097 ret = target_to_host_sigevent(phost_sevp, arg2);
11098 if (ret != 0) {
11099 break;
11100 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011101 }
11102
11103 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11104 if (ret) {
11105 phtimer = NULL;
11106 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011107 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011108 goto efault;
11109 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011110 }
11111 }
11112 break;
11113 }
11114#endif
11115
11116#ifdef TARGET_NR_timer_settime
11117 case TARGET_NR_timer_settime:
11118 {
11119 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11120 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011121 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011122
Alexander Grafaecc8862014-11-10 21:33:03 +010011123 if (timerid < 0) {
11124 ret = timerid;
11125 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011126 ret = -TARGET_EINVAL;
11127 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011128 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011129 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11130
11131 target_to_host_itimerspec(&hspec_new, arg3);
11132 ret = get_errno(
11133 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11134 host_to_target_itimerspec(arg2, &hspec_old);
11135 }
11136 break;
11137 }
11138#endif
11139
11140#ifdef TARGET_NR_timer_gettime
11141 case TARGET_NR_timer_gettime:
11142 {
11143 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011144 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011145
Alexander Grafaecc8862014-11-10 21:33:03 +010011146 if (timerid < 0) {
11147 ret = timerid;
11148 } else if (!arg2) {
11149 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011150 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011151 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011152 struct itimerspec hspec;
11153 ret = get_errno(timer_gettime(htimer, &hspec));
11154
11155 if (host_to_target_itimerspec(arg2, &hspec)) {
11156 ret = -TARGET_EFAULT;
11157 }
11158 }
11159 break;
11160 }
11161#endif
11162
11163#ifdef TARGET_NR_timer_getoverrun
11164 case TARGET_NR_timer_getoverrun:
11165 {
11166 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011167 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011168
Alexander Grafaecc8862014-11-10 21:33:03 +010011169 if (timerid < 0) {
11170 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011171 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011172 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011173 ret = get_errno(timer_getoverrun(htimer));
11174 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011175 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011176 break;
11177 }
11178#endif
11179
11180#ifdef TARGET_NR_timer_delete
11181 case TARGET_NR_timer_delete:
11182 {
11183 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011184 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011185
Alexander Grafaecc8862014-11-10 21:33:03 +010011186 if (timerid < 0) {
11187 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011188 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011189 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011190 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011191 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011192 }
11193 break;
11194 }
11195#endif
11196
Riku Voipio51834342014-06-22 11:25:42 +010011197#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11198 case TARGET_NR_timerfd_create:
11199 ret = get_errno(timerfd_create(arg1,
11200 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11201 break;
11202#endif
11203
11204#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11205 case TARGET_NR_timerfd_gettime:
11206 {
11207 struct itimerspec its_curr;
11208
11209 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11210
11211 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11212 goto efault;
11213 }
11214 }
11215 break;
11216#endif
11217
11218#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11219 case TARGET_NR_timerfd_settime:
11220 {
11221 struct itimerspec its_new, its_old, *p_new;
11222
11223 if (arg3) {
11224 if (target_to_host_itimerspec(&its_new, arg3)) {
11225 goto efault;
11226 }
11227 p_new = &its_new;
11228 } else {
11229 p_new = NULL;
11230 }
11231
11232 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11233
11234 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11235 goto efault;
11236 }
11237 }
11238 break;
11239#endif
11240
Paul Burtonab31cda2014-06-22 11:25:43 +010011241#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11242 case TARGET_NR_ioprio_get:
11243 ret = get_errno(ioprio_get(arg1, arg2));
11244 break;
11245#endif
11246
11247#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11248 case TARGET_NR_ioprio_set:
11249 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11250 break;
11251#endif
11252
Riku Voipio9af5c902014-08-12 15:58:57 +030011253#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11254 case TARGET_NR_setns:
11255 ret = get_errno(setns(arg1, arg2));
11256 break;
11257#endif
11258#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11259 case TARGET_NR_unshare:
11260 ret = get_errno(unshare(arg1));
11261 break;
11262#endif
11263
bellard31e31b82003-02-18 22:55:36 +000011264 default:
11265 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011266 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011267#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 +000011268 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011269#endif
ths0da46a62007-10-20 20:23:07 +000011270 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011271 break;
11272 }
bellard579a97f2007-11-11 14:26:47 +000011273fail:
bellardc573ff62004-01-04 15:51:36 +000011274#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011275 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011276#endif
thsb92c47c2007-11-01 00:07:38 +000011277 if(do_strace)
11278 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020011279 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000011280 return ret;
bellard579a97f2007-11-11 14:26:47 +000011281efault:
11282 ret = -TARGET_EFAULT;
11283 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011284}