blob: 919b589b0e24463fe4574636760a7cbfc3597dbe [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 Viviera82ea932016-06-27 00:18:22 +0200103#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200104#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200105#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200106#include <linux/rtnetlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200107#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200108#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000109#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200110#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000111
bellard3ef693a2003-03-23 20:17:16 +0000112#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000113
pbrookd865bab2008-06-07 22:12:17 +0000114#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
115 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000116
bellard72f03902003-02-18 23:33:18 +0000117//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100118/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
119 * once. This exercises the codepaths for restart.
120 */
121//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000122
bellard1a9353d2003-03-16 20:28:50 +0000123//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000124#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
125#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000126
bellard70a194b2003-08-11 22:20:16 +0000127#undef _syscall0
128#undef _syscall1
129#undef _syscall2
130#undef _syscall3
131#undef _syscall4
132#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000133#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000134
bellard83fcb512006-06-14 13:37:16 +0000135#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000136static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000137{ \
138 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000139}
140
bellard83fcb512006-06-14 13:37:16 +0000141#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000142static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000143{ \
144 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000145}
146
bellard83fcb512006-06-14 13:37:16 +0000147#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000148static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000149{ \
150 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000151}
152
bellard83fcb512006-06-14 13:37:16 +0000153#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000154static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000155{ \
156 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000157}
158
bellard83fcb512006-06-14 13:37:16 +0000159#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000160static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000161{ \
162 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000163}
164
bellard83fcb512006-06-14 13:37:16 +0000165#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
166 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000167static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000168{ \
169 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000170}
bellard83fcb512006-06-14 13:37:16 +0000171
172
173#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
174 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000175static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
176 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000177{ \
178 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
179}
180
bellard70a194b2003-08-11 22:20:16 +0000181
bellard31e31b82003-02-18 22:55:36 +0000182#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000183#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000185#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000186#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000187#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000188#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000189#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000190#define __NR_sys_inotify_init __NR_inotify_init
191#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
192#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000193
Alexander Graf42a39fb2011-04-15 17:32:45 +0200194#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
195 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000196#define __NR__llseek __NR_lseek
197#endif
198
James Hogana29e5ba2014-03-25 21:51:08 +0000199/* Newer kernel ports have llseek() instead of _llseek() */
200#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
201#define TARGET_NR__llseek TARGET_NR_llseek
202#endif
203
bellard72f03902003-02-18 23:33:18 +0000204#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000205_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000206#else
ths0da46a62007-10-20 20:23:07 +0000207/* This is a replacement for the host gettid() and must return a host
208 errno. */
bellard72f03902003-02-18 23:33:18 +0000209static int gettid(void) {
210 return -ENOSYS;
211}
212#endif
Chen Gang704eff62015-08-21 05:37:33 +0800213#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100215#endif
216#if !defined(__NR_getdents) || \
217 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
219#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700220#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000221_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
222 loff_t *, res, uint, wh);
223#endif
224_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
225_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000226#ifdef __NR_exit_group
227_syscall1(int,exit_group,int,error_code)
228#endif
229#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
230_syscall1(int,set_tid_address,int *,tidptr)
231#endif
aurel323b3f24a2009-04-15 16:12:13 +0000232#if defined(TARGET_NR_futex) && defined(__NR_futex)
233_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
234 const struct timespec *,timeout,int *,uaddr2,int,val3)
235#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500236#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
237_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
238 unsigned long *, user_mask_ptr);
239#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
240_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
241 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200242_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
243 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000244_syscall2(int, capget, struct __user_cap_header_struct *, header,
245 struct __user_cap_data_struct *, data);
246_syscall2(int, capset, struct __user_cap_header_struct *, header,
247 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100248#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
249_syscall2(int, ioprio_get, int, which, int, who)
250#endif
251#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
252_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
253#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100254#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
255_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
256#endif
aurel323b3f24a2009-04-15 16:12:13 +0000257
258static bitmask_transtbl fcntl_flags_tbl[] = {
259 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
260 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
261 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
262 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
263 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
264 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
265 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
266 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700267 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000268 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
269 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
270 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
271 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000272#if defined(O_DIRECT)
273 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
274#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700275#if defined(O_NOATIME)
276 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
277#endif
278#if defined(O_CLOEXEC)
279 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
280#endif
281#if defined(O_PATH)
282 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
283#endif
284 /* Don't terminate the list prematurely on 64-bit host+guest. */
285#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
286 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
287#endif
aurel323b3f24a2009-04-15 16:12:13 +0000288 { 0, 0, 0, 0 }
289};
290
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100291typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100292typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200293typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100294 TargetFdDataFunc host_to_target_data;
295 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100296 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200297} TargetFdTrans;
298
299static TargetFdTrans **target_fd_trans;
300
301static unsigned int target_fd_max;
302
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200303static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
304{
305 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
306 return target_fd_trans[fd]->target_to_host_data;
307 }
308 return NULL;
309}
310
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100311static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200312{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100313 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100314 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200315 }
316 return NULL;
317}
318
Laurent Vivier7b36f782015-10-28 21:40:44 +0100319static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
320{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100321 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100322 return target_fd_trans[fd]->target_to_host_addr;
323 }
324 return NULL;
325}
326
Laurent Viviere36800c2015-10-02 14:48:09 +0200327static void fd_trans_register(int fd, TargetFdTrans *trans)
328{
329 unsigned int oldmax;
330
331 if (fd >= target_fd_max) {
332 oldmax = target_fd_max;
333 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100334 target_fd_trans = g_renew(TargetFdTrans *,
335 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200336 memset((void *)(target_fd_trans + oldmax), 0,
337 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
338 }
339 target_fd_trans[fd] = trans;
340}
341
342static void fd_trans_unregister(int fd)
343{
344 if (fd >= 0 && fd < target_fd_max) {
345 target_fd_trans[fd] = NULL;
346 }
347}
348
349static void fd_trans_dup(int oldfd, int newfd)
350{
351 fd_trans_unregister(newfd);
352 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
353 fd_trans_register(newfd, target_fd_trans[oldfd]);
354 }
355}
356
aurel323b3f24a2009-04-15 16:12:13 +0000357static int sys_getcwd1(char *buf, size_t size)
358{
359 if (getcwd(buf, size) == NULL) {
360 /* getcwd() sets errno */
361 return (-1);
362 }
aurel32aaf4ad32009-04-16 14:17:14 +0000363 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000364}
365
Peter Maydell1acae9f2013-07-02 14:04:12 +0100366#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300367#ifdef CONFIG_UTIMENSAT
368static int sys_utimensat(int dirfd, const char *pathname,
369 const struct timespec times[2], int flags)
370{
371 if (pathname == NULL)
372 return futimens(dirfd, times);
373 else
374 return utimensat(dirfd, pathname, times, flags);
375}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100376#elif defined(__NR_utimensat)
377#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000378_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
379 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100380#else
381static int sys_utimensat(int dirfd, const char *pathname,
382 const struct timespec times[2], int flags)
383{
384 errno = ENOSYS;
385 return -1;
386}
ths9007f0e2007-09-25 17:50:37 +0000387#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100388#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000389
390#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000391#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000392
aurel3239b59762008-10-01 21:46:50 +0000393#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000394static int sys_inotify_init(void)
395{
396 return (inotify_init());
397}
aurel3239b59762008-10-01 21:46:50 +0000398#endif
399#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000400static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
401{
402 return (inotify_add_watch(fd, pathname, mask));
403}
aurel3239b59762008-10-01 21:46:50 +0000404#endif
405#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000406static int sys_inotify_rm_watch(int fd, int32_t wd)
407{
aurel328690e422009-04-17 13:50:32 +0000408 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000409}
aurel3239b59762008-10-01 21:46:50 +0000410#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000411#ifdef CONFIG_INOTIFY1
412#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
413static int sys_inotify_init1(int flags)
414{
415 return (inotify_init1(flags));
416}
417#endif
418#endif
aurel323b3f24a2009-04-15 16:12:13 +0000419#else
420/* Userspace can usually survive runtime without inotify */
421#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000422#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000423#undef TARGET_NR_inotify_add_watch
424#undef TARGET_NR_inotify_rm_watch
425#endif /* CONFIG_INOTIFY */
426
Peter Maydell163a05a2011-06-27 17:44:52 +0100427#if defined(TARGET_NR_prlimit64)
428#ifndef __NR_prlimit64
429# define __NR_prlimit64 -1
430#endif
431#define __NR_sys_prlimit64 __NR_prlimit64
432/* The glibc rlimit structure may not be that used by the underlying syscall */
433struct host_rlimit64 {
434 uint64_t rlim_cur;
435 uint64_t rlim_max;
436};
437_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
438 const struct host_rlimit64 *, new_limit,
439 struct host_rlimit64 *, old_limit)
440#endif
441
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100442
443#if defined(TARGET_NR_timer_create)
444/* Maxiumum of 32 active POSIX timers allowed at any one time. */
445static timer_t g_posix_timers[32] = { 0, } ;
446
447static inline int next_free_host_timer(void)
448{
449 int k ;
450 /* FIXME: Does finding the next free slot require a lock? */
451 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
452 if (g_posix_timers[k] == 0) {
453 g_posix_timers[k] = (timer_t) 1;
454 return k;
455 }
456 }
457 return -1;
458}
459#endif
460
Riku Voipio48e515d2011-07-12 15:40:51 +0300461/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000462#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300463static inline int regpairs_aligned(void *cpu_env) {
464 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
465}
466#elif defined(TARGET_MIPS)
467static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000468#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
469/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
470 * of registers which translates to the same as ARM/MIPS, because we start with
471 * r3 as arg1 */
472static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300473#else
474static inline int regpairs_aligned(void *cpu_env) { return 0; }
475#endif
476
thsb92c47c2007-11-01 00:07:38 +0000477#define ERRNO_TABLE_SIZE 1200
478
479/* target_to_host_errno_table[] is initialized from
480 * host_to_target_errno_table[] in syscall_init(). */
481static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
482};
483
ths637947f2007-06-01 12:09:19 +0000484/*
thsfe8f0962007-07-12 10:59:21 +0000485 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000486 * minus the errnos that are not actually generic to all archs.
487 */
thsb92c47c2007-11-01 00:07:38 +0000488static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800489 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000490 [EIDRM] = TARGET_EIDRM,
491 [ECHRNG] = TARGET_ECHRNG,
492 [EL2NSYNC] = TARGET_EL2NSYNC,
493 [EL3HLT] = TARGET_EL3HLT,
494 [EL3RST] = TARGET_EL3RST,
495 [ELNRNG] = TARGET_ELNRNG,
496 [EUNATCH] = TARGET_EUNATCH,
497 [ENOCSI] = TARGET_ENOCSI,
498 [EL2HLT] = TARGET_EL2HLT,
499 [EDEADLK] = TARGET_EDEADLK,
500 [ENOLCK] = TARGET_ENOLCK,
501 [EBADE] = TARGET_EBADE,
502 [EBADR] = TARGET_EBADR,
503 [EXFULL] = TARGET_EXFULL,
504 [ENOANO] = TARGET_ENOANO,
505 [EBADRQC] = TARGET_EBADRQC,
506 [EBADSLT] = TARGET_EBADSLT,
507 [EBFONT] = TARGET_EBFONT,
508 [ENOSTR] = TARGET_ENOSTR,
509 [ENODATA] = TARGET_ENODATA,
510 [ETIME] = TARGET_ETIME,
511 [ENOSR] = TARGET_ENOSR,
512 [ENONET] = TARGET_ENONET,
513 [ENOPKG] = TARGET_ENOPKG,
514 [EREMOTE] = TARGET_EREMOTE,
515 [ENOLINK] = TARGET_ENOLINK,
516 [EADV] = TARGET_EADV,
517 [ESRMNT] = TARGET_ESRMNT,
518 [ECOMM] = TARGET_ECOMM,
519 [EPROTO] = TARGET_EPROTO,
520 [EDOTDOT] = TARGET_EDOTDOT,
521 [EMULTIHOP] = TARGET_EMULTIHOP,
522 [EBADMSG] = TARGET_EBADMSG,
523 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
524 [EOVERFLOW] = TARGET_EOVERFLOW,
525 [ENOTUNIQ] = TARGET_ENOTUNIQ,
526 [EBADFD] = TARGET_EBADFD,
527 [EREMCHG] = TARGET_EREMCHG,
528 [ELIBACC] = TARGET_ELIBACC,
529 [ELIBBAD] = TARGET_ELIBBAD,
530 [ELIBSCN] = TARGET_ELIBSCN,
531 [ELIBMAX] = TARGET_ELIBMAX,
532 [ELIBEXEC] = TARGET_ELIBEXEC,
533 [EILSEQ] = TARGET_EILSEQ,
534 [ENOSYS] = TARGET_ENOSYS,
535 [ELOOP] = TARGET_ELOOP,
536 [ERESTART] = TARGET_ERESTART,
537 [ESTRPIPE] = TARGET_ESTRPIPE,
538 [ENOTEMPTY] = TARGET_ENOTEMPTY,
539 [EUSERS] = TARGET_EUSERS,
540 [ENOTSOCK] = TARGET_ENOTSOCK,
541 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
542 [EMSGSIZE] = TARGET_EMSGSIZE,
543 [EPROTOTYPE] = TARGET_EPROTOTYPE,
544 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
545 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
546 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
547 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
548 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
549 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
550 [EADDRINUSE] = TARGET_EADDRINUSE,
551 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
552 [ENETDOWN] = TARGET_ENETDOWN,
553 [ENETUNREACH] = TARGET_ENETUNREACH,
554 [ENETRESET] = TARGET_ENETRESET,
555 [ECONNABORTED] = TARGET_ECONNABORTED,
556 [ECONNRESET] = TARGET_ECONNRESET,
557 [ENOBUFS] = TARGET_ENOBUFS,
558 [EISCONN] = TARGET_EISCONN,
559 [ENOTCONN] = TARGET_ENOTCONN,
560 [EUCLEAN] = TARGET_EUCLEAN,
561 [ENOTNAM] = TARGET_ENOTNAM,
562 [ENAVAIL] = TARGET_ENAVAIL,
563 [EISNAM] = TARGET_EISNAM,
564 [EREMOTEIO] = TARGET_EREMOTEIO,
565 [ESHUTDOWN] = TARGET_ESHUTDOWN,
566 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
567 [ETIMEDOUT] = TARGET_ETIMEDOUT,
568 [ECONNREFUSED] = TARGET_ECONNREFUSED,
569 [EHOSTDOWN] = TARGET_EHOSTDOWN,
570 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
571 [EALREADY] = TARGET_EALREADY,
572 [EINPROGRESS] = TARGET_EINPROGRESS,
573 [ESTALE] = TARGET_ESTALE,
574 [ECANCELED] = TARGET_ECANCELED,
575 [ENOMEDIUM] = TARGET_ENOMEDIUM,
576 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000577#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000578 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000579#endif
580#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000581 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000582#endif
583#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000584 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000585#endif
586#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000587 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000588#endif
589#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000590 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000591#endif
592#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000593 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000594#endif
thsb92c47c2007-11-01 00:07:38 +0000595};
ths637947f2007-06-01 12:09:19 +0000596
597static inline int host_to_target_errno(int err)
598{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100599 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
600 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000601 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100602 }
ths637947f2007-06-01 12:09:19 +0000603 return err;
604}
605
thsb92c47c2007-11-01 00:07:38 +0000606static inline int target_to_host_errno(int err)
607{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100608 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
609 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000610 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100611 }
thsb92c47c2007-11-01 00:07:38 +0000612 return err;
613}
614
blueswir1992f48a2007-10-14 16:27:31 +0000615static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000616{
617 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000618 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000619 else
620 return ret;
621}
622
blueswir1992f48a2007-10-14 16:27:31 +0000623static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000624{
blueswir1992f48a2007-10-14 16:27:31 +0000625 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000626}
627
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100628const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000629{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100630 if (err == TARGET_ERESTARTSYS) {
631 return "To be restarted";
632 }
633 if (err == TARGET_QEMU_ESIGRETURN) {
634 return "Successful exit from sigreturn";
635 }
636
Alexander Graf962b2892011-11-21 12:04:07 +0100637 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
638 return NULL;
639 }
thsb92c47c2007-11-01 00:07:38 +0000640 return strerror(target_to_host_errno(err));
641}
642
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100643#define safe_syscall0(type, name) \
644static type safe_##name(void) \
645{ \
646 return safe_syscall(__NR_##name); \
647}
648
649#define safe_syscall1(type, name, type1, arg1) \
650static type safe_##name(type1 arg1) \
651{ \
652 return safe_syscall(__NR_##name, arg1); \
653}
654
655#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
656static type safe_##name(type1 arg1, type2 arg2) \
657{ \
658 return safe_syscall(__NR_##name, arg1, arg2); \
659}
660
661#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
662static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
663{ \
664 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
665}
666
667#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
668 type4, arg4) \
669static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
670{ \
671 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
672}
673
674#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
675 type4, arg4, type5, arg5) \
676static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
677 type5 arg5) \
678{ \
679 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
680}
681
682#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
683 type4, arg4, type5, arg5, type6, arg6) \
684static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
685 type5 arg5, type6 arg6) \
686{ \
687 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
688}
689
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100690safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
691safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100692safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
693 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100694safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
695 struct rusage *, rusage)
696safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
697 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100698safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100699safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
700 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100701safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
702 struct timespec *, tsp, const sigset_t *, sigmask,
703 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100704safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
705 int, maxevents, int, timeout, const sigset_t *, sigmask,
706 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100707safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
708 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100709safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100710safe_syscall2(int, kill, pid_t, pid, int, sig)
711safe_syscall2(int, tkill, int, tid, int, sig)
712safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100713safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
714safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100715safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
716 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100717safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
718 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
719safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
720 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
721safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
722safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100723safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100724safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
725 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100726safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
727 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100728safe_syscall2(int, nanosleep, const struct timespec *, req,
729 struct timespec *, rem)
730#ifdef TARGET_NR_clock_nanosleep
731safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
732 const struct timespec *, req, struct timespec *, rem)
733#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100734#ifdef __NR_msgsnd
735safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
736 int, flags)
737safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
738 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100739safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
740 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100741#else
742/* This host kernel architecture uses a single ipc syscall; fake up
743 * wrappers for the sub-operations to hide this implementation detail.
744 * Annoyingly we can't include linux/ipc.h to get the constant definitions
745 * for the call parameter because some structs in there conflict with the
746 * sys/ipc.h ones. So we just define them here, and rely on them being
747 * the same for all host architectures.
748 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100749#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100750#define Q_MSGSND 11
751#define Q_MSGRCV 12
752#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
753
754safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
755 void *, ptr, long, fifth)
756static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
757{
758 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
759}
760static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
761{
762 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
763}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100764static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
765 const struct timespec *timeout)
766{
767 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
768 (long)timeout);
769}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100770#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100771#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
772safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
773 size_t, len, unsigned, prio, const struct timespec *, timeout)
774safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
775 size_t, len, unsigned *, prio, const struct timespec *, timeout)
776#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100777/* We do ioctl like this rather than via safe_syscall3 to preserve the
778 * "third argument might be integer or pointer or not present" behaviour of
779 * the libc function.
780 */
781#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100782/* Similarly for fcntl. Note that callers must always:
783 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
784 * use the flock64 struct rather than unsuffixed flock
785 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
786 */
787#ifdef __NR_fcntl64
788#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
789#else
790#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
791#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100792
Paul Burton8289d112014-06-22 11:25:33 +0100793static inline int host_to_target_sock_type(int host_type)
794{
795 int target_type;
796
797 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
798 case SOCK_DGRAM:
799 target_type = TARGET_SOCK_DGRAM;
800 break;
801 case SOCK_STREAM:
802 target_type = TARGET_SOCK_STREAM;
803 break;
804 default:
805 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
806 break;
807 }
808
809#if defined(SOCK_CLOEXEC)
810 if (host_type & SOCK_CLOEXEC) {
811 target_type |= TARGET_SOCK_CLOEXEC;
812 }
813#endif
814
815#if defined(SOCK_NONBLOCK)
816 if (host_type & SOCK_NONBLOCK) {
817 target_type |= TARGET_SOCK_NONBLOCK;
818 }
819#endif
820
821 return target_type;
822}
823
blueswir1992f48a2007-10-14 16:27:31 +0000824static abi_ulong target_brk;
825static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000826static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000827
blueswir1992f48a2007-10-14 16:27:31 +0000828void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000829{
blueswir14c1de732007-07-07 20:45:44 +0000830 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000831 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000832}
833
vincent4d1de872011-06-14 21:56:33 +0000834//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
835#define DEBUGF_BRK(message, args...)
836
ths0da46a62007-10-20 20:23:07 +0000837/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000838abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000839{
blueswir1992f48a2007-10-14 16:27:31 +0000840 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000841 int new_alloc_size;
842
Paul Brook3a0c6c42012-02-09 19:04:27 +0000843 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000844
vincent4d1de872011-06-14 21:56:33 +0000845 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000846 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000847 return target_brk;
848 }
849 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000850 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
851 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000852 return target_brk;
853 }
bellard31e31b82003-02-18 22:55:36 +0000854
vincent4d1de872011-06-14 21:56:33 +0000855 /* If the new brk is less than the highest page reserved to the
856 * target heap allocation, set it and we're almost done... */
857 if (new_brk <= brk_page) {
858 /* Heap contents are initialized to zero, as for anonymous
859 * mapped pages. */
860 if (new_brk > target_brk) {
861 memset(g2h(target_brk), 0, new_brk - target_brk);
862 }
bellard31e31b82003-02-18 22:55:36 +0000863 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000864 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000865 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000866 }
867
Peter Maydell00faf082011-04-18 16:34:24 +0100868 /* We need to allocate more memory after the brk... Note that
869 * we don't use MAP_FIXED because that will map over the top of
870 * any existing mapping (like the one with the host libc or qemu
871 * itself); instead we treat "mapped but at wrong address" as
872 * a failure and unmap again.
873 */
vincent4d1de872011-06-14 21:56:33 +0000874 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000875 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000876 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100877 MAP_ANON|MAP_PRIVATE, 0, 0));
878
879 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200880 /* Heap contents are initialized to zero, as for anonymous
881 * mapped pages. Technically the new pages are already
882 * initialized to zero since they *are* anonymous mapped
883 * pages, however we have to take care with the contents that
884 * come from the remaining part of the previous page: it may
885 * contains garbage data due to a previous heap usage (grown
886 * then shrunken). */
887 memset(g2h(target_brk), 0, brk_page - target_brk);
888
Peter Maydell00faf082011-04-18 16:34:24 +0100889 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000890 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000891 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
892 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100893 return target_brk;
894 } else if (mapped_addr != -1) {
895 /* Mapped but at wrong address, meaning there wasn't actually
896 * enough space for this brk.
897 */
898 target_munmap(mapped_addr, new_alloc_size);
899 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000900 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000901 }
902 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000903 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100904 }
balrog7ab240a2008-04-26 12:17:34 +0000905
Richard Henderson7dd46c02010-05-03 10:07:49 -0700906#if defined(TARGET_ALPHA)
907 /* We (partially) emulate OSF/1 on Alpha, which requires we
908 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100909 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700910#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100911 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000912 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000913}
914
ths26edcf42007-12-09 02:25:24 +0000915static inline abi_long copy_from_user_fdset(fd_set *fds,
916 abi_ulong target_fds_addr,
917 int n)
bellard31e31b82003-02-18 22:55:36 +0000918{
ths26edcf42007-12-09 02:25:24 +0000919 int i, nw, j, k;
920 abi_ulong b, *target_fds;
921
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200922 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000923 if (!(target_fds = lock_user(VERIFY_READ,
924 target_fds_addr,
925 sizeof(abi_ulong) * nw,
926 1)))
927 return -TARGET_EFAULT;
928
929 FD_ZERO(fds);
930 k = 0;
931 for (i = 0; i < nw; i++) {
932 /* grab the abi_ulong */
933 __get_user(b, &target_fds[i]);
934 for (j = 0; j < TARGET_ABI_BITS; j++) {
935 /* check the bit inside the abi_ulong */
936 if ((b >> j) & 1)
937 FD_SET(k, fds);
938 k++;
bellard31e31b82003-02-18 22:55:36 +0000939 }
bellard31e31b82003-02-18 22:55:36 +0000940 }
ths26edcf42007-12-09 02:25:24 +0000941
942 unlock_user(target_fds, target_fds_addr, 0);
943
944 return 0;
bellard31e31b82003-02-18 22:55:36 +0000945}
946
Mike Frysinger055e0902011-06-03 17:01:49 -0400947static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
948 abi_ulong target_fds_addr,
949 int n)
950{
951 if (target_fds_addr) {
952 if (copy_from_user_fdset(fds, target_fds_addr, n))
953 return -TARGET_EFAULT;
954 *fds_ptr = fds;
955 } else {
956 *fds_ptr = NULL;
957 }
958 return 0;
959}
960
ths26edcf42007-12-09 02:25:24 +0000961static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
962 const fd_set *fds,
963 int n)
bellard31e31b82003-02-18 22:55:36 +0000964{
bellard31e31b82003-02-18 22:55:36 +0000965 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000966 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000967 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000968
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200969 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000970 if (!(target_fds = lock_user(VERIFY_WRITE,
971 target_fds_addr,
972 sizeof(abi_ulong) * nw,
973 0)))
974 return -TARGET_EFAULT;
975
976 k = 0;
977 for (i = 0; i < nw; i++) {
978 v = 0;
979 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000980 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000981 k++;
bellard31e31b82003-02-18 22:55:36 +0000982 }
ths26edcf42007-12-09 02:25:24 +0000983 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000984 }
ths26edcf42007-12-09 02:25:24 +0000985
986 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
987
988 return 0;
bellard31e31b82003-02-18 22:55:36 +0000989}
990
bellardc596ed12003-07-13 17:32:31 +0000991#if defined(__alpha__)
992#define HOST_HZ 1024
993#else
994#define HOST_HZ 100
995#endif
996
blueswir1992f48a2007-10-14 16:27:31 +0000997static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000998{
999#if HOST_HZ == TARGET_HZ
1000 return ticks;
1001#else
1002 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1003#endif
1004}
1005
bellard579a97f2007-11-11 14:26:47 +00001006static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1007 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001008{
pbrook53a59602006-03-25 19:31:22 +00001009 struct target_rusage *target_rusage;
1010
bellard579a97f2007-11-11 14:26:47 +00001011 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1012 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001013 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1014 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1015 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1016 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1017 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1018 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1019 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1020 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1021 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1022 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1023 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1024 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1025 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1026 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1027 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1028 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1029 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1030 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001031 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001032
1033 return 0;
bellardb4091862003-05-16 15:39:34 +00001034}
1035
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001036static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001037{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001038 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001039 rlim_t result;
1040
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001041 target_rlim_swap = tswapal(target_rlim);
1042 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1043 return RLIM_INFINITY;
1044
1045 result = target_rlim_swap;
1046 if (target_rlim_swap != (rlim_t)result)
1047 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001048
1049 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001050}
1051
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001052static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001053{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001054 abi_ulong target_rlim_swap;
1055 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001056
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001057 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001058 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001059 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001060 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001061 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001062
1063 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001064}
1065
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001066static inline int target_to_host_resource(int code)
1067{
1068 switch (code) {
1069 case TARGET_RLIMIT_AS:
1070 return RLIMIT_AS;
1071 case TARGET_RLIMIT_CORE:
1072 return RLIMIT_CORE;
1073 case TARGET_RLIMIT_CPU:
1074 return RLIMIT_CPU;
1075 case TARGET_RLIMIT_DATA:
1076 return RLIMIT_DATA;
1077 case TARGET_RLIMIT_FSIZE:
1078 return RLIMIT_FSIZE;
1079 case TARGET_RLIMIT_LOCKS:
1080 return RLIMIT_LOCKS;
1081 case TARGET_RLIMIT_MEMLOCK:
1082 return RLIMIT_MEMLOCK;
1083 case TARGET_RLIMIT_MSGQUEUE:
1084 return RLIMIT_MSGQUEUE;
1085 case TARGET_RLIMIT_NICE:
1086 return RLIMIT_NICE;
1087 case TARGET_RLIMIT_NOFILE:
1088 return RLIMIT_NOFILE;
1089 case TARGET_RLIMIT_NPROC:
1090 return RLIMIT_NPROC;
1091 case TARGET_RLIMIT_RSS:
1092 return RLIMIT_RSS;
1093 case TARGET_RLIMIT_RTPRIO:
1094 return RLIMIT_RTPRIO;
1095 case TARGET_RLIMIT_SIGPENDING:
1096 return RLIMIT_SIGPENDING;
1097 case TARGET_RLIMIT_STACK:
1098 return RLIMIT_STACK;
1099 default:
1100 return code;
1101 }
1102}
1103
ths788f5ec2007-12-09 02:37:05 +00001104static inline abi_long copy_from_user_timeval(struct timeval *tv,
1105 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001106{
pbrook53a59602006-03-25 19:31:22 +00001107 struct target_timeval *target_tv;
1108
ths788f5ec2007-12-09 02:37:05 +00001109 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001110 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001111
1112 __get_user(tv->tv_sec, &target_tv->tv_sec);
1113 __get_user(tv->tv_usec, &target_tv->tv_usec);
1114
1115 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001116
1117 return 0;
bellard31e31b82003-02-18 22:55:36 +00001118}
1119
ths788f5ec2007-12-09 02:37:05 +00001120static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1121 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001122{
pbrook53a59602006-03-25 19:31:22 +00001123 struct target_timeval *target_tv;
1124
ths788f5ec2007-12-09 02:37:05 +00001125 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001126 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001127
1128 __put_user(tv->tv_sec, &target_tv->tv_sec);
1129 __put_user(tv->tv_usec, &target_tv->tv_usec);
1130
1131 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001132
1133 return 0;
bellard31e31b82003-02-18 22:55:36 +00001134}
1135
Paul Burtonef4467e2014-06-22 11:25:40 +01001136static inline abi_long copy_from_user_timezone(struct timezone *tz,
1137 abi_ulong target_tz_addr)
1138{
1139 struct target_timezone *target_tz;
1140
1141 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1142 return -TARGET_EFAULT;
1143 }
1144
1145 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1146 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1147
1148 unlock_user_struct(target_tz, target_tz_addr, 0);
1149
1150 return 0;
1151}
1152
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001153#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1154#include <mqueue.h>
1155
aurel3224e10032009-04-15 16:11:43 +00001156static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1157 abi_ulong target_mq_attr_addr)
1158{
1159 struct target_mq_attr *target_mq_attr;
1160
1161 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1162 target_mq_attr_addr, 1))
1163 return -TARGET_EFAULT;
1164
1165 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1166 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1167 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1168 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1169
1170 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1171
1172 return 0;
1173}
1174
1175static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1176 const struct mq_attr *attr)
1177{
1178 struct target_mq_attr *target_mq_attr;
1179
1180 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1181 target_mq_attr_addr, 0))
1182 return -TARGET_EFAULT;
1183
1184 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1185 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1186 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1187 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1188
1189 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1190
1191 return 0;
1192}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001193#endif
bellard31e31b82003-02-18 22:55:36 +00001194
Mike Frysinger055e0902011-06-03 17:01:49 -04001195#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001196/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001197static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001198 abi_ulong rfd_addr, abi_ulong wfd_addr,
1199 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001200{
1201 fd_set rfds, wfds, efds;
1202 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001203 struct timeval tv;
1204 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001205 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001206
Mike Frysinger055e0902011-06-03 17:01:49 -04001207 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1208 if (ret) {
1209 return ret;
pbrook53a59602006-03-25 19:31:22 +00001210 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001211 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1212 if (ret) {
1213 return ret;
pbrook53a59602006-03-25 19:31:22 +00001214 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001215 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1216 if (ret) {
1217 return ret;
pbrook53a59602006-03-25 19:31:22 +00001218 }
ths3b46e622007-09-17 08:09:54 +00001219
ths26edcf42007-12-09 02:25:24 +00001220 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001221 if (copy_from_user_timeval(&tv, target_tv_addr))
1222 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001223 ts.tv_sec = tv.tv_sec;
1224 ts.tv_nsec = tv.tv_usec * 1000;
1225 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001226 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001227 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001228 }
ths26edcf42007-12-09 02:25:24 +00001229
Peter Maydell6df9d382016-05-12 18:47:51 +01001230 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1231 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001232
ths26edcf42007-12-09 02:25:24 +00001233 if (!is_error(ret)) {
1234 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1235 return -TARGET_EFAULT;
1236 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1237 return -TARGET_EFAULT;
1238 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1239 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001240
Peter Maydell6df9d382016-05-12 18:47:51 +01001241 if (target_tv_addr) {
1242 tv.tv_sec = ts.tv_sec;
1243 tv.tv_usec = ts.tv_nsec / 1000;
1244 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1245 return -TARGET_EFAULT;
1246 }
1247 }
bellard31e31b82003-02-18 22:55:36 +00001248 }
bellard579a97f2007-11-11 14:26:47 +00001249
bellard31e31b82003-02-18 22:55:36 +00001250 return ret;
1251}
Mike Frysinger055e0902011-06-03 17:01:49 -04001252#endif
bellard31e31b82003-02-18 22:55:36 +00001253
Riku Voipio099d6b02009-05-05 12:10:04 +03001254static abi_long do_pipe2(int host_pipe[], int flags)
1255{
1256#ifdef CONFIG_PIPE2
1257 return pipe2(host_pipe, flags);
1258#else
1259 return -ENOSYS;
1260#endif
1261}
1262
Richard Hendersonfb41a662010-05-03 10:07:52 -07001263static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1264 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001265{
1266 int host_pipe[2];
1267 abi_long ret;
1268 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1269
1270 if (is_error(ret))
1271 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001272
1273 /* Several targets have special calling conventions for the original
1274 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1275 if (!is_pipe2) {
1276#if defined(TARGET_ALPHA)
1277 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1278 return host_pipe[0];
1279#elif defined(TARGET_MIPS)
1280 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1281 return host_pipe[0];
1282#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001283 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001284 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001285#elif defined(TARGET_SPARC)
1286 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1287 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001288#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001289 }
1290
Riku Voipio099d6b02009-05-05 12:10:04 +03001291 if (put_user_s32(host_pipe[0], pipedes)
1292 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1293 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001294 return get_errno(ret);
1295}
1296
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001297static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1298 abi_ulong target_addr,
1299 socklen_t len)
1300{
1301 struct target_ip_mreqn *target_smreqn;
1302
1303 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1304 if (!target_smreqn)
1305 return -TARGET_EFAULT;
1306 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1307 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1308 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001309 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001310 unlock_user(target_smreqn, target_addr, 0);
1311
1312 return 0;
1313}
1314
Laurent Vivier7b36f782015-10-28 21:40:44 +01001315static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001316 abi_ulong target_addr,
1317 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001318{
aurel32607175e2009-04-15 16:11:59 +00001319 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1320 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001321 struct target_sockaddr *target_saddr;
1322
Laurent Vivier7b36f782015-10-28 21:40:44 +01001323 if (fd_trans_target_to_host_addr(fd)) {
1324 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1325 }
1326
bellard579a97f2007-11-11 14:26:47 +00001327 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1328 if (!target_saddr)
1329 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001330
1331 sa_family = tswap16(target_saddr->sa_family);
1332
1333 /* Oops. The caller might send a incomplete sun_path; sun_path
1334 * must be terminated by \0 (see the manual page), but
1335 * unfortunately it is quite common to specify sockaddr_un
1336 * length as "strlen(x->sun_path)" while it should be
1337 * "strlen(...) + 1". We'll fix that here if needed.
1338 * Linux kernel has a similar feature.
1339 */
1340
1341 if (sa_family == AF_UNIX) {
1342 if (len < unix_maxlen && len > 0) {
1343 char *cp = (char*)target_saddr;
1344
1345 if ( cp[len-1] && !cp[len] )
1346 len++;
1347 }
1348 if (len > unix_maxlen)
1349 len = unix_maxlen;
1350 }
1351
pbrook53a59602006-03-25 19:31:22 +00001352 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001353 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001354 if (sa_family == AF_NETLINK) {
1355 struct sockaddr_nl *nladdr;
1356
1357 nladdr = (struct sockaddr_nl *)addr;
1358 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1359 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1360 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001361 struct target_sockaddr_ll *lladdr;
1362
1363 lladdr = (struct target_sockaddr_ll *)addr;
1364 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1365 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1366 }
pbrook53a59602006-03-25 19:31:22 +00001367 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001368
1369 return 0;
bellard7854b052003-03-29 17:22:23 +00001370}
1371
bellard579a97f2007-11-11 14:26:47 +00001372static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1373 struct sockaddr *addr,
1374 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001375{
pbrook53a59602006-03-25 19:31:22 +00001376 struct target_sockaddr *target_saddr;
1377
bellard579a97f2007-11-11 14:26:47 +00001378 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1379 if (!target_saddr)
1380 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001381 memcpy(target_saddr, addr, len);
1382 target_saddr->sa_family = tswap16(addr->sa_family);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001383 if (addr->sa_family == AF_NETLINK) {
1384 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1385 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1386 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001387 } else if (addr->sa_family == AF_PACKET) {
1388 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1389 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1390 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001391 }
pbrook53a59602006-03-25 19:31:22 +00001392 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001393
1394 return 0;
bellard7854b052003-03-29 17:22:23 +00001395}
1396
bellard5a4a8982007-11-11 17:39:18 +00001397static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1398 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001399{
1400 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001401 abi_long msg_controllen;
1402 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001403 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001404 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001405
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001406 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001407 if (msg_controllen < sizeof (struct target_cmsghdr))
1408 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001409 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001410 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001411 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001412 if (!target_cmsg)
1413 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001414
1415 while (cmsg && target_cmsg) {
1416 void *data = CMSG_DATA(cmsg);
1417 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1418
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001419 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001420 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1421
1422 space += CMSG_SPACE(len);
1423 if (space > msgh->msg_controllen) {
1424 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001425 /* This is a QEMU bug, since we allocated the payload
1426 * area ourselves (unlike overflow in host-to-target
1427 * conversion, which is just the guest giving us a buffer
1428 * that's too small). It can't happen for the payload types
1429 * we currently support; if it becomes an issue in future
1430 * we would need to improve our allocation strategy to
1431 * something more intelligent than "twice the size of the
1432 * target buffer we're reading from".
1433 */
bellard31febb72005-12-18 20:03:27 +00001434 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001435 break;
1436 }
1437
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001438 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1439 cmsg->cmsg_level = SOL_SOCKET;
1440 } else {
1441 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1442 }
bellard7854b052003-03-29 17:22:23 +00001443 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1444 cmsg->cmsg_len = CMSG_LEN(len);
1445
Alex Suykov30b8b682014-12-23 07:52:58 +02001446 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001447 int *fd = (int *)data;
1448 int *target_fd = (int *)target_data;
1449 int i, numfds = len / sizeof(int);
1450
Peter Maydell876e23c2015-05-26 19:46:32 +01001451 for (i = 0; i < numfds; i++) {
1452 __get_user(fd[i], target_fd + i);
1453 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001454 } else if (cmsg->cmsg_level == SOL_SOCKET
1455 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1456 struct ucred *cred = (struct ucred *)data;
1457 struct target_ucred *target_cred =
1458 (struct target_ucred *)target_data;
1459
Peter Maydell876e23c2015-05-26 19:46:32 +01001460 __get_user(cred->pid, &target_cred->pid);
1461 __get_user(cred->uid, &target_cred->uid);
1462 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001463 } else {
1464 gemu_log("Unsupported ancillary data: %d/%d\n",
1465 cmsg->cmsg_level, cmsg->cmsg_type);
1466 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001467 }
1468
1469 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001470 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1471 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001472 }
bellard5a4a8982007-11-11 17:39:18 +00001473 unlock_user(target_cmsg, target_cmsg_addr, 0);
1474 the_end:
bellard7854b052003-03-29 17:22:23 +00001475 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001476 return 0;
bellard7854b052003-03-29 17:22:23 +00001477}
1478
bellard5a4a8982007-11-11 17:39:18 +00001479static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1480 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001481{
1482 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001483 abi_long msg_controllen;
1484 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001485 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001486 socklen_t space = 0;
1487
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001488 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001489 if (msg_controllen < sizeof (struct target_cmsghdr))
1490 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001491 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001492 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001493 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001494 if (!target_cmsg)
1495 return -TARGET_EFAULT;
1496
bellard7854b052003-03-29 17:22:23 +00001497 while (cmsg && target_cmsg) {
1498 void *data = CMSG_DATA(cmsg);
1499 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1500
1501 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001502 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001503
Peter Maydellc2aeb252015-05-26 19:46:31 +01001504 /* We never copy a half-header but may copy half-data;
1505 * this is Linux's behaviour in put_cmsg(). Note that
1506 * truncation here is a guest problem (which we report
1507 * to the guest via the CTRUNC bit), unlike truncation
1508 * in target_to_host_cmsg, which is a QEMU bug.
1509 */
1510 if (msg_controllen < sizeof(struct cmsghdr)) {
1511 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001512 break;
1513 }
1514
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001515 if (cmsg->cmsg_level == SOL_SOCKET) {
1516 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1517 } else {
1518 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1519 }
bellard7854b052003-03-29 17:22:23 +00001520 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001521
Peter Maydellc2aeb252015-05-26 19:46:31 +01001522 tgt_len = TARGET_CMSG_LEN(len);
1523
1524 /* Payload types which need a different size of payload on
1525 * the target must adjust tgt_len here.
1526 */
1527 switch (cmsg->cmsg_level) {
1528 case SOL_SOCKET:
1529 switch (cmsg->cmsg_type) {
1530 case SO_TIMESTAMP:
1531 tgt_len = sizeof(struct target_timeval);
1532 break;
1533 default:
1534 break;
1535 }
1536 default:
1537 break;
1538 }
1539
1540 if (msg_controllen < tgt_len) {
1541 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1542 tgt_len = msg_controllen;
1543 }
1544
1545 /* We must now copy-and-convert len bytes of payload
1546 * into tgt_len bytes of destination space. Bear in mind
1547 * that in both source and destination we may be dealing
1548 * with a truncated value!
1549 */
Huw Davies52b65492014-04-17 14:02:47 +01001550 switch (cmsg->cmsg_level) {
1551 case SOL_SOCKET:
1552 switch (cmsg->cmsg_type) {
1553 case SCM_RIGHTS:
1554 {
1555 int *fd = (int *)data;
1556 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001557 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001558
Peter Maydell876e23c2015-05-26 19:46:32 +01001559 for (i = 0; i < numfds; i++) {
1560 __put_user(fd[i], target_fd + i);
1561 }
Huw Davies52b65492014-04-17 14:02:47 +01001562 break;
1563 }
1564 case SO_TIMESTAMP:
1565 {
1566 struct timeval *tv = (struct timeval *)data;
1567 struct target_timeval *target_tv =
1568 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001569
Peter Maydellc2aeb252015-05-26 19:46:31 +01001570 if (len != sizeof(struct timeval) ||
1571 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001572 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001573 }
Huw Davies52b65492014-04-17 14:02:47 +01001574
1575 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001576 __put_user(tv->tv_sec, &target_tv->tv_sec);
1577 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001578 break;
1579 }
Huw Davies4bc29752014-04-17 14:02:48 +01001580 case SCM_CREDENTIALS:
1581 {
1582 struct ucred *cred = (struct ucred *)data;
1583 struct target_ucred *target_cred =
1584 (struct target_ucred *)target_data;
1585
1586 __put_user(cred->pid, &target_cred->pid);
1587 __put_user(cred->uid, &target_cred->uid);
1588 __put_user(cred->gid, &target_cred->gid);
1589 break;
1590 }
Huw Davies52b65492014-04-17 14:02:47 +01001591 default:
1592 goto unimplemented;
1593 }
1594 break;
1595
1596 default:
1597 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001598 gemu_log("Unsupported ancillary data: %d/%d\n",
1599 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001600 memcpy(target_data, data, MIN(len, tgt_len));
1601 if (tgt_len > len) {
1602 memset(target_data + len, 0, tgt_len - len);
1603 }
bellard7854b052003-03-29 17:22:23 +00001604 }
1605
Peter Maydellc2aeb252015-05-26 19:46:31 +01001606 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001607 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001608 if (msg_controllen < tgt_space) {
1609 tgt_space = msg_controllen;
1610 }
1611 msg_controllen -= tgt_space;
1612 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001613 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001614 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1615 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001616 }
bellard5a4a8982007-11-11 17:39:18 +00001617 unlock_user(target_cmsg, target_cmsg_addr, space);
1618 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001619 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001620 return 0;
bellard7854b052003-03-29 17:22:23 +00001621}
1622
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001623static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1624{
1625 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1626 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1627 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1628 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1629 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1630}
1631
1632static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1633 size_t len,
1634 abi_long (*host_to_target_nlmsg)
1635 (struct nlmsghdr *))
1636{
1637 uint32_t nlmsg_len;
1638 abi_long ret;
1639
1640 while (len > sizeof(struct nlmsghdr)) {
1641
1642 nlmsg_len = nlh->nlmsg_len;
1643 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1644 nlmsg_len > len) {
1645 break;
1646 }
1647
1648 switch (nlh->nlmsg_type) {
1649 case NLMSG_DONE:
1650 tswap_nlmsghdr(nlh);
1651 return 0;
1652 case NLMSG_NOOP:
1653 break;
1654 case NLMSG_ERROR:
1655 {
1656 struct nlmsgerr *e = NLMSG_DATA(nlh);
1657 e->error = tswap32(e->error);
1658 tswap_nlmsghdr(&e->msg);
1659 tswap_nlmsghdr(nlh);
1660 return 0;
1661 }
1662 default:
1663 ret = host_to_target_nlmsg(nlh);
1664 if (ret < 0) {
1665 tswap_nlmsghdr(nlh);
1666 return ret;
1667 }
1668 break;
1669 }
1670 tswap_nlmsghdr(nlh);
1671 len -= NLMSG_ALIGN(nlmsg_len);
1672 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1673 }
1674 return 0;
1675}
1676
1677static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1678 size_t len,
1679 abi_long (*target_to_host_nlmsg)
1680 (struct nlmsghdr *))
1681{
1682 int ret;
1683
1684 while (len > sizeof(struct nlmsghdr)) {
1685 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1686 tswap32(nlh->nlmsg_len) > len) {
1687 break;
1688 }
1689 tswap_nlmsghdr(nlh);
1690 switch (nlh->nlmsg_type) {
1691 case NLMSG_DONE:
1692 return 0;
1693 case NLMSG_NOOP:
1694 break;
1695 case NLMSG_ERROR:
1696 {
1697 struct nlmsgerr *e = NLMSG_DATA(nlh);
1698 e->error = tswap32(e->error);
1699 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02001700 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001701 }
1702 default:
1703 ret = target_to_host_nlmsg(nlh);
1704 if (ret < 0) {
1705 return ret;
1706 }
1707 }
1708 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1709 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1710 }
1711 return 0;
1712}
1713
Laurent Vivier575b22b2016-06-02 22:14:15 +02001714#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001715static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1716 size_t len,
1717 abi_long (*host_to_target_rtattr)
1718 (struct rtattr *))
1719{
1720 unsigned short rta_len;
1721 abi_long ret;
1722
1723 while (len > sizeof(struct rtattr)) {
1724 rta_len = rtattr->rta_len;
1725 if (rta_len < sizeof(struct rtattr) ||
1726 rta_len > len) {
1727 break;
1728 }
1729 ret = host_to_target_rtattr(rtattr);
1730 rtattr->rta_len = tswap16(rtattr->rta_len);
1731 rtattr->rta_type = tswap16(rtattr->rta_type);
1732 if (ret < 0) {
1733 return ret;
1734 }
1735 len -= RTA_ALIGN(rta_len);
1736 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1737 }
1738 return 0;
1739}
1740
1741static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
1742{
1743 uint32_t *u32;
1744 struct rtnl_link_stats *st;
1745 struct rtnl_link_stats64 *st64;
1746 struct rtnl_link_ifmap *map;
1747
1748 switch (rtattr->rta_type) {
1749 /* binary stream */
1750 case IFLA_ADDRESS:
1751 case IFLA_BROADCAST:
1752 /* string */
1753 case IFLA_IFNAME:
1754 case IFLA_QDISC:
1755 break;
1756 /* uin8_t */
1757 case IFLA_OPERSTATE:
1758 case IFLA_LINKMODE:
1759 case IFLA_CARRIER:
1760 case IFLA_PROTO_DOWN:
1761 break;
1762 /* uint32_t */
1763 case IFLA_MTU:
1764 case IFLA_LINK:
1765 case IFLA_WEIGHT:
1766 case IFLA_TXQLEN:
1767 case IFLA_CARRIER_CHANGES:
1768 case IFLA_NUM_RX_QUEUES:
1769 case IFLA_NUM_TX_QUEUES:
1770 case IFLA_PROMISCUITY:
1771 case IFLA_EXT_MASK:
1772 case IFLA_LINK_NETNSID:
1773 case IFLA_GROUP:
1774 case IFLA_MASTER:
1775 case IFLA_NUM_VF:
1776 u32 = RTA_DATA(rtattr);
1777 *u32 = tswap32(*u32);
1778 break;
1779 /* struct rtnl_link_stats */
1780 case IFLA_STATS:
1781 st = RTA_DATA(rtattr);
1782 st->rx_packets = tswap32(st->rx_packets);
1783 st->tx_packets = tswap32(st->tx_packets);
1784 st->rx_bytes = tswap32(st->rx_bytes);
1785 st->tx_bytes = tswap32(st->tx_bytes);
1786 st->rx_errors = tswap32(st->rx_errors);
1787 st->tx_errors = tswap32(st->tx_errors);
1788 st->rx_dropped = tswap32(st->rx_dropped);
1789 st->tx_dropped = tswap32(st->tx_dropped);
1790 st->multicast = tswap32(st->multicast);
1791 st->collisions = tswap32(st->collisions);
1792
1793 /* detailed rx_errors: */
1794 st->rx_length_errors = tswap32(st->rx_length_errors);
1795 st->rx_over_errors = tswap32(st->rx_over_errors);
1796 st->rx_crc_errors = tswap32(st->rx_crc_errors);
1797 st->rx_frame_errors = tswap32(st->rx_frame_errors);
1798 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
1799 st->rx_missed_errors = tswap32(st->rx_missed_errors);
1800
1801 /* detailed tx_errors */
1802 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
1803 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
1804 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
1805 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
1806 st->tx_window_errors = tswap32(st->tx_window_errors);
1807
1808 /* for cslip etc */
1809 st->rx_compressed = tswap32(st->rx_compressed);
1810 st->tx_compressed = tswap32(st->tx_compressed);
1811 break;
1812 /* struct rtnl_link_stats64 */
1813 case IFLA_STATS64:
1814 st64 = RTA_DATA(rtattr);
1815 st64->rx_packets = tswap64(st64->rx_packets);
1816 st64->tx_packets = tswap64(st64->tx_packets);
1817 st64->rx_bytes = tswap64(st64->rx_bytes);
1818 st64->tx_bytes = tswap64(st64->tx_bytes);
1819 st64->rx_errors = tswap64(st64->rx_errors);
1820 st64->tx_errors = tswap64(st64->tx_errors);
1821 st64->rx_dropped = tswap64(st64->rx_dropped);
1822 st64->tx_dropped = tswap64(st64->tx_dropped);
1823 st64->multicast = tswap64(st64->multicast);
1824 st64->collisions = tswap64(st64->collisions);
1825
1826 /* detailed rx_errors: */
1827 st64->rx_length_errors = tswap64(st64->rx_length_errors);
1828 st64->rx_over_errors = tswap64(st64->rx_over_errors);
1829 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
1830 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
1831 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
1832 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
1833
1834 /* detailed tx_errors */
1835 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
1836 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
1837 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
1838 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
1839 st64->tx_window_errors = tswap64(st64->tx_window_errors);
1840
1841 /* for cslip etc */
1842 st64->rx_compressed = tswap64(st64->rx_compressed);
1843 st64->tx_compressed = tswap64(st64->tx_compressed);
1844 break;
1845 /* struct rtnl_link_ifmap */
1846 case IFLA_MAP:
1847 map = RTA_DATA(rtattr);
1848 map->mem_start = tswap64(map->mem_start);
1849 map->mem_end = tswap64(map->mem_end);
1850 map->base_addr = tswap64(map->base_addr);
1851 map->irq = tswap16(map->irq);
1852 break;
1853 /* nested */
1854 case IFLA_AF_SPEC:
1855 case IFLA_LINKINFO:
1856 /* FIXME: implement nested type */
1857 gemu_log("Unimplemented nested type %d\n", rtattr->rta_type);
1858 break;
1859 default:
1860 gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type);
1861 break;
1862 }
1863 return 0;
1864}
1865
1866static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
1867{
1868 uint32_t *u32;
1869 struct ifa_cacheinfo *ci;
1870
1871 switch (rtattr->rta_type) {
1872 /* binary: depends on family type */
1873 case IFA_ADDRESS:
1874 case IFA_LOCAL:
1875 break;
1876 /* string */
1877 case IFA_LABEL:
1878 break;
1879 /* u32 */
1880 case IFA_FLAGS:
1881 case IFA_BROADCAST:
1882 u32 = RTA_DATA(rtattr);
1883 *u32 = tswap32(*u32);
1884 break;
1885 /* struct ifa_cacheinfo */
1886 case IFA_CACHEINFO:
1887 ci = RTA_DATA(rtattr);
1888 ci->ifa_prefered = tswap32(ci->ifa_prefered);
1889 ci->ifa_valid = tswap32(ci->ifa_valid);
1890 ci->cstamp = tswap32(ci->cstamp);
1891 ci->tstamp = tswap32(ci->tstamp);
1892 break;
1893 default:
1894 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
1895 break;
1896 }
1897 return 0;
1898}
1899
1900static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
1901{
1902 uint32_t *u32;
1903 switch (rtattr->rta_type) {
1904 /* binary: depends on family type */
1905 case RTA_GATEWAY:
1906 case RTA_DST:
1907 case RTA_PREFSRC:
1908 break;
1909 /* u32 */
1910 case RTA_PRIORITY:
1911 case RTA_TABLE:
1912 case RTA_OIF:
1913 u32 = RTA_DATA(rtattr);
1914 *u32 = tswap32(*u32);
1915 break;
1916 default:
1917 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
1918 break;
1919 }
1920 return 0;
1921}
1922
1923static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
1924 uint32_t rtattr_len)
1925{
1926 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1927 host_to_target_data_link_rtattr);
1928}
1929
1930static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
1931 uint32_t rtattr_len)
1932{
1933 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1934 host_to_target_data_addr_rtattr);
1935}
1936
1937static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
1938 uint32_t rtattr_len)
1939{
1940 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1941 host_to_target_data_route_rtattr);
1942}
1943
1944static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
1945{
1946 uint32_t nlmsg_len;
1947 struct ifinfomsg *ifi;
1948 struct ifaddrmsg *ifa;
1949 struct rtmsg *rtm;
1950
1951 nlmsg_len = nlh->nlmsg_len;
1952 switch (nlh->nlmsg_type) {
1953 case RTM_NEWLINK:
1954 case RTM_DELLINK:
1955 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02001956 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
1957 ifi = NLMSG_DATA(nlh);
1958 ifi->ifi_type = tswap16(ifi->ifi_type);
1959 ifi->ifi_index = tswap32(ifi->ifi_index);
1960 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1961 ifi->ifi_change = tswap32(ifi->ifi_change);
1962 host_to_target_link_rtattr(IFLA_RTA(ifi),
1963 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1964 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001965 break;
1966 case RTM_NEWADDR:
1967 case RTM_DELADDR:
1968 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02001969 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
1970 ifa = NLMSG_DATA(nlh);
1971 ifa->ifa_index = tswap32(ifa->ifa_index);
1972 host_to_target_addr_rtattr(IFA_RTA(ifa),
1973 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1974 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001975 break;
1976 case RTM_NEWROUTE:
1977 case RTM_DELROUTE:
1978 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02001979 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
1980 rtm = NLMSG_DATA(nlh);
1981 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1982 host_to_target_route_rtattr(RTM_RTA(rtm),
1983 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1984 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001985 break;
1986 default:
1987 return -TARGET_EINVAL;
1988 }
1989 return 0;
1990}
1991
1992static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1993 size_t len)
1994{
1995 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1996}
1997
1998static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1999 size_t len,
2000 abi_long (*target_to_host_rtattr)
2001 (struct rtattr *))
2002{
2003 abi_long ret;
2004
2005 while (len >= sizeof(struct rtattr)) {
2006 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2007 tswap16(rtattr->rta_len) > len) {
2008 break;
2009 }
2010 rtattr->rta_len = tswap16(rtattr->rta_len);
2011 rtattr->rta_type = tswap16(rtattr->rta_type);
2012 ret = target_to_host_rtattr(rtattr);
2013 if (ret < 0) {
2014 return ret;
2015 }
2016 len -= RTA_ALIGN(rtattr->rta_len);
2017 rtattr = (struct rtattr *)(((char *)rtattr) +
2018 RTA_ALIGN(rtattr->rta_len));
2019 }
2020 return 0;
2021}
2022
2023static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2024{
2025 switch (rtattr->rta_type) {
2026 default:
2027 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
2028 break;
2029 }
2030 return 0;
2031}
2032
2033static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2034{
2035 switch (rtattr->rta_type) {
2036 /* binary: depends on family type */
2037 case IFA_LOCAL:
2038 case IFA_ADDRESS:
2039 break;
2040 default:
2041 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2042 break;
2043 }
2044 return 0;
2045}
2046
2047static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2048{
2049 uint32_t *u32;
2050 switch (rtattr->rta_type) {
2051 /* binary: depends on family type */
2052 case RTA_DST:
2053 case RTA_SRC:
2054 case RTA_GATEWAY:
2055 break;
2056 /* u32 */
2057 case RTA_OIF:
2058 u32 = RTA_DATA(rtattr);
2059 *u32 = tswap32(*u32);
2060 break;
2061 default:
2062 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2063 break;
2064 }
2065 return 0;
2066}
2067
2068static void target_to_host_link_rtattr(struct rtattr *rtattr,
2069 uint32_t rtattr_len)
2070{
2071 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2072 target_to_host_data_link_rtattr);
2073}
2074
2075static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2076 uint32_t rtattr_len)
2077{
2078 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2079 target_to_host_data_addr_rtattr);
2080}
2081
2082static void target_to_host_route_rtattr(struct rtattr *rtattr,
2083 uint32_t rtattr_len)
2084{
2085 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2086 target_to_host_data_route_rtattr);
2087}
2088
2089static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2090{
2091 struct ifinfomsg *ifi;
2092 struct ifaddrmsg *ifa;
2093 struct rtmsg *rtm;
2094
2095 switch (nlh->nlmsg_type) {
2096 case RTM_GETLINK:
2097 break;
2098 case RTM_NEWLINK:
2099 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002100 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2101 ifi = NLMSG_DATA(nlh);
2102 ifi->ifi_type = tswap16(ifi->ifi_type);
2103 ifi->ifi_index = tswap32(ifi->ifi_index);
2104 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2105 ifi->ifi_change = tswap32(ifi->ifi_change);
2106 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2107 NLMSG_LENGTH(sizeof(*ifi)));
2108 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002109 break;
2110 case RTM_GETADDR:
2111 case RTM_NEWADDR:
2112 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002113 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2114 ifa = NLMSG_DATA(nlh);
2115 ifa->ifa_index = tswap32(ifa->ifa_index);
2116 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2117 NLMSG_LENGTH(sizeof(*ifa)));
2118 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002119 break;
2120 case RTM_GETROUTE:
2121 break;
2122 case RTM_NEWROUTE:
2123 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002124 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2125 rtm = NLMSG_DATA(nlh);
2126 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2127 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2128 NLMSG_LENGTH(sizeof(*rtm)));
2129 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002130 break;
2131 default:
2132 return -TARGET_EOPNOTSUPP;
2133 }
2134 return 0;
2135}
2136
2137static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2138{
2139 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2140}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002141#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002142
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002143static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2144{
2145 switch (nlh->nlmsg_type) {
2146 default:
2147 gemu_log("Unknown host audit message type %d\n",
2148 nlh->nlmsg_type);
2149 return -TARGET_EINVAL;
2150 }
2151 return 0;
2152}
2153
2154static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2155 size_t len)
2156{
2157 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2158}
2159
2160static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2161{
2162 switch (nlh->nlmsg_type) {
2163 case AUDIT_USER:
2164 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2165 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2166 break;
2167 default:
2168 gemu_log("Unknown target audit message type %d\n",
2169 nlh->nlmsg_type);
2170 return -TARGET_EINVAL;
2171 }
2172
2173 return 0;
2174}
2175
2176static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2177{
2178 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2179}
2180
ths0da46a62007-10-20 20:23:07 +00002181/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002182static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002183 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002184{
blueswir1992f48a2007-10-14 16:27:31 +00002185 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002186 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002187 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002188 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002189
bellard8853f862004-02-22 14:57:26 +00002190 switch(level) {
2191 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002192 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002193 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002194 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002195
bellard2f619692007-11-16 10:46:05 +00002196 if (get_user_u32(val, optval_addr))
2197 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002198 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2199 break;
2200 case SOL_IP:
2201 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002202 case IP_TOS:
2203 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002204 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002205 case IP_ROUTER_ALERT:
2206 case IP_RECVOPTS:
2207 case IP_RETOPTS:
2208 case IP_PKTINFO:
2209 case IP_MTU_DISCOVER:
2210 case IP_RECVERR:
2211 case IP_RECVTOS:
2212#ifdef IP_FREEBIND
2213 case IP_FREEBIND:
2214#endif
2215 case IP_MULTICAST_TTL:
2216 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002217 val = 0;
2218 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002219 if (get_user_u32(val, optval_addr))
2220 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002221 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002222 if (get_user_u8(val, optval_addr))
2223 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002224 }
2225 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2226 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002227 case IP_ADD_MEMBERSHIP:
2228 case IP_DROP_MEMBERSHIP:
2229 if (optlen < sizeof (struct target_ip_mreq) ||
2230 optlen > sizeof (struct target_ip_mreqn))
2231 return -TARGET_EINVAL;
2232
2233 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2234 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2235 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2236 break;
2237
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002238 case IP_BLOCK_SOURCE:
2239 case IP_UNBLOCK_SOURCE:
2240 case IP_ADD_SOURCE_MEMBERSHIP:
2241 case IP_DROP_SOURCE_MEMBERSHIP:
2242 if (optlen != sizeof (struct target_ip_mreq_source))
2243 return -TARGET_EINVAL;
2244
2245 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2246 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2247 unlock_user (ip_mreq_source, optval_addr, 0);
2248 break;
2249
bellard8853f862004-02-22 14:57:26 +00002250 default:
2251 goto unimplemented;
2252 }
2253 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002254 case SOL_IPV6:
2255 switch (optname) {
2256 case IPV6_MTU_DISCOVER:
2257 case IPV6_MTU:
2258 case IPV6_V6ONLY:
2259 case IPV6_RECVPKTINFO:
2260 val = 0;
2261 if (optlen < sizeof(uint32_t)) {
2262 return -TARGET_EINVAL;
2263 }
2264 if (get_user_u32(val, optval_addr)) {
2265 return -TARGET_EFAULT;
2266 }
2267 ret = get_errno(setsockopt(sockfd, level, optname,
2268 &val, sizeof(val)));
2269 break;
2270 default:
2271 goto unimplemented;
2272 }
2273 break;
Jing Huang920394d2012-07-24 13:59:23 +00002274 case SOL_RAW:
2275 switch (optname) {
2276 case ICMP_FILTER:
2277 /* struct icmp_filter takes an u32 value */
2278 if (optlen < sizeof(uint32_t)) {
2279 return -TARGET_EINVAL;
2280 }
2281
2282 if (get_user_u32(val, optval_addr)) {
2283 return -TARGET_EFAULT;
2284 }
2285 ret = get_errno(setsockopt(sockfd, level, optname,
2286 &val, sizeof(val)));
2287 break;
2288
2289 default:
2290 goto unimplemented;
2291 }
2292 break;
bellard3532fa72006-06-24 15:06:03 +00002293 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002294 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002295 case TARGET_SO_RCVTIMEO:
2296 {
2297 struct timeval tv;
2298
2299 optname = SO_RCVTIMEO;
2300
2301set_timeout:
2302 if (optlen != sizeof(struct target_timeval)) {
2303 return -TARGET_EINVAL;
2304 }
2305
2306 if (copy_from_user_timeval(&tv, optval_addr)) {
2307 return -TARGET_EFAULT;
2308 }
2309
2310 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2311 &tv, sizeof(tv)));
2312 return ret;
2313 }
2314 case TARGET_SO_SNDTIMEO:
2315 optname = SO_SNDTIMEO;
2316 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002317 case TARGET_SO_ATTACH_FILTER:
2318 {
2319 struct target_sock_fprog *tfprog;
2320 struct target_sock_filter *tfilter;
2321 struct sock_fprog fprog;
2322 struct sock_filter *filter;
2323 int i;
2324
2325 if (optlen != sizeof(*tfprog)) {
2326 return -TARGET_EINVAL;
2327 }
2328 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2329 return -TARGET_EFAULT;
2330 }
2331 if (!lock_user_struct(VERIFY_READ, tfilter,
2332 tswapal(tfprog->filter), 0)) {
2333 unlock_user_struct(tfprog, optval_addr, 1);
2334 return -TARGET_EFAULT;
2335 }
2336
2337 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302338 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002339 if (filter == NULL) {
2340 unlock_user_struct(tfilter, tfprog->filter, 1);
2341 unlock_user_struct(tfprog, optval_addr, 1);
2342 return -TARGET_ENOMEM;
2343 }
2344 for (i = 0; i < fprog.len; i++) {
2345 filter[i].code = tswap16(tfilter[i].code);
2346 filter[i].jt = tfilter[i].jt;
2347 filter[i].jf = tfilter[i].jf;
2348 filter[i].k = tswap32(tfilter[i].k);
2349 }
2350 fprog.filter = filter;
2351
2352 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2353 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302354 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002355
2356 unlock_user_struct(tfilter, tfprog->filter, 1);
2357 unlock_user_struct(tfprog, optval_addr, 1);
2358 return ret;
2359 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002360 case TARGET_SO_BINDTODEVICE:
2361 {
2362 char *dev_ifname, *addr_ifname;
2363
2364 if (optlen > IFNAMSIZ - 1) {
2365 optlen = IFNAMSIZ - 1;
2366 }
2367 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2368 if (!dev_ifname) {
2369 return -TARGET_EFAULT;
2370 }
2371 optname = SO_BINDTODEVICE;
2372 addr_ifname = alloca(IFNAMSIZ);
2373 memcpy(addr_ifname, dev_ifname, optlen);
2374 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002375 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2376 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002377 unlock_user (dev_ifname, optval_addr, 0);
2378 return ret;
2379 }
bellard8853f862004-02-22 14:57:26 +00002380 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002381 case TARGET_SO_DEBUG:
2382 optname = SO_DEBUG;
2383 break;
2384 case TARGET_SO_REUSEADDR:
2385 optname = SO_REUSEADDR;
2386 break;
2387 case TARGET_SO_TYPE:
2388 optname = SO_TYPE;
2389 break;
2390 case TARGET_SO_ERROR:
2391 optname = SO_ERROR;
2392 break;
2393 case TARGET_SO_DONTROUTE:
2394 optname = SO_DONTROUTE;
2395 break;
2396 case TARGET_SO_BROADCAST:
2397 optname = SO_BROADCAST;
2398 break;
2399 case TARGET_SO_SNDBUF:
2400 optname = SO_SNDBUF;
2401 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002402 case TARGET_SO_SNDBUFFORCE:
2403 optname = SO_SNDBUFFORCE;
2404 break;
bellard3532fa72006-06-24 15:06:03 +00002405 case TARGET_SO_RCVBUF:
2406 optname = SO_RCVBUF;
2407 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002408 case TARGET_SO_RCVBUFFORCE:
2409 optname = SO_RCVBUFFORCE;
2410 break;
bellard3532fa72006-06-24 15:06:03 +00002411 case TARGET_SO_KEEPALIVE:
2412 optname = SO_KEEPALIVE;
2413 break;
2414 case TARGET_SO_OOBINLINE:
2415 optname = SO_OOBINLINE;
2416 break;
2417 case TARGET_SO_NO_CHECK:
2418 optname = SO_NO_CHECK;
2419 break;
2420 case TARGET_SO_PRIORITY:
2421 optname = SO_PRIORITY;
2422 break;
bellard5e83e8e2005-03-01 22:32:06 +00002423#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002424 case TARGET_SO_BSDCOMPAT:
2425 optname = SO_BSDCOMPAT;
2426 break;
bellard5e83e8e2005-03-01 22:32:06 +00002427#endif
bellard3532fa72006-06-24 15:06:03 +00002428 case TARGET_SO_PASSCRED:
2429 optname = SO_PASSCRED;
2430 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002431 case TARGET_SO_PASSSEC:
2432 optname = SO_PASSSEC;
2433 break;
bellard3532fa72006-06-24 15:06:03 +00002434 case TARGET_SO_TIMESTAMP:
2435 optname = SO_TIMESTAMP;
2436 break;
2437 case TARGET_SO_RCVLOWAT:
2438 optname = SO_RCVLOWAT;
2439 break;
bellard8853f862004-02-22 14:57:26 +00002440 break;
2441 default:
2442 goto unimplemented;
2443 }
bellard3532fa72006-06-24 15:06:03 +00002444 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002445 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002446
bellard2f619692007-11-16 10:46:05 +00002447 if (get_user_u32(val, optval_addr))
2448 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002449 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002450 break;
bellard7854b052003-03-29 17:22:23 +00002451 default:
bellard8853f862004-02-22 14:57:26 +00002452 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002453 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002454 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002455 }
bellard8853f862004-02-22 14:57:26 +00002456 return ret;
bellard7854b052003-03-29 17:22:23 +00002457}
2458
ths0da46a62007-10-20 20:23:07 +00002459/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002460static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002461 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002462{
blueswir1992f48a2007-10-14 16:27:31 +00002463 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002464 int len, val;
2465 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002466
2467 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002468 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002469 level = SOL_SOCKET;
2470 switch (optname) {
2471 /* These don't just return a single integer */
2472 case TARGET_SO_LINGER:
2473 case TARGET_SO_RCVTIMEO:
2474 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002475 case TARGET_SO_PEERNAME:
2476 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002477 case TARGET_SO_PEERCRED: {
2478 struct ucred cr;
2479 socklen_t crlen;
2480 struct target_ucred *tcr;
2481
2482 if (get_user_u32(len, optlen)) {
2483 return -TARGET_EFAULT;
2484 }
2485 if (len < 0) {
2486 return -TARGET_EINVAL;
2487 }
2488
2489 crlen = sizeof(cr);
2490 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2491 &cr, &crlen));
2492 if (ret < 0) {
2493 return ret;
2494 }
2495 if (len > crlen) {
2496 len = crlen;
2497 }
2498 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2499 return -TARGET_EFAULT;
2500 }
2501 __put_user(cr.pid, &tcr->pid);
2502 __put_user(cr.uid, &tcr->uid);
2503 __put_user(cr.gid, &tcr->gid);
2504 unlock_user_struct(tcr, optval_addr, 1);
2505 if (put_user_u32(len, optlen)) {
2506 return -TARGET_EFAULT;
2507 }
2508 break;
2509 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002510 /* Options with 'int' argument. */
2511 case TARGET_SO_DEBUG:
2512 optname = SO_DEBUG;
2513 goto int_case;
2514 case TARGET_SO_REUSEADDR:
2515 optname = SO_REUSEADDR;
2516 goto int_case;
2517 case TARGET_SO_TYPE:
2518 optname = SO_TYPE;
2519 goto int_case;
2520 case TARGET_SO_ERROR:
2521 optname = SO_ERROR;
2522 goto int_case;
2523 case TARGET_SO_DONTROUTE:
2524 optname = SO_DONTROUTE;
2525 goto int_case;
2526 case TARGET_SO_BROADCAST:
2527 optname = SO_BROADCAST;
2528 goto int_case;
2529 case TARGET_SO_SNDBUF:
2530 optname = SO_SNDBUF;
2531 goto int_case;
2532 case TARGET_SO_RCVBUF:
2533 optname = SO_RCVBUF;
2534 goto int_case;
2535 case TARGET_SO_KEEPALIVE:
2536 optname = SO_KEEPALIVE;
2537 goto int_case;
2538 case TARGET_SO_OOBINLINE:
2539 optname = SO_OOBINLINE;
2540 goto int_case;
2541 case TARGET_SO_NO_CHECK:
2542 optname = SO_NO_CHECK;
2543 goto int_case;
2544 case TARGET_SO_PRIORITY:
2545 optname = SO_PRIORITY;
2546 goto int_case;
2547#ifdef SO_BSDCOMPAT
2548 case TARGET_SO_BSDCOMPAT:
2549 optname = SO_BSDCOMPAT;
2550 goto int_case;
2551#endif
2552 case TARGET_SO_PASSCRED:
2553 optname = SO_PASSCRED;
2554 goto int_case;
2555 case TARGET_SO_TIMESTAMP:
2556 optname = SO_TIMESTAMP;
2557 goto int_case;
2558 case TARGET_SO_RCVLOWAT:
2559 optname = SO_RCVLOWAT;
2560 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002561 case TARGET_SO_ACCEPTCONN:
2562 optname = SO_ACCEPTCONN;
2563 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002564 default:
bellard2efbe912005-07-23 15:10:20 +00002565 goto int_case;
2566 }
2567 break;
2568 case SOL_TCP:
2569 /* TCP options all take an 'int' value. */
2570 int_case:
bellard2f619692007-11-16 10:46:05 +00002571 if (get_user_u32(len, optlen))
2572 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002573 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002574 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002575 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002576 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2577 if (ret < 0)
2578 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002579 if (optname == SO_TYPE) {
2580 val = host_to_target_sock_type(val);
2581 }
bellard2efbe912005-07-23 15:10:20 +00002582 if (len > lv)
2583 len = lv;
bellard2f619692007-11-16 10:46:05 +00002584 if (len == 4) {
2585 if (put_user_u32(val, optval_addr))
2586 return -TARGET_EFAULT;
2587 } else {
2588 if (put_user_u8(val, optval_addr))
2589 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002590 }
bellard2f619692007-11-16 10:46:05 +00002591 if (put_user_u32(len, optlen))
2592 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002593 break;
2594 case SOL_IP:
2595 switch(optname) {
2596 case IP_TOS:
2597 case IP_TTL:
2598 case IP_HDRINCL:
2599 case IP_ROUTER_ALERT:
2600 case IP_RECVOPTS:
2601 case IP_RETOPTS:
2602 case IP_PKTINFO:
2603 case IP_MTU_DISCOVER:
2604 case IP_RECVERR:
2605 case IP_RECVTOS:
2606#ifdef IP_FREEBIND
2607 case IP_FREEBIND:
2608#endif
2609 case IP_MULTICAST_TTL:
2610 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002611 if (get_user_u32(len, optlen))
2612 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002613 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002614 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002615 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002616 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2617 if (ret < 0)
2618 return ret;
bellard2efbe912005-07-23 15:10:20 +00002619 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002620 len = 1;
bellard2f619692007-11-16 10:46:05 +00002621 if (put_user_u32(len, optlen)
2622 || put_user_u8(val, optval_addr))
2623 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002624 } else {
bellard2efbe912005-07-23 15:10:20 +00002625 if (len > sizeof(int))
2626 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002627 if (put_user_u32(len, optlen)
2628 || put_user_u32(val, optval_addr))
2629 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002630 }
bellard8853f862004-02-22 14:57:26 +00002631 break;
bellard2efbe912005-07-23 15:10:20 +00002632 default:
thsc02f4992007-12-18 02:39:59 +00002633 ret = -TARGET_ENOPROTOOPT;
2634 break;
bellard8853f862004-02-22 14:57:26 +00002635 }
2636 break;
2637 default:
2638 unimplemented:
2639 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2640 level, optname);
thsc02f4992007-12-18 02:39:59 +00002641 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002642 break;
2643 }
2644 return ret;
bellard7854b052003-03-29 17:22:23 +00002645}
2646
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002647static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2648 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002649{
2650 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002651 struct iovec *vec;
2652 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002653 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002654 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002655 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002656
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002657 if (count == 0) {
2658 errno = 0;
2659 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002660 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002661 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002662 errno = EINVAL;
2663 return NULL;
2664 }
2665
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302666 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002667 if (vec == NULL) {
2668 errno = ENOMEM;
2669 return NULL;
2670 }
2671
2672 target_vec = lock_user(VERIFY_READ, target_addr,
2673 count * sizeof(struct target_iovec), 1);
2674 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002675 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002676 goto fail2;
2677 }
2678
2679 /* ??? If host page size > target page size, this will result in a
2680 value larger than what we can actually support. */
2681 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2682 total_len = 0;
2683
2684 for (i = 0; i < count; i++) {
2685 abi_ulong base = tswapal(target_vec[i].iov_base);
2686 abi_long len = tswapal(target_vec[i].iov_len);
2687
2688 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002689 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002690 goto fail;
2691 } else if (len == 0) {
2692 /* Zero length pointer is ignored. */
2693 vec[i].iov_base = 0;
2694 } else {
2695 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002696 /* If the first buffer pointer is bad, this is a fault. But
2697 * subsequent bad buffers will result in a partial write; this
2698 * is realized by filling the vector with null pointers and
2699 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002700 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002701 if (i == 0) {
2702 err = EFAULT;
2703 goto fail;
2704 } else {
2705 bad_address = true;
2706 }
2707 }
2708 if (bad_address) {
2709 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002710 }
2711 if (len > max_len - total_len) {
2712 len = max_len - total_len;
2713 }
2714 }
2715 vec[i].iov_len = len;
2716 total_len += len;
2717 }
2718
2719 unlock_user(target_vec, target_addr, 0);
2720 return vec;
2721
2722 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002723 while (--i >= 0) {
2724 if (tswapal(target_vec[i].iov_len) > 0) {
2725 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2726 }
2727 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002728 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002729 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302730 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002731 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002732 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002733}
2734
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002735static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2736 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002737{
2738 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002739 int i;
2740
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002741 target_vec = lock_user(VERIFY_READ, target_addr,
2742 count * sizeof(struct target_iovec), 1);
2743 if (target_vec) {
2744 for (i = 0; i < count; i++) {
2745 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002746 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002747 if (len < 0) {
2748 break;
2749 }
balrogd732dcb2008-10-28 10:21:03 +00002750 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2751 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002752 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002753 }
bellard579a97f2007-11-11 14:26:47 +00002754
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302755 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002756}
2757
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002758static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002759{
2760 int host_type = 0;
2761 int target_type = *type;
2762
2763 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2764 case TARGET_SOCK_DGRAM:
2765 host_type = SOCK_DGRAM;
2766 break;
2767 case TARGET_SOCK_STREAM:
2768 host_type = SOCK_STREAM;
2769 break;
2770 default:
2771 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2772 break;
2773 }
2774 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002775#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002776 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002777#else
2778 return -TARGET_EINVAL;
2779#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002780 }
2781 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002782#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002783 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002784#elif !defined(O_NONBLOCK)
2785 return -TARGET_EINVAL;
2786#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002787 }
2788 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002789 return 0;
2790}
2791
2792/* Try to emulate socket type flags after socket creation. */
2793static int sock_flags_fixup(int fd, int target_type)
2794{
2795#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2796 if (target_type & TARGET_SOCK_NONBLOCK) {
2797 int flags = fcntl(fd, F_GETFL);
2798 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2799 close(fd);
2800 return -TARGET_EINVAL;
2801 }
2802 }
2803#endif
2804 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002805}
2806
Laurent Vivier0cf22722015-10-28 21:40:45 +01002807static abi_long packet_target_to_host_sockaddr(void *host_addr,
2808 abi_ulong target_addr,
2809 socklen_t len)
2810{
2811 struct sockaddr *addr = host_addr;
2812 struct target_sockaddr *target_saddr;
2813
2814 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2815 if (!target_saddr) {
2816 return -TARGET_EFAULT;
2817 }
2818
2819 memcpy(addr, target_saddr, len);
2820 addr->sa_family = tswap16(target_saddr->sa_family);
2821 /* spkt_protocol is big-endian */
2822
2823 unlock_user(target_saddr, target_addr, 0);
2824 return 0;
2825}
2826
2827static TargetFdTrans target_packet_trans = {
2828 .target_to_host_addr = packet_target_to_host_sockaddr,
2829};
2830
Laurent Vivier575b22b2016-06-02 22:14:15 +02002831#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002832static abi_long netlink_route_target_to_host(void *buf, size_t len)
2833{
Laurent Vivieref759f62016-06-21 19:51:13 +02002834 abi_long ret;
2835
2836 ret = target_to_host_nlmsg_route(buf, len);
2837 if (ret < 0) {
2838 return ret;
2839 }
2840
2841 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002842}
2843
2844static abi_long netlink_route_host_to_target(void *buf, size_t len)
2845{
Laurent Vivieref759f62016-06-21 19:51:13 +02002846 abi_long ret;
2847
2848 ret = host_to_target_nlmsg_route(buf, len);
2849 if (ret < 0) {
2850 return ret;
2851 }
2852
2853 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002854}
2855
2856static TargetFdTrans target_netlink_route_trans = {
2857 .target_to_host_data = netlink_route_target_to_host,
2858 .host_to_target_data = netlink_route_host_to_target,
2859};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002860#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002861
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002862static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2863{
Laurent Vivieref759f62016-06-21 19:51:13 +02002864 abi_long ret;
2865
2866 ret = target_to_host_nlmsg_audit(buf, len);
2867 if (ret < 0) {
2868 return ret;
2869 }
2870
2871 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002872}
2873
2874static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2875{
Laurent Vivieref759f62016-06-21 19:51:13 +02002876 abi_long ret;
2877
2878 ret = host_to_target_nlmsg_audit(buf, len);
2879 if (ret < 0) {
2880 return ret;
2881 }
2882
2883 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002884}
2885
2886static TargetFdTrans target_netlink_audit_trans = {
2887 .target_to_host_data = netlink_audit_target_to_host,
2888 .host_to_target_data = netlink_audit_host_to_target,
2889};
2890
ths0da46a62007-10-20 20:23:07 +00002891/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002892static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002893{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002894 int target_type = type;
2895 int ret;
2896
2897 ret = target_to_host_sock_type(&type);
2898 if (ret) {
2899 return ret;
2900 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002901
Laurent Vivier575b22b2016-06-02 22:14:15 +02002902 if (domain == PF_NETLINK && !(
2903#ifdef CONFIG_RTNETLINK
2904 protocol == NETLINK_ROUTE ||
2905#endif
2906 protocol == NETLINK_KOBJECT_UEVENT ||
2907 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002908 return -EPFNOSUPPORT;
2909 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002910
2911 if (domain == AF_PACKET ||
2912 (domain == AF_INET && type == SOCK_PACKET)) {
2913 protocol = tswap16(protocol);
2914 }
2915
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002916 ret = get_errno(socket(domain, type, protocol));
2917 if (ret >= 0) {
2918 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002919 if (type == SOCK_PACKET) {
2920 /* Manage an obsolete case :
2921 * if socket type is SOCK_PACKET, bind by name
2922 */
2923 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002924 } else if (domain == PF_NETLINK) {
2925 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002926#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002927 case NETLINK_ROUTE:
2928 fd_trans_register(ret, &target_netlink_route_trans);
2929 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002930#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002931 case NETLINK_KOBJECT_UEVENT:
2932 /* nothing to do: messages are strings */
2933 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002934 case NETLINK_AUDIT:
2935 fd_trans_register(ret, &target_netlink_audit_trans);
2936 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002937 default:
2938 g_assert_not_reached();
2939 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002940 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002941 }
2942 return ret;
bellard3532fa72006-06-24 15:06:03 +00002943}
2944
ths0da46a62007-10-20 20:23:07 +00002945/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002946static abi_long do_bind(int sockfd, abi_ulong target_addr,
2947 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002948{
aurel328f7aeaf2009-01-30 19:47:57 +00002949 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002950 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002951
Blue Swirl38724252010-09-18 05:53:14 +00002952 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002953 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002954 }
aurel328f7aeaf2009-01-30 19:47:57 +00002955
aurel32607175e2009-04-15 16:11:59 +00002956 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002957
Laurent Vivier7b36f782015-10-28 21:40:44 +01002958 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002959 if (ret)
2960 return ret;
2961
bellard3532fa72006-06-24 15:06:03 +00002962 return get_errno(bind(sockfd, addr, addrlen));
2963}
2964
ths0da46a62007-10-20 20:23:07 +00002965/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002966static abi_long do_connect(int sockfd, abi_ulong target_addr,
2967 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002968{
aurel328f7aeaf2009-01-30 19:47:57 +00002969 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002970 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002971
Blue Swirl38724252010-09-18 05:53:14 +00002972 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002973 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002974 }
aurel328f7aeaf2009-01-30 19:47:57 +00002975
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002976 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002977
Laurent Vivier7b36f782015-10-28 21:40:44 +01002978 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002979 if (ret)
2980 return ret;
2981
Peter Maydell2a3c7612016-06-06 19:58:03 +01002982 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002983}
2984
Alexander Graff19e00d2014-03-02 19:36:42 +00002985/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2986static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2987 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002988{
balrog6de645c2008-10-28 10:26:29 +00002989 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002990 struct msghdr msg;
2991 int count;
2992 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002993 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002994
bellard3532fa72006-06-24 15:06:03 +00002995 if (msgp->msg_name) {
2996 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002997 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002998 ret = target_to_host_sockaddr(fd, msg.msg_name,
2999 tswapal(msgp->msg_name),
3000 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003001 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003002 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003003 }
bellard3532fa72006-06-24 15:06:03 +00003004 } else {
3005 msg.msg_name = NULL;
3006 msg.msg_namelen = 0;
3007 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003008 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003009 msg.msg_control = alloca(msg.msg_controllen);
3010 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003011
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003012 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003013 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003014 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3015 target_vec, count, send);
3016 if (vec == NULL) {
3017 ret = -host_to_target_errno(errno);
3018 goto out2;
3019 }
bellard3532fa72006-06-24 15:06:03 +00003020 msg.msg_iovlen = count;
3021 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003022
bellard3532fa72006-06-24 15:06:03 +00003023 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003024 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003025 void *host_msg;
3026
3027 host_msg = g_malloc(msg.msg_iov->iov_len);
3028 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3029 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003030 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003031 if (ret >= 0) {
3032 msg.msg_iov->iov_base = host_msg;
3033 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3034 }
3035 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003036 } else {
3037 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003038 if (ret == 0) {
3039 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3040 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003041 }
bellard3532fa72006-06-24 15:06:03 +00003042 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003043 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003044 if (!is_error(ret)) {
3045 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003046 if (fd_trans_host_to_target_data(fd)) {
3047 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003048 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003049 } else {
3050 ret = host_to_target_cmsg(msgp, &msg);
3051 }
Jing Huangca619062012-07-24 13:58:02 +00003052 if (!is_error(ret)) {
3053 msgp->msg_namelen = tswap32(msg.msg_namelen);
3054 if (msg.msg_name != NULL) {
3055 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3056 msg.msg_name, msg.msg_namelen);
3057 if (ret) {
3058 goto out;
3059 }
3060 }
3061
balrog6de645c2008-10-28 10:26:29 +00003062 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003063 }
balrog6de645c2008-10-28 10:26:29 +00003064 }
bellard3532fa72006-06-24 15:06:03 +00003065 }
Jing Huangca619062012-07-24 13:58:02 +00003066
3067out:
bellard3532fa72006-06-24 15:06:03 +00003068 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003069out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003070 return ret;
3071}
3072
3073static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3074 int flags, int send)
3075{
3076 abi_long ret;
3077 struct target_msghdr *msgp;
3078
3079 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3080 msgp,
3081 target_msg,
3082 send ? 1 : 0)) {
3083 return -TARGET_EFAULT;
3084 }
3085 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003086 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003087 return ret;
3088}
3089
Alexander Graff19e00d2014-03-02 19:36:42 +00003090/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3091 * so it might not have this *mmsg-specific flag either.
3092 */
3093#ifndef MSG_WAITFORONE
3094#define MSG_WAITFORONE 0x10000
3095#endif
3096
3097static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3098 unsigned int vlen, unsigned int flags,
3099 int send)
3100{
3101 struct target_mmsghdr *mmsgp;
3102 abi_long ret = 0;
3103 int i;
3104
3105 if (vlen > UIO_MAXIOV) {
3106 vlen = UIO_MAXIOV;
3107 }
3108
3109 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3110 if (!mmsgp) {
3111 return -TARGET_EFAULT;
3112 }
3113
3114 for (i = 0; i < vlen; i++) {
3115 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3116 if (is_error(ret)) {
3117 break;
3118 }
3119 mmsgp[i].msg_len = tswap32(ret);
3120 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3121 if (flags & MSG_WAITFORONE) {
3122 flags |= MSG_DONTWAIT;
3123 }
3124 }
3125
3126 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3127
3128 /* Return number of datagrams sent if we sent any at all;
3129 * otherwise return the error.
3130 */
3131 if (i) {
3132 return i;
3133 }
3134 return ret;
3135}
Alexander Graff19e00d2014-03-02 19:36:42 +00003136
Peter Maydella94b4982013-02-08 04:35:04 +00003137/* do_accept4() Must return target values and target errnos. */
3138static abi_long do_accept4(int fd, abi_ulong target_addr,
3139 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003140{
bellard2f619692007-11-16 10:46:05 +00003141 socklen_t addrlen;
3142 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003143 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003144 int host_flags;
3145
3146 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003147
Peter Maydella94b4982013-02-08 04:35:04 +00003148 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003149 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003150 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003151
3152 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003153 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003154 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003155
Blue Swirl38724252010-09-18 05:53:14 +00003156 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003157 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003158 }
aurel328f7aeaf2009-01-30 19:47:57 +00003159
Arnaud Patard917507b2009-06-19 10:44:45 +03003160 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3161 return -TARGET_EINVAL;
3162
bellard2f619692007-11-16 10:46:05 +00003163 addr = alloca(addrlen);
3164
Peter Maydellff6dc132016-06-06 19:58:13 +01003165 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003166 if (!is_error(ret)) {
3167 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003168 if (put_user_u32(addrlen, target_addrlen_addr))
3169 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003170 }
3171 return ret;
3172}
3173
ths0da46a62007-10-20 20:23:07 +00003174/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003175static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003176 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003177{
bellard2f619692007-11-16 10:46:05 +00003178 socklen_t addrlen;
3179 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003180 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003181
bellard2f619692007-11-16 10:46:05 +00003182 if (get_user_u32(addrlen, target_addrlen_addr))
3183 return -TARGET_EFAULT;
3184
Blue Swirl38724252010-09-18 05:53:14 +00003185 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003186 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003187 }
aurel328f7aeaf2009-01-30 19:47:57 +00003188
Arnaud Patard917507b2009-06-19 10:44:45 +03003189 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3190 return -TARGET_EFAULT;
3191
bellard2f619692007-11-16 10:46:05 +00003192 addr = alloca(addrlen);
3193
pbrook1be9e1d2006-11-19 15:26:04 +00003194 ret = get_errno(getpeername(fd, addr, &addrlen));
3195 if (!is_error(ret)) {
3196 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003197 if (put_user_u32(addrlen, target_addrlen_addr))
3198 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003199 }
3200 return ret;
3201}
3202
ths0da46a62007-10-20 20:23:07 +00003203/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003204static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003205 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003206{
bellard2f619692007-11-16 10:46:05 +00003207 socklen_t addrlen;
3208 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003209 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003210
bellard2f619692007-11-16 10:46:05 +00003211 if (get_user_u32(addrlen, target_addrlen_addr))
3212 return -TARGET_EFAULT;
3213
Blue Swirl38724252010-09-18 05:53:14 +00003214 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003215 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003216 }
aurel328f7aeaf2009-01-30 19:47:57 +00003217
Arnaud Patard917507b2009-06-19 10:44:45 +03003218 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3219 return -TARGET_EFAULT;
3220
bellard2f619692007-11-16 10:46:05 +00003221 addr = alloca(addrlen);
3222
pbrook1be9e1d2006-11-19 15:26:04 +00003223 ret = get_errno(getsockname(fd, addr, &addrlen));
3224 if (!is_error(ret)) {
3225 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003226 if (put_user_u32(addrlen, target_addrlen_addr))
3227 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003228 }
3229 return ret;
3230}
3231
ths0da46a62007-10-20 20:23:07 +00003232/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003233static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003234 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003235{
3236 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003237 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003238
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003239 target_to_host_sock_type(&type);
3240
pbrook1be9e1d2006-11-19 15:26:04 +00003241 ret = get_errno(socketpair(domain, type, protocol, tab));
3242 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003243 if (put_user_s32(tab[0], target_tab_addr)
3244 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3245 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003246 }
3247 return ret;
3248}
3249
ths0da46a62007-10-20 20:23:07 +00003250/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003251static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3252 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003253{
3254 void *addr;
3255 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003256 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003257 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003258
Blue Swirl38724252010-09-18 05:53:14 +00003259 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003260 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003261 }
aurel328f7aeaf2009-01-30 19:47:57 +00003262
bellard579a97f2007-11-11 14:26:47 +00003263 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3264 if (!host_msg)
3265 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003266 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003267 copy_msg = host_msg;
3268 host_msg = g_malloc(len);
3269 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003270 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3271 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003272 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003273 }
3274 }
pbrook1be9e1d2006-11-19 15:26:04 +00003275 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003276 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003277 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003278 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003279 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003280 }
Peter Maydell66687532016-06-06 19:58:04 +01003281 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003282 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003283 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003284 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003285fail:
3286 if (copy_msg) {
3287 g_free(host_msg);
3288 host_msg = copy_msg;
3289 }
pbrook1be9e1d2006-11-19 15:26:04 +00003290 unlock_user(host_msg, msg, 0);
3291 return ret;
3292}
3293
ths0da46a62007-10-20 20:23:07 +00003294/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003295static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3296 abi_ulong target_addr,
3297 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003298{
3299 socklen_t addrlen;
3300 void *addr;
3301 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003302 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003303
bellard579a97f2007-11-11 14:26:47 +00003304 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3305 if (!host_msg)
3306 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003307 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003308 if (get_user_u32(addrlen, target_addrlen)) {
3309 ret = -TARGET_EFAULT;
3310 goto fail;
3311 }
Blue Swirl38724252010-09-18 05:53:14 +00003312 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003313 ret = -TARGET_EINVAL;
3314 goto fail;
3315 }
pbrook1be9e1d2006-11-19 15:26:04 +00003316 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003317 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3318 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003319 } else {
3320 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003321 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003322 }
3323 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003324 if (fd_trans_host_to_target_data(fd)) {
3325 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
3326 }
pbrook1be9e1d2006-11-19 15:26:04 +00003327 if (target_addr) {
3328 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003329 if (put_user_u32(addrlen, target_addrlen)) {
3330 ret = -TARGET_EFAULT;
3331 goto fail;
3332 }
pbrook1be9e1d2006-11-19 15:26:04 +00003333 }
3334 unlock_user(host_msg, msg, len);
3335 } else {
bellard2f619692007-11-16 10:46:05 +00003336fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003337 unlock_user(host_msg, msg, 0);
3338 }
3339 return ret;
3340}
3341
j_mayer32407102007-09-26 23:01:49 +00003342#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003343/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003344static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003345{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003346 static const unsigned ac[] = { /* number of arguments per call */
3347 [SOCKOP_socket] = 3, /* domain, type, protocol */
3348 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3349 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3350 [SOCKOP_listen] = 2, /* sockfd, backlog */
3351 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3352 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3353 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3354 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3355 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3356 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3357 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3358 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3359 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3360 [SOCKOP_shutdown] = 2, /* sockfd, how */
3361 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3362 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003363 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3364 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003365 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3366 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3367 };
3368 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003369
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003370 /* first, collect the arguments in a[] according to ac[] */
3371 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3372 unsigned i;
3373 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3374 for (i = 0; i < ac[num]; ++i) {
3375 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003376 return -TARGET_EFAULT;
3377 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003378 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003379 }
bellard2f619692007-11-16 10:46:05 +00003380
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003381 /* now when we have the args, actually handle the call */
3382 switch (num) {
3383 case SOCKOP_socket: /* domain, type, protocol */
3384 return do_socket(a[0], a[1], a[2]);
3385 case SOCKOP_bind: /* sockfd, addr, addrlen */
3386 return do_bind(a[0], a[1], a[2]);
3387 case SOCKOP_connect: /* sockfd, addr, addrlen */
3388 return do_connect(a[0], a[1], a[2]);
3389 case SOCKOP_listen: /* sockfd, backlog */
3390 return get_errno(listen(a[0], a[1]));
3391 case SOCKOP_accept: /* sockfd, addr, addrlen */
3392 return do_accept4(a[0], a[1], a[2], 0);
3393 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3394 return do_accept4(a[0], a[1], a[2], a[3]);
3395 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3396 return do_getsockname(a[0], a[1], a[2]);
3397 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3398 return do_getpeername(a[0], a[1], a[2]);
3399 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3400 return do_socketpair(a[0], a[1], a[2], a[3]);
3401 case SOCKOP_send: /* sockfd, msg, len, flags */
3402 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3403 case SOCKOP_recv: /* sockfd, msg, len, flags */
3404 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3405 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3406 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3407 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3408 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3409 case SOCKOP_shutdown: /* sockfd, how */
3410 return get_errno(shutdown(a[0], a[1]));
3411 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3412 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3413 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3414 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003415 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3416 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3417 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3418 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003419 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3420 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3421 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3422 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003423 default:
3424 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003425 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003426 }
bellard31e31b82003-02-18 22:55:36 +00003427}
j_mayer32407102007-09-26 23:01:49 +00003428#endif
bellard31e31b82003-02-18 22:55:36 +00003429
bellard8853f862004-02-22 14:57:26 +00003430#define N_SHM_REGIONS 32
3431
3432static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003433 abi_ulong start;
3434 abi_ulong size;
3435 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003436} shm_regions[N_SHM_REGIONS];
3437
ths3eb6b042007-06-03 14:26:27 +00003438struct target_semid_ds
3439{
3440 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003441 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003442#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003443 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003444#endif
blueswir1992f48a2007-10-14 16:27:31 +00003445 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003446#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003447 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003448#endif
blueswir1992f48a2007-10-14 16:27:31 +00003449 abi_ulong sem_nsems;
3450 abi_ulong __unused3;
3451 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003452};
3453
bellard579a97f2007-11-11 14:26:47 +00003454static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3455 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003456{
3457 struct target_ipc_perm *target_ip;
3458 struct target_semid_ds *target_sd;
3459
bellard579a97f2007-11-11 14:26:47 +00003460 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3461 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003462 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003463 host_ip->__key = tswap32(target_ip->__key);
3464 host_ip->uid = tswap32(target_ip->uid);
3465 host_ip->gid = tswap32(target_ip->gid);
3466 host_ip->cuid = tswap32(target_ip->cuid);
3467 host_ip->cgid = tswap32(target_ip->cgid);
3468#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3469 host_ip->mode = tswap32(target_ip->mode);
3470#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003471 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003472#endif
3473#if defined(TARGET_PPC)
3474 host_ip->__seq = tswap32(target_ip->__seq);
3475#else
3476 host_ip->__seq = tswap16(target_ip->__seq);
3477#endif
ths3eb6b042007-06-03 14:26:27 +00003478 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003479 return 0;
ths3eb6b042007-06-03 14:26:27 +00003480}
3481
bellard579a97f2007-11-11 14:26:47 +00003482static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3483 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003484{
3485 struct target_ipc_perm *target_ip;
3486 struct target_semid_ds *target_sd;
3487
bellard579a97f2007-11-11 14:26:47 +00003488 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3489 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003490 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003491 target_ip->__key = tswap32(host_ip->__key);
3492 target_ip->uid = tswap32(host_ip->uid);
3493 target_ip->gid = tswap32(host_ip->gid);
3494 target_ip->cuid = tswap32(host_ip->cuid);
3495 target_ip->cgid = tswap32(host_ip->cgid);
3496#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3497 target_ip->mode = tswap32(host_ip->mode);
3498#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003499 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003500#endif
3501#if defined(TARGET_PPC)
3502 target_ip->__seq = tswap32(host_ip->__seq);
3503#else
3504 target_ip->__seq = tswap16(host_ip->__seq);
3505#endif
ths3eb6b042007-06-03 14:26:27 +00003506 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003507 return 0;
ths3eb6b042007-06-03 14:26:27 +00003508}
3509
bellard579a97f2007-11-11 14:26:47 +00003510static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3511 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003512{
3513 struct target_semid_ds *target_sd;
3514
bellard579a97f2007-11-11 14:26:47 +00003515 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3516 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003517 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3518 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003519 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3520 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3521 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003522 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003523 return 0;
ths3eb6b042007-06-03 14:26:27 +00003524}
3525
bellard579a97f2007-11-11 14:26:47 +00003526static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3527 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003528{
3529 struct target_semid_ds *target_sd;
3530
bellard579a97f2007-11-11 14:26:47 +00003531 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3532 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003533 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003534 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003535 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3536 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3537 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003538 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003539 return 0;
ths3eb6b042007-06-03 14:26:27 +00003540}
3541
aurel32e5289082009-04-18 16:16:12 +00003542struct target_seminfo {
3543 int semmap;
3544 int semmni;
3545 int semmns;
3546 int semmnu;
3547 int semmsl;
3548 int semopm;
3549 int semume;
3550 int semusz;
3551 int semvmx;
3552 int semaem;
3553};
3554
3555static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3556 struct seminfo *host_seminfo)
3557{
3558 struct target_seminfo *target_seminfo;
3559 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3560 return -TARGET_EFAULT;
3561 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3562 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3563 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3564 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3565 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3566 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3567 __put_user(host_seminfo->semume, &target_seminfo->semume);
3568 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3569 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3570 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3571 unlock_user_struct(target_seminfo, target_addr, 1);
3572 return 0;
3573}
3574
thsfa294812007-02-02 22:05:00 +00003575union semun {
3576 int val;
ths3eb6b042007-06-03 14:26:27 +00003577 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003578 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003579 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003580};
3581
ths3eb6b042007-06-03 14:26:27 +00003582union target_semun {
3583 int val;
aurel32e5289082009-04-18 16:16:12 +00003584 abi_ulong buf;
3585 abi_ulong array;
3586 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003587};
3588
aurel32e5289082009-04-18 16:16:12 +00003589static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3590 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003591{
aurel32e5289082009-04-18 16:16:12 +00003592 int nsems;
3593 unsigned short *array;
3594 union semun semun;
3595 struct semid_ds semid_ds;
3596 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003597
aurel32e5289082009-04-18 16:16:12 +00003598 semun.buf = &semid_ds;
3599
3600 ret = semctl(semid, 0, IPC_STAT, semun);
3601 if (ret == -1)
3602 return get_errno(ret);
3603
3604 nsems = semid_ds.sem_nsems;
3605
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303606 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003607 if (!*host_array) {
3608 return -TARGET_ENOMEM;
3609 }
aurel32e5289082009-04-18 16:16:12 +00003610 array = lock_user(VERIFY_READ, target_addr,
3611 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003612 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303613 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003614 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003615 }
aurel32e5289082009-04-18 16:16:12 +00003616
3617 for(i=0; i<nsems; i++) {
3618 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003619 }
aurel32e5289082009-04-18 16:16:12 +00003620 unlock_user(array, target_addr, 0);
3621
bellard579a97f2007-11-11 14:26:47 +00003622 return 0;
ths3eb6b042007-06-03 14:26:27 +00003623}
3624
aurel32e5289082009-04-18 16:16:12 +00003625static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3626 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003627{
aurel32e5289082009-04-18 16:16:12 +00003628 int nsems;
3629 unsigned short *array;
3630 union semun semun;
3631 struct semid_ds semid_ds;
3632 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003633
aurel32e5289082009-04-18 16:16:12 +00003634 semun.buf = &semid_ds;
3635
3636 ret = semctl(semid, 0, IPC_STAT, semun);
3637 if (ret == -1)
3638 return get_errno(ret);
3639
3640 nsems = semid_ds.sem_nsems;
3641
3642 array = lock_user(VERIFY_WRITE, target_addr,
3643 nsems*sizeof(unsigned short), 0);
3644 if (!array)
3645 return -TARGET_EFAULT;
3646
3647 for(i=0; i<nsems; i++) {
3648 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003649 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303650 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003651 unlock_user(array, target_addr, 1);
3652
bellard579a97f2007-11-11 14:26:47 +00003653 return 0;
ths3eb6b042007-06-03 14:26:27 +00003654}
3655
aurel32e5289082009-04-18 16:16:12 +00003656static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003657 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003658{
Stefan Weild1c002b2015-02-08 15:40:58 +01003659 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003660 union semun arg;
3661 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303662 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003663 struct seminfo seminfo;
3664 abi_long ret = -TARGET_EINVAL;
3665 abi_long err;
3666 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003667
3668 switch( cmd ) {
3669 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003670 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003671 /* In 64 bit cross-endian situations, we will erroneously pick up
3672 * the wrong half of the union for the "val" element. To rectify
3673 * this, the entire 8-byte structure is byteswapped, followed by
3674 * a swap of the 4 byte val field. In other cases, the data is
3675 * already in proper host byte order. */
3676 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3677 target_su.buf = tswapal(target_su.buf);
3678 arg.val = tswap32(target_su.val);
3679 } else {
3680 arg.val = target_su.val;
3681 }
aurel32e5289082009-04-18 16:16:12 +00003682 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003683 break;
3684 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003685 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003686 err = target_to_host_semarray(semid, &array, target_su.array);
3687 if (err)
3688 return err;
3689 arg.array = array;
3690 ret = get_errno(semctl(semid, semnum, cmd, arg));
3691 err = host_to_target_semarray(semid, target_su.array, &array);
3692 if (err)
3693 return err;
ths3eb6b042007-06-03 14:26:27 +00003694 break;
3695 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003696 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003697 case SEM_STAT:
3698 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3699 if (err)
3700 return err;
3701 arg.buf = &dsarg;
3702 ret = get_errno(semctl(semid, semnum, cmd, arg));
3703 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3704 if (err)
3705 return err;
ths3eb6b042007-06-03 14:26:27 +00003706 break;
aurel32e5289082009-04-18 16:16:12 +00003707 case IPC_INFO:
3708 case SEM_INFO:
3709 arg.__buf = &seminfo;
3710 ret = get_errno(semctl(semid, semnum, cmd, arg));
3711 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3712 if (err)
3713 return err;
3714 break;
3715 case IPC_RMID:
3716 case GETPID:
3717 case GETNCNT:
3718 case GETZCNT:
3719 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3720 break;
ths3eb6b042007-06-03 14:26:27 +00003721 }
3722
3723 return ret;
3724}
3725
aurel32e5289082009-04-18 16:16:12 +00003726struct target_sembuf {
3727 unsigned short sem_num;
3728 short sem_op;
3729 short sem_flg;
3730};
3731
3732static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3733 abi_ulong target_addr,
3734 unsigned nsops)
3735{
3736 struct target_sembuf *target_sembuf;
3737 int i;
3738
3739 target_sembuf = lock_user(VERIFY_READ, target_addr,
3740 nsops*sizeof(struct target_sembuf), 1);
3741 if (!target_sembuf)
3742 return -TARGET_EFAULT;
3743
3744 for(i=0; i<nsops; i++) {
3745 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3746 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3747 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3748 }
3749
3750 unlock_user(target_sembuf, target_addr, 0);
3751
3752 return 0;
3753}
3754
3755static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3756{
3757 struct sembuf sops[nsops];
3758
3759 if (target_to_host_sembuf(sops, ptr, nsops))
3760 return -TARGET_EFAULT;
3761
Peter Maydellffb7ee72016-06-06 19:58:12 +01003762 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00003763}
3764
ths1bc012f2007-06-03 14:27:49 +00003765struct target_msqid_ds
3766{
aurel321c54ff92008-10-13 21:08:44 +00003767 struct target_ipc_perm msg_perm;
3768 abi_ulong msg_stime;
3769#if TARGET_ABI_BITS == 32
3770 abi_ulong __unused1;
3771#endif
3772 abi_ulong msg_rtime;
3773#if TARGET_ABI_BITS == 32
3774 abi_ulong __unused2;
3775#endif
3776 abi_ulong msg_ctime;
3777#if TARGET_ABI_BITS == 32
3778 abi_ulong __unused3;
3779#endif
3780 abi_ulong __msg_cbytes;
3781 abi_ulong msg_qnum;
3782 abi_ulong msg_qbytes;
3783 abi_ulong msg_lspid;
3784 abi_ulong msg_lrpid;
3785 abi_ulong __unused4;
3786 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003787};
3788
bellard579a97f2007-11-11 14:26:47 +00003789static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3790 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003791{
3792 struct target_msqid_ds *target_md;
3793
bellard579a97f2007-11-11 14:26:47 +00003794 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3795 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003796 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3797 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003798 host_md->msg_stime = tswapal(target_md->msg_stime);
3799 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3800 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3801 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3802 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3803 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3804 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3805 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003806 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003807 return 0;
ths1bc012f2007-06-03 14:27:49 +00003808}
3809
bellard579a97f2007-11-11 14:26:47 +00003810static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3811 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003812{
3813 struct target_msqid_ds *target_md;
3814
bellard579a97f2007-11-11 14:26:47 +00003815 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3816 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003817 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3818 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003819 target_md->msg_stime = tswapal(host_md->msg_stime);
3820 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3821 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3822 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3823 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3824 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3825 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3826 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003827 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003828 return 0;
ths1bc012f2007-06-03 14:27:49 +00003829}
3830
aurel321c54ff92008-10-13 21:08:44 +00003831struct target_msginfo {
3832 int msgpool;
3833 int msgmap;
3834 int msgmax;
3835 int msgmnb;
3836 int msgmni;
3837 int msgssz;
3838 int msgtql;
3839 unsigned short int msgseg;
3840};
3841
3842static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3843 struct msginfo *host_msginfo)
3844{
3845 struct target_msginfo *target_msginfo;
3846 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3847 return -TARGET_EFAULT;
3848 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3849 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3850 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3851 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3852 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3853 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3854 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3855 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3856 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003857 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003858}
3859
3860static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003861{
3862 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003863 struct msginfo msginfo;
3864 abi_long ret = -TARGET_EINVAL;
3865
3866 cmd &= 0xff;
3867
3868 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003869 case IPC_STAT:
3870 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003871 case MSG_STAT:
3872 if (target_to_host_msqid_ds(&dsarg,ptr))
3873 return -TARGET_EFAULT;
3874 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3875 if (host_to_target_msqid_ds(ptr,&dsarg))
3876 return -TARGET_EFAULT;
3877 break;
3878 case IPC_RMID:
3879 ret = get_errno(msgctl(msgid, cmd, NULL));
3880 break;
3881 case IPC_INFO:
3882 case MSG_INFO:
3883 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3884 if (host_to_target_msginfo(ptr, &msginfo))
3885 return -TARGET_EFAULT;
3886 break;
ths1bc012f2007-06-03 14:27:49 +00003887 }
aurel321c54ff92008-10-13 21:08:44 +00003888
ths1bc012f2007-06-03 14:27:49 +00003889 return ret;
3890}
3891
3892struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003893 abi_long mtype;
3894 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003895};
3896
blueswir1992f48a2007-10-14 16:27:31 +00003897static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003898 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003899{
3900 struct target_msgbuf *target_mb;
3901 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003902 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003903
Tom Mustaedcc5f92014-08-12 13:53:37 -05003904 if (msgsz < 0) {
3905 return -TARGET_EINVAL;
3906 }
3907
bellard579a97f2007-11-11 14:26:47 +00003908 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3909 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303910 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003911 if (!host_mb) {
3912 unlock_user_struct(target_mb, msgp, 0);
3913 return -TARGET_ENOMEM;
3914 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003915 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003916 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01003917 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303918 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003919 unlock_user_struct(target_mb, msgp, 0);
3920
3921 return ret;
3922}
3923
blueswir1992f48a2007-10-14 16:27:31 +00003924static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003925 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003926 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003927{
3928 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003929 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003930 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003931 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003932
Peter Maydell99874f62016-05-20 19:00:56 +01003933 if (msgsz < 0) {
3934 return -TARGET_EINVAL;
3935 }
3936
bellard579a97f2007-11-11 14:26:47 +00003937 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3938 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003939
Peter Maydell415d8472016-05-20 19:00:57 +01003940 host_mb = g_try_malloc(msgsz + sizeof(long));
3941 if (!host_mb) {
3942 ret = -TARGET_ENOMEM;
3943 goto end;
3944 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01003945 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003946
bellard579a97f2007-11-11 14:26:47 +00003947 if (ret > 0) {
3948 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3949 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3950 if (!target_mtext) {
3951 ret = -TARGET_EFAULT;
3952 goto end;
3953 }
aurel321c54ff92008-10-13 21:08:44 +00003954 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003955 unlock_user(target_mtext, target_mtext_addr, ret);
3956 }
aurel321c54ff92008-10-13 21:08:44 +00003957
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003958 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003959
bellard579a97f2007-11-11 14:26:47 +00003960end:
3961 if (target_mb)
3962 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003963 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003964 return ret;
3965}
3966
Riku Voipio88a8c982009-04-03 10:42:00 +03003967static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3968 abi_ulong target_addr)
3969{
3970 struct target_shmid_ds *target_sd;
3971
3972 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3973 return -TARGET_EFAULT;
3974 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3975 return -TARGET_EFAULT;
3976 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3977 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3978 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3979 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3980 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3981 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3982 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3983 unlock_user_struct(target_sd, target_addr, 0);
3984 return 0;
3985}
3986
3987static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3988 struct shmid_ds *host_sd)
3989{
3990 struct target_shmid_ds *target_sd;
3991
3992 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3993 return -TARGET_EFAULT;
3994 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3995 return -TARGET_EFAULT;
3996 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3997 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3998 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3999 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4000 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4001 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4002 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4003 unlock_user_struct(target_sd, target_addr, 1);
4004 return 0;
4005}
4006
4007struct target_shminfo {
4008 abi_ulong shmmax;
4009 abi_ulong shmmin;
4010 abi_ulong shmmni;
4011 abi_ulong shmseg;
4012 abi_ulong shmall;
4013};
4014
4015static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4016 struct shminfo *host_shminfo)
4017{
4018 struct target_shminfo *target_shminfo;
4019 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4020 return -TARGET_EFAULT;
4021 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4022 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4023 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4024 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4025 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4026 unlock_user_struct(target_shminfo, target_addr, 1);
4027 return 0;
4028}
4029
4030struct target_shm_info {
4031 int used_ids;
4032 abi_ulong shm_tot;
4033 abi_ulong shm_rss;
4034 abi_ulong shm_swp;
4035 abi_ulong swap_attempts;
4036 abi_ulong swap_successes;
4037};
4038
4039static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4040 struct shm_info *host_shm_info)
4041{
4042 struct target_shm_info *target_shm_info;
4043 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4044 return -TARGET_EFAULT;
4045 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4046 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4047 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4048 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4049 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4050 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4051 unlock_user_struct(target_shm_info, target_addr, 1);
4052 return 0;
4053}
4054
4055static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4056{
4057 struct shmid_ds dsarg;
4058 struct shminfo shminfo;
4059 struct shm_info shm_info;
4060 abi_long ret = -TARGET_EINVAL;
4061
4062 cmd &= 0xff;
4063
4064 switch(cmd) {
4065 case IPC_STAT:
4066 case IPC_SET:
4067 case SHM_STAT:
4068 if (target_to_host_shmid_ds(&dsarg, buf))
4069 return -TARGET_EFAULT;
4070 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4071 if (host_to_target_shmid_ds(buf, &dsarg))
4072 return -TARGET_EFAULT;
4073 break;
4074 case IPC_INFO:
4075 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4076 if (host_to_target_shminfo(buf, &shminfo))
4077 return -TARGET_EFAULT;
4078 break;
4079 case SHM_INFO:
4080 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4081 if (host_to_target_shm_info(buf, &shm_info))
4082 return -TARGET_EFAULT;
4083 break;
4084 case IPC_RMID:
4085 case SHM_LOCK:
4086 case SHM_UNLOCK:
4087 ret = get_errno(shmctl(shmid, cmd, NULL));
4088 break;
4089 }
4090
4091 return ret;
4092}
4093
4094static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4095{
4096 abi_long raddr;
4097 void *host_raddr;
4098 struct shmid_ds shm_info;
4099 int i,ret;
4100
4101 /* find out the length of the shared memory segment */
4102 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4103 if (is_error(ret)) {
4104 /* can't get length, bail out */
4105 return ret;
4106 }
4107
4108 mmap_lock();
4109
4110 if (shmaddr)
4111 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4112 else {
4113 abi_ulong mmap_start;
4114
4115 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4116
4117 if (mmap_start == -1) {
4118 errno = ENOMEM;
4119 host_raddr = (void *)-1;
4120 } else
4121 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4122 }
4123
4124 if (host_raddr == (void *)-1) {
4125 mmap_unlock();
4126 return get_errno((long)host_raddr);
4127 }
4128 raddr=h2g((unsigned long)host_raddr);
4129
4130 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4131 PAGE_VALID | PAGE_READ |
4132 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4133
4134 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004135 if (!shm_regions[i].in_use) {
4136 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004137 shm_regions[i].start = raddr;
4138 shm_regions[i].size = shm_info.shm_segsz;
4139 break;
4140 }
4141 }
4142
4143 mmap_unlock();
4144 return raddr;
4145
4146}
4147
4148static inline abi_long do_shmdt(abi_ulong shmaddr)
4149{
4150 int i;
4151
4152 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004153 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4154 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004155 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004156 break;
4157 }
4158 }
4159
4160 return get_errno(shmdt(g2h(shmaddr)));
4161}
4162
aurel321c54ff92008-10-13 21:08:44 +00004163#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004164/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004165/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004166static abi_long do_ipc(unsigned int call, abi_long first,
4167 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004168 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004169{
4170 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004171 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004172
4173 version = call >> 16;
4174 call &= 0xffff;
4175
4176 switch (call) {
thsfa294812007-02-02 22:05:00 +00004177 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004178 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004179 break;
4180
4181 case IPCOP_semget:
4182 ret = get_errno(semget(first, second, third));
4183 break;
4184
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004185 case IPCOP_semctl: {
4186 /* The semun argument to semctl is passed by value, so dereference the
4187 * ptr argument. */
4188 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004189 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004190 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004191 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004192 }
thsd96372e2007-02-02 22:05:44 +00004193
aurel321c54ff92008-10-13 21:08:44 +00004194 case IPCOP_msgget:
4195 ret = get_errno(msgget(first, second));
4196 break;
thsd96372e2007-02-02 22:05:44 +00004197
aurel321c54ff92008-10-13 21:08:44 +00004198 case IPCOP_msgsnd:
4199 ret = do_msgsnd(first, ptr, second, third);
4200 break;
thsd96372e2007-02-02 22:05:44 +00004201
aurel321c54ff92008-10-13 21:08:44 +00004202 case IPCOP_msgctl:
4203 ret = do_msgctl(first, second, ptr);
4204 break;
thsd96372e2007-02-02 22:05:44 +00004205
aurel321c54ff92008-10-13 21:08:44 +00004206 case IPCOP_msgrcv:
4207 switch (version) {
4208 case 0:
4209 {
4210 struct target_ipc_kludge {
4211 abi_long msgp;
4212 abi_long msgtyp;
4213 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004214
aurel321c54ff92008-10-13 21:08:44 +00004215 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4216 ret = -TARGET_EFAULT;
4217 break;
ths1bc012f2007-06-03 14:27:49 +00004218 }
aurel321c54ff92008-10-13 21:08:44 +00004219
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004220 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004221
4222 unlock_user_struct(tmp, ptr, 0);
4223 break;
4224 }
4225 default:
4226 ret = do_msgrcv(first, ptr, second, fifth, third);
4227 }
4228 break;
thsd96372e2007-02-02 22:05:44 +00004229
bellard8853f862004-02-22 14:57:26 +00004230 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004231 switch (version) {
4232 default:
bellard5a4a8982007-11-11 17:39:18 +00004233 {
4234 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004235 raddr = do_shmat(first, ptr, second);
4236 if (is_error(raddr))
4237 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004238 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004239 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004240 break;
4241 }
4242 case 1:
4243 ret = -TARGET_EINVAL;
4244 break;
bellard5a4a8982007-11-11 17:39:18 +00004245 }
bellard8853f862004-02-22 14:57:26 +00004246 break;
4247 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004248 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004249 break;
4250
4251 case IPCOP_shmget:
4252 /* IPC_* flag values are the same on all linux platforms */
4253 ret = get_errno(shmget(first, second, third));
4254 break;
4255
4256 /* IPC_* and SHM_* command values are the same on all linux platforms */
4257 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004258 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004259 break;
4260 default:
j_mayer32407102007-09-26 23:01:49 +00004261 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004262 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004263 break;
4264 }
4265 return ret;
4266}
j_mayer32407102007-09-26 23:01:49 +00004267#endif
bellard8853f862004-02-22 14:57:26 +00004268
bellard31e31b82003-02-18 22:55:36 +00004269/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004270
Blue Swirl001faf32009-05-13 17:53:17 +00004271#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004272#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4273enum {
4274#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004275STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004276};
4277#undef STRUCT
4278#undef STRUCT_SPECIAL
4279
Blue Swirl001faf32009-05-13 17:53:17 +00004280#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004281#define STRUCT_SPECIAL(name)
4282#include "syscall_types.h"
4283#undef STRUCT
4284#undef STRUCT_SPECIAL
4285
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004286typedef struct IOCTLEntry IOCTLEntry;
4287
4288typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004289 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004290
4291struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004292 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004293 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004294 const char *name;
4295 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004296 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004297 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004298};
bellard31e31b82003-02-18 22:55:36 +00004299
4300#define IOC_R 0x0001
4301#define IOC_W 0x0002
4302#define IOC_RW (IOC_R | IOC_W)
4303
4304#define MAX_STRUCT_SIZE 4096
4305
Peter Maydelldace20d2011-01-10 13:11:24 +00004306#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004307/* So fiemap access checks don't overflow on 32 bit systems.
4308 * This is very slightly smaller than the limit imposed by
4309 * the underlying kernel.
4310 */
4311#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4312 / sizeof(struct fiemap_extent))
4313
4314static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004315 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004316{
4317 /* The parameter for this ioctl is a struct fiemap followed
4318 * by an array of struct fiemap_extent whose size is set
4319 * in fiemap->fm_extent_count. The array is filled in by the
4320 * ioctl.
4321 */
4322 int target_size_in, target_size_out;
4323 struct fiemap *fm;
4324 const argtype *arg_type = ie->arg_type;
4325 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4326 void *argptr, *p;
4327 abi_long ret;
4328 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4329 uint32_t outbufsz;
4330 int free_fm = 0;
4331
4332 assert(arg_type[0] == TYPE_PTR);
4333 assert(ie->access == IOC_RW);
4334 arg_type++;
4335 target_size_in = thunk_type_size(arg_type, 0);
4336 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4337 if (!argptr) {
4338 return -TARGET_EFAULT;
4339 }
4340 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4341 unlock_user(argptr, arg, 0);
4342 fm = (struct fiemap *)buf_temp;
4343 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4344 return -TARGET_EINVAL;
4345 }
4346
4347 outbufsz = sizeof (*fm) +
4348 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4349
4350 if (outbufsz > MAX_STRUCT_SIZE) {
4351 /* We can't fit all the extents into the fixed size buffer.
4352 * Allocate one that is large enough and use it instead.
4353 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304354 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004355 if (!fm) {
4356 return -TARGET_ENOMEM;
4357 }
4358 memcpy(fm, buf_temp, sizeof(struct fiemap));
4359 free_fm = 1;
4360 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004361 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004362 if (!is_error(ret)) {
4363 target_size_out = target_size_in;
4364 /* An extent_count of 0 means we were only counting the extents
4365 * so there are no structs to copy
4366 */
4367 if (fm->fm_extent_count != 0) {
4368 target_size_out += fm->fm_mapped_extents * extent_size;
4369 }
4370 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4371 if (!argptr) {
4372 ret = -TARGET_EFAULT;
4373 } else {
4374 /* Convert the struct fiemap */
4375 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4376 if (fm->fm_extent_count != 0) {
4377 p = argptr + target_size_in;
4378 /* ...and then all the struct fiemap_extents */
4379 for (i = 0; i < fm->fm_mapped_extents; i++) {
4380 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4381 THUNK_TARGET);
4382 p += extent_size;
4383 }
4384 }
4385 unlock_user(argptr, arg, target_size_out);
4386 }
4387 }
4388 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304389 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004390 }
4391 return ret;
4392}
Peter Maydelldace20d2011-01-10 13:11:24 +00004393#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004394
Laurent Vivier059c2f22011-03-30 00:12:12 +02004395static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004396 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004397{
4398 const argtype *arg_type = ie->arg_type;
4399 int target_size;
4400 void *argptr;
4401 int ret;
4402 struct ifconf *host_ifconf;
4403 uint32_t outbufsz;
4404 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4405 int target_ifreq_size;
4406 int nb_ifreq;
4407 int free_buf = 0;
4408 int i;
4409 int target_ifc_len;
4410 abi_long target_ifc_buf;
4411 int host_ifc_len;
4412 char *host_ifc_buf;
4413
4414 assert(arg_type[0] == TYPE_PTR);
4415 assert(ie->access == IOC_RW);
4416
4417 arg_type++;
4418 target_size = thunk_type_size(arg_type, 0);
4419
4420 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4421 if (!argptr)
4422 return -TARGET_EFAULT;
4423 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4424 unlock_user(argptr, arg, 0);
4425
4426 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4427 target_ifc_len = host_ifconf->ifc_len;
4428 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4429
4430 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4431 nb_ifreq = target_ifc_len / target_ifreq_size;
4432 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4433
4434 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4435 if (outbufsz > MAX_STRUCT_SIZE) {
4436 /* We can't fit all the extents into the fixed size buffer.
4437 * Allocate one that is large enough and use it instead.
4438 */
4439 host_ifconf = malloc(outbufsz);
4440 if (!host_ifconf) {
4441 return -TARGET_ENOMEM;
4442 }
4443 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4444 free_buf = 1;
4445 }
4446 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4447
4448 host_ifconf->ifc_len = host_ifc_len;
4449 host_ifconf->ifc_buf = host_ifc_buf;
4450
Peter Maydell49ca6f32016-06-06 19:58:14 +01004451 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004452 if (!is_error(ret)) {
4453 /* convert host ifc_len to target ifc_len */
4454
4455 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4456 target_ifc_len = nb_ifreq * target_ifreq_size;
4457 host_ifconf->ifc_len = target_ifc_len;
4458
4459 /* restore target ifc_buf */
4460
4461 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4462
4463 /* copy struct ifconf to target user */
4464
4465 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4466 if (!argptr)
4467 return -TARGET_EFAULT;
4468 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4469 unlock_user(argptr, arg, target_size);
4470
4471 /* copy ifreq[] to target user */
4472
4473 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4474 for (i = 0; i < nb_ifreq ; i++) {
4475 thunk_convert(argptr + i * target_ifreq_size,
4476 host_ifc_buf + i * sizeof(struct ifreq),
4477 ifreq_arg_type, THUNK_TARGET);
4478 }
4479 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4480 }
4481
4482 if (free_buf) {
4483 free(host_ifconf);
4484 }
4485
4486 return ret;
4487}
4488
Alexander Graf56e904e2012-01-31 18:42:06 +01004489static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004490 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004491{
4492 void *argptr;
4493 struct dm_ioctl *host_dm;
4494 abi_long guest_data;
4495 uint32_t guest_data_size;
4496 int target_size;
4497 const argtype *arg_type = ie->arg_type;
4498 abi_long ret;
4499 void *big_buf = NULL;
4500 char *host_data;
4501
4502 arg_type++;
4503 target_size = thunk_type_size(arg_type, 0);
4504 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4505 if (!argptr) {
4506 ret = -TARGET_EFAULT;
4507 goto out;
4508 }
4509 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4510 unlock_user(argptr, arg, 0);
4511
4512 /* buf_temp is too small, so fetch things into a bigger buffer */
4513 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4514 memcpy(big_buf, buf_temp, target_size);
4515 buf_temp = big_buf;
4516 host_dm = big_buf;
4517
4518 guest_data = arg + host_dm->data_start;
4519 if ((guest_data - arg) < 0) {
4520 ret = -EINVAL;
4521 goto out;
4522 }
4523 guest_data_size = host_dm->data_size - host_dm->data_start;
4524 host_data = (char*)host_dm + host_dm->data_start;
4525
4526 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4527 switch (ie->host_cmd) {
4528 case DM_REMOVE_ALL:
4529 case DM_LIST_DEVICES:
4530 case DM_DEV_CREATE:
4531 case DM_DEV_REMOVE:
4532 case DM_DEV_SUSPEND:
4533 case DM_DEV_STATUS:
4534 case DM_DEV_WAIT:
4535 case DM_TABLE_STATUS:
4536 case DM_TABLE_CLEAR:
4537 case DM_TABLE_DEPS:
4538 case DM_LIST_VERSIONS:
4539 /* no input data */
4540 break;
4541 case DM_DEV_RENAME:
4542 case DM_DEV_SET_GEOMETRY:
4543 /* data contains only strings */
4544 memcpy(host_data, argptr, guest_data_size);
4545 break;
4546 case DM_TARGET_MSG:
4547 memcpy(host_data, argptr, guest_data_size);
4548 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4549 break;
4550 case DM_TABLE_LOAD:
4551 {
4552 void *gspec = argptr;
4553 void *cur_data = host_data;
4554 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4555 int spec_size = thunk_type_size(arg_type, 0);
4556 int i;
4557
4558 for (i = 0; i < host_dm->target_count; i++) {
4559 struct dm_target_spec *spec = cur_data;
4560 uint32_t next;
4561 int slen;
4562
4563 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4564 slen = strlen((char*)gspec + spec_size) + 1;
4565 next = spec->next;
4566 spec->next = sizeof(*spec) + slen;
4567 strcpy((char*)&spec[1], gspec + spec_size);
4568 gspec += next;
4569 cur_data += spec->next;
4570 }
4571 break;
4572 }
4573 default:
4574 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004575 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004576 goto out;
4577 }
4578 unlock_user(argptr, guest_data, 0);
4579
Peter Maydell49ca6f32016-06-06 19:58:14 +01004580 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01004581 if (!is_error(ret)) {
4582 guest_data = arg + host_dm->data_start;
4583 guest_data_size = host_dm->data_size - host_dm->data_start;
4584 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4585 switch (ie->host_cmd) {
4586 case DM_REMOVE_ALL:
4587 case DM_DEV_CREATE:
4588 case DM_DEV_REMOVE:
4589 case DM_DEV_RENAME:
4590 case DM_DEV_SUSPEND:
4591 case DM_DEV_STATUS:
4592 case DM_TABLE_LOAD:
4593 case DM_TABLE_CLEAR:
4594 case DM_TARGET_MSG:
4595 case DM_DEV_SET_GEOMETRY:
4596 /* no return data */
4597 break;
4598 case DM_LIST_DEVICES:
4599 {
4600 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4601 uint32_t remaining_data = guest_data_size;
4602 void *cur_data = argptr;
4603 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4604 int nl_size = 12; /* can't use thunk_size due to alignment */
4605
4606 while (1) {
4607 uint32_t next = nl->next;
4608 if (next) {
4609 nl->next = nl_size + (strlen(nl->name) + 1);
4610 }
4611 if (remaining_data < nl->next) {
4612 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4613 break;
4614 }
4615 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4616 strcpy(cur_data + nl_size, nl->name);
4617 cur_data += nl->next;
4618 remaining_data -= nl->next;
4619 if (!next) {
4620 break;
4621 }
4622 nl = (void*)nl + next;
4623 }
4624 break;
4625 }
4626 case DM_DEV_WAIT:
4627 case DM_TABLE_STATUS:
4628 {
4629 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4630 void *cur_data = argptr;
4631 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4632 int spec_size = thunk_type_size(arg_type, 0);
4633 int i;
4634
4635 for (i = 0; i < host_dm->target_count; i++) {
4636 uint32_t next = spec->next;
4637 int slen = strlen((char*)&spec[1]) + 1;
4638 spec->next = (cur_data - argptr) + spec_size + slen;
4639 if (guest_data_size < spec->next) {
4640 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4641 break;
4642 }
4643 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4644 strcpy(cur_data + spec_size, (char*)&spec[1]);
4645 cur_data = argptr + spec->next;
4646 spec = (void*)host_dm + host_dm->data_start + next;
4647 }
4648 break;
4649 }
4650 case DM_TABLE_DEPS:
4651 {
4652 void *hdata = (void*)host_dm + host_dm->data_start;
4653 int count = *(uint32_t*)hdata;
4654 uint64_t *hdev = hdata + 8;
4655 uint64_t *gdev = argptr + 8;
4656 int i;
4657
4658 *(uint32_t*)argptr = tswap32(count);
4659 for (i = 0; i < count; i++) {
4660 *gdev = tswap64(*hdev);
4661 gdev++;
4662 hdev++;
4663 }
4664 break;
4665 }
4666 case DM_LIST_VERSIONS:
4667 {
4668 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4669 uint32_t remaining_data = guest_data_size;
4670 void *cur_data = argptr;
4671 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4672 int vers_size = thunk_type_size(arg_type, 0);
4673
4674 while (1) {
4675 uint32_t next = vers->next;
4676 if (next) {
4677 vers->next = vers_size + (strlen(vers->name) + 1);
4678 }
4679 if (remaining_data < vers->next) {
4680 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4681 break;
4682 }
4683 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4684 strcpy(cur_data + vers_size, vers->name);
4685 cur_data += vers->next;
4686 remaining_data -= vers->next;
4687 if (!next) {
4688 break;
4689 }
4690 vers = (void*)vers + next;
4691 }
4692 break;
4693 }
4694 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004695 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004696 ret = -TARGET_EINVAL;
4697 goto out;
4698 }
4699 unlock_user(argptr, guest_data, guest_data_size);
4700
4701 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4702 if (!argptr) {
4703 ret = -TARGET_EFAULT;
4704 goto out;
4705 }
4706 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4707 unlock_user(argptr, arg, target_size);
4708 }
4709out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004710 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004711 return ret;
4712}
4713
Alexander Grafa59b5e32014-08-22 13:15:50 +02004714static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004715 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004716{
4717 void *argptr;
4718 int target_size;
4719 const argtype *arg_type = ie->arg_type;
4720 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4721 abi_long ret;
4722
4723 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4724 struct blkpg_partition host_part;
4725
4726 /* Read and convert blkpg */
4727 arg_type++;
4728 target_size = thunk_type_size(arg_type, 0);
4729 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4730 if (!argptr) {
4731 ret = -TARGET_EFAULT;
4732 goto out;
4733 }
4734 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4735 unlock_user(argptr, arg, 0);
4736
4737 switch (host_blkpg->op) {
4738 case BLKPG_ADD_PARTITION:
4739 case BLKPG_DEL_PARTITION:
4740 /* payload is struct blkpg_partition */
4741 break;
4742 default:
4743 /* Unknown opcode */
4744 ret = -TARGET_EINVAL;
4745 goto out;
4746 }
4747
4748 /* Read and convert blkpg->data */
4749 arg = (abi_long)(uintptr_t)host_blkpg->data;
4750 target_size = thunk_type_size(part_arg_type, 0);
4751 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4752 if (!argptr) {
4753 ret = -TARGET_EFAULT;
4754 goto out;
4755 }
4756 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4757 unlock_user(argptr, arg, 0);
4758
4759 /* Swizzle the data pointer to our local copy and call! */
4760 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01004761 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02004762
4763out:
4764 return ret;
4765}
4766
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004767static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004768 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004769{
4770 const argtype *arg_type = ie->arg_type;
4771 const StructEntry *se;
4772 const argtype *field_types;
4773 const int *dst_offsets, *src_offsets;
4774 int target_size;
4775 void *argptr;
4776 abi_ulong *target_rt_dev_ptr;
4777 unsigned long *host_rt_dev_ptr;
4778 abi_long ret;
4779 int i;
4780
4781 assert(ie->access == IOC_W);
4782 assert(*arg_type == TYPE_PTR);
4783 arg_type++;
4784 assert(*arg_type == TYPE_STRUCT);
4785 target_size = thunk_type_size(arg_type, 0);
4786 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4787 if (!argptr) {
4788 return -TARGET_EFAULT;
4789 }
4790 arg_type++;
4791 assert(*arg_type == (int)STRUCT_rtentry);
4792 se = struct_entries + *arg_type++;
4793 assert(se->convert[0] == NULL);
4794 /* convert struct here to be able to catch rt_dev string */
4795 field_types = se->field_types;
4796 dst_offsets = se->field_offsets[THUNK_HOST];
4797 src_offsets = se->field_offsets[THUNK_TARGET];
4798 for (i = 0; i < se->nb_fields; i++) {
4799 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4800 assert(*field_types == TYPE_PTRVOID);
4801 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4802 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4803 if (*target_rt_dev_ptr != 0) {
4804 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4805 tswapal(*target_rt_dev_ptr));
4806 if (!*host_rt_dev_ptr) {
4807 unlock_user(argptr, arg, 0);
4808 return -TARGET_EFAULT;
4809 }
4810 } else {
4811 *host_rt_dev_ptr = 0;
4812 }
4813 field_types++;
4814 continue;
4815 }
4816 field_types = thunk_convert(buf_temp + dst_offsets[i],
4817 argptr + src_offsets[i],
4818 field_types, THUNK_HOST);
4819 }
4820 unlock_user(argptr, arg, 0);
4821
Peter Maydell49ca6f32016-06-06 19:58:14 +01004822 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004823 if (*host_rt_dev_ptr != 0) {
4824 unlock_user((void *)*host_rt_dev_ptr,
4825 *target_rt_dev_ptr, 0);
4826 }
4827 return ret;
4828}
4829
Paul Burtonca56f5b2014-06-22 11:25:47 +01004830static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004831 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004832{
4833 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004834 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01004835}
4836
blueswir19f106a72008-10-05 10:52:52 +00004837static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004838#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004839 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4840#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4841 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004842#include "ioctls.h"
4843 { 0, 0, },
4844};
4845
pbrook53a59602006-03-25 19:31:22 +00004846/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004847/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004848static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004849{
4850 const IOCTLEntry *ie;
4851 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004852 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004853 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004854 int target_size;
4855 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004856
4857 ie = ioctl_entries;
4858 for(;;) {
4859 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004860 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004861 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004862 }
4863 if (ie->target_cmd == cmd)
4864 break;
4865 ie++;
4866 }
4867 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004868#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004869 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004870#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004871 if (ie->do_ioctl) {
4872 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4873 }
4874
bellard31e31b82003-02-18 22:55:36 +00004875 switch(arg_type[0]) {
4876 case TYPE_NULL:
4877 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01004878 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00004879 break;
4880 case TYPE_PTRVOID:
4881 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004882 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00004883 break;
4884 case TYPE_PTR:
4885 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004886 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004887 switch(ie->access) {
4888 case IOC_R:
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 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004899 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4900 if (!argptr)
4901 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004902 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4903 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004904 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004905 break;
4906 default:
4907 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004908 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4909 if (!argptr)
4910 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004911 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4912 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004913 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004914 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004915 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4916 if (!argptr)
4917 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004918 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4919 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004920 }
4921 break;
4922 }
4923 break;
4924 default:
j_mayer32407102007-09-26 23:01:49 +00004925 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4926 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004927 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004928 break;
4929 }
4930 return ret;
4931}
4932
blueswir1b39bc502008-10-05 10:51:10 +00004933static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004934 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4935 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4936 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4937 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4938 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4939 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4940 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4941 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4942 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4943 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4944 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4945 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4946 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4947 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4948 { 0, 0, 0, 0 }
4949};
4950
blueswir1b39bc502008-10-05 10:51:10 +00004951static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004952 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4953 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4954 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4955 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4956 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4957 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4958 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4959 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4960 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4961 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4962 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4963 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4964 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4965 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4966 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4967 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4968 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4969 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4970 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4971 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4972 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4973 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4974 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4975 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4976 { 0, 0, 0, 0 }
4977};
4978
blueswir1b39bc502008-10-05 10:51:10 +00004979static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004980 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4981 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4982 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4983 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4984 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4985 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4986 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4987 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4988 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4989 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4990 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4991 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4992 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4993 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4994 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4995 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4996 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4997 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4998 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4999 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5000 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5001 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5002 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5003 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5004 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5005 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5006 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5007 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5008 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5009 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5010 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5011 { 0, 0, 0, 0 }
5012};
5013
blueswir1b39bc502008-10-05 10:51:10 +00005014static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005015 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5016 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5017 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5018 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5019 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5020 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5021 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5022 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5023 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5024 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5025 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5026 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5027 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5028 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5029 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5030 { 0, 0, 0, 0 }
5031};
5032
5033static void target_to_host_termios (void *dst, const void *src)
5034{
5035 struct host_termios *host = dst;
5036 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005037
ths5fafdf22007-09-16 21:08:06 +00005038 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005039 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005040 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005041 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005042 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005043 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005044 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005045 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5046 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005047
Arnaud Patard44607122009-04-21 17:39:08 +03005048 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005049 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5050 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005051 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005052 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005053 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005054 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005055 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005056 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005057 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005058 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5059 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005060 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5061 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5062 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5063 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5064 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005065 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005066}
ths3b46e622007-09-17 08:09:54 +00005067
bellard31e31b82003-02-18 22:55:36 +00005068static void host_to_target_termios (void *dst, const void *src)
5069{
5070 struct target_termios *target = dst;
5071 const struct host_termios *host = src;
5072
ths5fafdf22007-09-16 21:08:06 +00005073 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005074 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005075 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005076 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005077 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005078 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005079 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005080 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5081 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005082
Arnaud Patard44607122009-04-21 17:39:08 +03005083 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005084 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5085 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5086 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5087 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5088 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5089 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5090 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5091 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5092 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5093 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5094 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5095 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5096 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5097 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5098 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5099 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5100 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5101}
5102
blueswir18e853dc2008-10-05 10:49:32 +00005103static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005104 .convert = { host_to_target_termios, target_to_host_termios },
5105 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5106 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5107};
5108
bellard5286db72003-06-05 00:57:30 +00005109static bitmask_transtbl mmap_flags_tbl[] = {
5110 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5111 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5112 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5113 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5114 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5115 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5116 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5117 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005118 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5119 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005120 { 0, 0, 0, 0 }
5121};
5122
bellard2ab83ea2003-06-15 19:56:46 +00005123#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005124
5125/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005126static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005127
bellard03acab62007-11-11 14:57:14 +00005128static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005129{
5130 int size;
pbrook53a59602006-03-25 19:31:22 +00005131 void *p;
bellard6dbad632003-03-16 18:05:05 +00005132
5133 if (!ldt_table)
5134 return 0;
5135 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5136 if (size > bytecount)
5137 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005138 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5139 if (!p)
bellard03acab62007-11-11 14:57:14 +00005140 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005141 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005142 memcpy(p, ldt_table, size);
5143 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005144 return size;
5145}
5146
5147/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005148static abi_long write_ldt(CPUX86State *env,
5149 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005150{
5151 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005152 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005153 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005154 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005155 uint32_t *lp, entry_1, entry_2;
5156
5157 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005158 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005159 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005160 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005161 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005162 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005163 ldt_info.limit = tswap32(target_ldt_info->limit);
5164 ldt_info.flags = tswap32(target_ldt_info->flags);
5165 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005166
bellard6dbad632003-03-16 18:05:05 +00005167 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005168 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005169 seg_32bit = ldt_info.flags & 1;
5170 contents = (ldt_info.flags >> 1) & 3;
5171 read_exec_only = (ldt_info.flags >> 3) & 1;
5172 limit_in_pages = (ldt_info.flags >> 4) & 1;
5173 seg_not_present = (ldt_info.flags >> 5) & 1;
5174 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005175#ifdef TARGET_ABI32
5176 lm = 0;
5177#else
5178 lm = (ldt_info.flags >> 7) & 1;
5179#endif
bellard6dbad632003-03-16 18:05:05 +00005180 if (contents == 3) {
5181 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005182 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005183 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005184 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005185 }
5186 /* allocate the LDT */
5187 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005188 env->ldt.base = target_mmap(0,
5189 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5190 PROT_READ|PROT_WRITE,
5191 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5192 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005193 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005194 memset(g2h(env->ldt.base), 0,
5195 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005196 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005197 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005198 }
5199
5200 /* NOTE: same code as Linux kernel */
5201 /* Allow LDTs to be cleared by the user. */
5202 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5203 if (oldmode ||
5204 (contents == 0 &&
5205 read_exec_only == 1 &&
5206 seg_32bit == 0 &&
5207 limit_in_pages == 0 &&
5208 seg_not_present == 1 &&
5209 useable == 0 )) {
5210 entry_1 = 0;
5211 entry_2 = 0;
5212 goto install;
5213 }
5214 }
ths3b46e622007-09-17 08:09:54 +00005215
bellard6dbad632003-03-16 18:05:05 +00005216 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5217 (ldt_info.limit & 0x0ffff);
5218 entry_2 = (ldt_info.base_addr & 0xff000000) |
5219 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5220 (ldt_info.limit & 0xf0000) |
5221 ((read_exec_only ^ 1) << 9) |
5222 (contents << 10) |
5223 ((seg_not_present ^ 1) << 15) |
5224 (seg_32bit << 22) |
5225 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005226 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005227 0x7000;
5228 if (!oldmode)
5229 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005230
bellard6dbad632003-03-16 18:05:05 +00005231 /* Install the new entry ... */
5232install:
5233 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5234 lp[0] = tswap32(entry_1);
5235 lp[1] = tswap32(entry_2);
5236 return 0;
5237}
5238
5239/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005240static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5241 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005242{
bellard03acab62007-11-11 14:57:14 +00005243 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005244
bellard6dbad632003-03-16 18:05:05 +00005245 switch (func) {
5246 case 0:
5247 ret = read_ldt(ptr, bytecount);
5248 break;
5249 case 1:
5250 ret = write_ldt(env, ptr, bytecount, 1);
5251 break;
5252 case 0x11:
5253 ret = write_ldt(env, ptr, bytecount, 0);
5254 break;
bellard03acab62007-11-11 14:57:14 +00005255 default:
5256 ret = -TARGET_ENOSYS;
5257 break;
bellard6dbad632003-03-16 18:05:05 +00005258 }
5259 return ret;
5260}
bellard1b6b0292003-03-22 17:31:38 +00005261
blueswir14583f582008-08-24 10:35:55 +00005262#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005263abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005264{
5265 uint64_t *gdt_table = g2h(env->gdt.base);
5266 struct target_modify_ldt_ldt_s ldt_info;
5267 struct target_modify_ldt_ldt_s *target_ldt_info;
5268 int seg_32bit, contents, read_exec_only, limit_in_pages;
5269 int seg_not_present, useable, lm;
5270 uint32_t *lp, entry_1, entry_2;
5271 int i;
5272
5273 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5274 if (!target_ldt_info)
5275 return -TARGET_EFAULT;
5276 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005277 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005278 ldt_info.limit = tswap32(target_ldt_info->limit);
5279 ldt_info.flags = tswap32(target_ldt_info->flags);
5280 if (ldt_info.entry_number == -1) {
5281 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5282 if (gdt_table[i] == 0) {
5283 ldt_info.entry_number = i;
5284 target_ldt_info->entry_number = tswap32(i);
5285 break;
5286 }
5287 }
5288 }
5289 unlock_user_struct(target_ldt_info, ptr, 1);
5290
5291 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5292 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5293 return -TARGET_EINVAL;
5294 seg_32bit = ldt_info.flags & 1;
5295 contents = (ldt_info.flags >> 1) & 3;
5296 read_exec_only = (ldt_info.flags >> 3) & 1;
5297 limit_in_pages = (ldt_info.flags >> 4) & 1;
5298 seg_not_present = (ldt_info.flags >> 5) & 1;
5299 useable = (ldt_info.flags >> 6) & 1;
5300#ifdef TARGET_ABI32
5301 lm = 0;
5302#else
5303 lm = (ldt_info.flags >> 7) & 1;
5304#endif
5305
5306 if (contents == 3) {
5307 if (seg_not_present == 0)
5308 return -TARGET_EINVAL;
5309 }
5310
5311 /* NOTE: same code as Linux kernel */
5312 /* Allow LDTs to be cleared by the user. */
5313 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5314 if ((contents == 0 &&
5315 read_exec_only == 1 &&
5316 seg_32bit == 0 &&
5317 limit_in_pages == 0 &&
5318 seg_not_present == 1 &&
5319 useable == 0 )) {
5320 entry_1 = 0;
5321 entry_2 = 0;
5322 goto install;
5323 }
5324 }
5325
5326 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5327 (ldt_info.limit & 0x0ffff);
5328 entry_2 = (ldt_info.base_addr & 0xff000000) |
5329 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5330 (ldt_info.limit & 0xf0000) |
5331 ((read_exec_only ^ 1) << 9) |
5332 (contents << 10) |
5333 ((seg_not_present ^ 1) << 15) |
5334 (seg_32bit << 22) |
5335 (limit_in_pages << 23) |
5336 (useable << 20) |
5337 (lm << 21) |
5338 0x7000;
5339
5340 /* Install the new entry ... */
5341install:
5342 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5343 lp[0] = tswap32(entry_1);
5344 lp[1] = tswap32(entry_2);
5345 return 0;
5346}
5347
blueswir18fcd3692008-08-17 20:26:25 +00005348static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005349{
5350 struct target_modify_ldt_ldt_s *target_ldt_info;
5351 uint64_t *gdt_table = g2h(env->gdt.base);
5352 uint32_t base_addr, limit, flags;
5353 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5354 int seg_not_present, useable, lm;
5355 uint32_t *lp, entry_1, entry_2;
5356
5357 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5358 if (!target_ldt_info)
5359 return -TARGET_EFAULT;
5360 idx = tswap32(target_ldt_info->entry_number);
5361 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5362 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5363 unlock_user_struct(target_ldt_info, ptr, 1);
5364 return -TARGET_EINVAL;
5365 }
5366 lp = (uint32_t *)(gdt_table + idx);
5367 entry_1 = tswap32(lp[0]);
5368 entry_2 = tswap32(lp[1]);
5369
5370 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5371 contents = (entry_2 >> 10) & 3;
5372 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5373 seg_32bit = (entry_2 >> 22) & 1;
5374 limit_in_pages = (entry_2 >> 23) & 1;
5375 useable = (entry_2 >> 20) & 1;
5376#ifdef TARGET_ABI32
5377 lm = 0;
5378#else
5379 lm = (entry_2 >> 21) & 1;
5380#endif
5381 flags = (seg_32bit << 0) | (contents << 1) |
5382 (read_exec_only << 3) | (limit_in_pages << 4) |
5383 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5384 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5385 base_addr = (entry_1 >> 16) |
5386 (entry_2 & 0xff000000) |
5387 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005388 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005389 target_ldt_info->limit = tswap32(limit);
5390 target_ldt_info->flags = tswap32(flags);
5391 unlock_user_struct(target_ldt_info, ptr, 1);
5392 return 0;
5393}
blueswir14583f582008-08-24 10:35:55 +00005394#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005395
bellardd2fd1af2007-11-14 18:08:56 +00005396#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005397abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005398{
Juan Quintela1add8692011-06-16 17:37:09 +01005399 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005400 abi_ulong val;
5401 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005402
bellardd2fd1af2007-11-14 18:08:56 +00005403 switch(code) {
5404 case TARGET_ARCH_SET_GS:
5405 case TARGET_ARCH_SET_FS:
5406 if (code == TARGET_ARCH_SET_GS)
5407 idx = R_GS;
5408 else
5409 idx = R_FS;
5410 cpu_x86_load_seg(env, idx, 0);
5411 env->segs[idx].base = addr;
5412 break;
5413 case TARGET_ARCH_GET_GS:
5414 case TARGET_ARCH_GET_FS:
5415 if (code == TARGET_ARCH_GET_GS)
5416 idx = R_GS;
5417 else
5418 idx = R_FS;
5419 val = env->segs[idx].base;
5420 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005421 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005422 break;
5423 default:
5424 ret = -TARGET_EINVAL;
5425 break;
5426 }
Juan Quintela1add8692011-06-16 17:37:09 +01005427 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005428}
5429#endif
5430
bellard2ab83ea2003-06-15 19:56:46 +00005431#endif /* defined(TARGET_I386) */
5432
Riku Voipio05098a92011-03-04 15:27:29 +02005433#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005434
pbrookd865bab2008-06-07 22:12:17 +00005435
5436static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5437typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005438 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005439 pthread_mutex_t mutex;
5440 pthread_cond_t cond;
5441 pthread_t thread;
5442 uint32_t tid;
5443 abi_ulong child_tidptr;
5444 abi_ulong parent_tidptr;
5445 sigset_t sigmask;
5446} new_thread_info;
5447
5448static void *clone_func(void *arg)
5449{
5450 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005451 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005452 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005453 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005454
Emilio G. Cota70903762015-08-23 20:23:41 -04005455 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005456 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005457 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005458 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005459 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005460 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005461 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005462 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005463 if (info->child_tidptr)
5464 put_user_u32(info->tid, info->child_tidptr);
5465 if (info->parent_tidptr)
5466 put_user_u32(info->tid, info->parent_tidptr);
5467 /* Enable signals. */
5468 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5469 /* Signal to the parent that we're ready. */
5470 pthread_mutex_lock(&info->mutex);
5471 pthread_cond_broadcast(&info->cond);
5472 pthread_mutex_unlock(&info->mutex);
5473 /* Wait until the parent has finshed initializing the tls state. */
5474 pthread_mutex_lock(&clone_lock);
5475 pthread_mutex_unlock(&clone_lock);
5476 cpu_loop(env);
5477 /* never exits */
5478 return NULL;
5479}
bellard1b6b0292003-03-22 17:31:38 +00005480
ths0da46a62007-10-20 20:23:07 +00005481/* do_fork() Must return host values and target errnos (unlike most
5482 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005483static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005484 abi_ulong parent_tidptr, target_ulong newtls,
5485 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005486{
Andreas Färber0429a972013-08-26 18:14:44 +02005487 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005488 int ret;
bellard5cd43932003-03-29 16:54:36 +00005489 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005490 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005491 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005492 unsigned int nptl_flags;
5493 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005494
balrog436d1242008-09-21 02:39:45 +00005495 /* Emulate vfork() with fork() */
5496 if (flags & CLONE_VFORK)
5497 flags &= ~(CLONE_VFORK | CLONE_VM);
5498
bellard1b6b0292003-03-22 17:31:38 +00005499 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005500 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005501 new_thread_info info;
5502 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005503
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005504 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005505 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005506 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005507 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005508 /* Init regs that differ from the parent. */
5509 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005510 new_cpu = ENV_GET_CPU(new_env);
5511 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005512 ts->bprm = parent_ts->bprm;
5513 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005514 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005515 nptl_flags = flags;
5516 flags &= ~CLONE_NPTL_FLAGS2;
5517
pbrookc2764712009-03-07 15:24:59 +00005518 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5519 ts->child_tidptr = child_tidptr;
5520 }
5521
pbrookd865bab2008-06-07 22:12:17 +00005522 if (nptl_flags & CLONE_SETTLS)
5523 cpu_set_tls (new_env, newtls);
5524
5525 /* Grab a mutex so that thread setup appears atomic. */
5526 pthread_mutex_lock(&clone_lock);
5527
5528 memset(&info, 0, sizeof(info));
5529 pthread_mutex_init(&info.mutex, NULL);
5530 pthread_mutex_lock(&info.mutex);
5531 pthread_cond_init(&info.cond, NULL);
5532 info.env = new_env;
5533 if (nptl_flags & CLONE_CHILD_SETTID)
5534 info.child_tidptr = child_tidptr;
5535 if (nptl_flags & CLONE_PARENT_SETTID)
5536 info.parent_tidptr = parent_tidptr;
5537
5538 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005539 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5540 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005541 /* It is not safe to deliver signals until the child has finished
5542 initializing, so temporarily block all signals. */
5543 sigfillset(&sigmask);
5544 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5545
5546 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005547 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005548
5549 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5550 pthread_attr_destroy(&attr);
5551 if (ret == 0) {
5552 /* Wait for the child to initialize. */
5553 pthread_cond_wait(&info.cond, &info.mutex);
5554 ret = info.tid;
5555 if (flags & CLONE_PARENT_SETTID)
5556 put_user_u32(ret, parent_tidptr);
5557 } else {
5558 ret = -1;
5559 }
5560 pthread_mutex_unlock(&info.mutex);
5561 pthread_cond_destroy(&info.cond);
5562 pthread_mutex_destroy(&info.mutex);
5563 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005564 } else {
5565 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005566 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5567 return -TARGET_EINVAL;
5568 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005569
5570 if (block_signals()) {
5571 return -TARGET_ERESTARTSYS;
5572 }
5573
pbrookd865bab2008-06-07 22:12:17 +00005574 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005575 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005576 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005577 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005578 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005579 cpu_clone_regs(env, newsp);
5580 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005581 /* There is a race condition here. The parent process could
5582 theoretically read the TID in the child process before the child
5583 tid is set. This would require using either ptrace
5584 (not implemented) or having *_tidptr to point at a shared memory
5585 mapping. We can't repeat the spinlock hack used above because
5586 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005587 if (flags & CLONE_CHILD_SETTID)
5588 put_user_u32(gettid(), child_tidptr);
5589 if (flags & CLONE_PARENT_SETTID)
5590 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005591 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005592 if (flags & CLONE_SETTLS)
5593 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005594 if (flags & CLONE_CHILD_CLEARTID)
5595 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005596 } else {
5597 fork_end(0);
5598 }
bellard1b6b0292003-03-22 17:31:38 +00005599 }
5600 return ret;
5601}
5602
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005603/* warning : doesn't handle linux specific flags... */
5604static int target_to_host_fcntl_cmd(int cmd)
5605{
5606 switch(cmd) {
5607 case TARGET_F_DUPFD:
5608 case TARGET_F_GETFD:
5609 case TARGET_F_SETFD:
5610 case TARGET_F_GETFL:
5611 case TARGET_F_SETFL:
5612 return cmd;
5613 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005614 return F_GETLK64;
5615 case TARGET_F_SETLK:
5616 return F_SETLK64;
5617 case TARGET_F_SETLKW:
5618 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005619 case TARGET_F_GETOWN:
5620 return F_GETOWN;
5621 case TARGET_F_SETOWN:
5622 return F_SETOWN;
5623 case TARGET_F_GETSIG:
5624 return F_GETSIG;
5625 case TARGET_F_SETSIG:
5626 return F_SETSIG;
5627#if TARGET_ABI_BITS == 32
5628 case TARGET_F_GETLK64:
5629 return F_GETLK64;
5630 case TARGET_F_SETLK64:
5631 return F_SETLK64;
5632 case TARGET_F_SETLKW64:
5633 return F_SETLKW64;
5634#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005635 case TARGET_F_SETLEASE:
5636 return F_SETLEASE;
5637 case TARGET_F_GETLEASE:
5638 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005639#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005640 case TARGET_F_DUPFD_CLOEXEC:
5641 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005642#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005643 case TARGET_F_NOTIFY:
5644 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005645#ifdef F_GETOWN_EX
5646 case TARGET_F_GETOWN_EX:
5647 return F_GETOWN_EX;
5648#endif
5649#ifdef F_SETOWN_EX
5650 case TARGET_F_SETOWN_EX:
5651 return F_SETOWN_EX;
5652#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01005653#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005654 case TARGET_F_SETPIPE_SZ:
5655 return F_SETPIPE_SZ;
5656 case TARGET_F_GETPIPE_SZ:
5657 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01005658#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005659 default:
5660 return -TARGET_EINVAL;
5661 }
5662 return -TARGET_EINVAL;
5663}
5664
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005665#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5666static const bitmask_transtbl flock_tbl[] = {
5667 TRANSTBL_CONVERT(F_RDLCK),
5668 TRANSTBL_CONVERT(F_WRLCK),
5669 TRANSTBL_CONVERT(F_UNLCK),
5670 TRANSTBL_CONVERT(F_EXLCK),
5671 TRANSTBL_CONVERT(F_SHLCK),
5672 { 0, 0, 0, 0 }
5673};
5674
Peter Maydell213d3e92016-06-13 11:22:05 +01005675static inline abi_long copy_from_user_flock(struct flock64 *fl,
5676 abi_ulong target_flock_addr)
5677{
5678 struct target_flock *target_fl;
5679 short l_type;
5680
5681 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5682 return -TARGET_EFAULT;
5683 }
5684
5685 __get_user(l_type, &target_fl->l_type);
5686 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5687 __get_user(fl->l_whence, &target_fl->l_whence);
5688 __get_user(fl->l_start, &target_fl->l_start);
5689 __get_user(fl->l_len, &target_fl->l_len);
5690 __get_user(fl->l_pid, &target_fl->l_pid);
5691 unlock_user_struct(target_fl, target_flock_addr, 0);
5692 return 0;
5693}
5694
5695static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
5696 const struct flock64 *fl)
5697{
5698 struct target_flock *target_fl;
5699 short l_type;
5700
5701 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5702 return -TARGET_EFAULT;
5703 }
5704
5705 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5706 __put_user(l_type, &target_fl->l_type);
5707 __put_user(fl->l_whence, &target_fl->l_whence);
5708 __put_user(fl->l_start, &target_fl->l_start);
5709 __put_user(fl->l_len, &target_fl->l_len);
5710 __put_user(fl->l_pid, &target_fl->l_pid);
5711 unlock_user_struct(target_fl, target_flock_addr, 1);
5712 return 0;
5713}
5714
5715typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
5716typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
5717
5718#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
5719static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
5720 abi_ulong target_flock_addr)
5721{
5722 struct target_eabi_flock64 *target_fl;
5723 short l_type;
5724
5725 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5726 return -TARGET_EFAULT;
5727 }
5728
5729 __get_user(l_type, &target_fl->l_type);
5730 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5731 __get_user(fl->l_whence, &target_fl->l_whence);
5732 __get_user(fl->l_start, &target_fl->l_start);
5733 __get_user(fl->l_len, &target_fl->l_len);
5734 __get_user(fl->l_pid, &target_fl->l_pid);
5735 unlock_user_struct(target_fl, target_flock_addr, 0);
5736 return 0;
5737}
5738
5739static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
5740 const struct flock64 *fl)
5741{
5742 struct target_eabi_flock64 *target_fl;
5743 short l_type;
5744
5745 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5746 return -TARGET_EFAULT;
5747 }
5748
5749 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5750 __put_user(l_type, &target_fl->l_type);
5751 __put_user(fl->l_whence, &target_fl->l_whence);
5752 __put_user(fl->l_start, &target_fl->l_start);
5753 __put_user(fl->l_len, &target_fl->l_len);
5754 __put_user(fl->l_pid, &target_fl->l_pid);
5755 unlock_user_struct(target_fl, target_flock_addr, 1);
5756 return 0;
5757}
5758#endif
5759
5760static inline abi_long copy_from_user_flock64(struct flock64 *fl,
5761 abi_ulong target_flock_addr)
5762{
5763 struct target_flock64 *target_fl;
5764 short l_type;
5765
5766 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5767 return -TARGET_EFAULT;
5768 }
5769
5770 __get_user(l_type, &target_fl->l_type);
5771 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
5772 __get_user(fl->l_whence, &target_fl->l_whence);
5773 __get_user(fl->l_start, &target_fl->l_start);
5774 __get_user(fl->l_len, &target_fl->l_len);
5775 __get_user(fl->l_pid, &target_fl->l_pid);
5776 unlock_user_struct(target_fl, target_flock_addr, 0);
5777 return 0;
5778}
5779
5780static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
5781 const struct flock64 *fl)
5782{
5783 struct target_flock64 *target_fl;
5784 short l_type;
5785
5786 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5787 return -TARGET_EFAULT;
5788 }
5789
5790 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
5791 __put_user(l_type, &target_fl->l_type);
5792 __put_user(fl->l_whence, &target_fl->l_whence);
5793 __put_user(fl->l_start, &target_fl->l_start);
5794 __put_user(fl->l_len, &target_fl->l_len);
5795 __put_user(fl->l_pid, &target_fl->l_pid);
5796 unlock_user_struct(target_fl, target_flock_addr, 1);
5797 return 0;
5798}
5799
blueswir1992f48a2007-10-14 16:27:31 +00005800static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005801{
ths43f238d2007-01-05 20:55:49 +00005802 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005803#ifdef F_GETOWN_EX
5804 struct f_owner_ex fox;
5805 struct target_f_owner_ex *target_fox;
5806#endif
blueswir1992f48a2007-10-14 16:27:31 +00005807 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005808 int host_cmd = target_to_host_fcntl_cmd(cmd);
5809
5810 if (host_cmd == -TARGET_EINVAL)
5811 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005812
bellard7775e9e2003-05-14 22:46:48 +00005813 switch(cmd) {
5814 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005815 ret = copy_from_user_flock(&fl64, arg);
5816 if (ret) {
5817 return ret;
5818 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005819 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005820 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005821 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00005822 }
5823 break;
ths3b46e622007-09-17 08:09:54 +00005824
bellard7775e9e2003-05-14 22:46:48 +00005825 case TARGET_F_SETLK:
5826 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01005827 ret = copy_from_user_flock(&fl64, arg);
5828 if (ret) {
5829 return ret;
5830 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005831 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005832 break;
ths3b46e622007-09-17 08:09:54 +00005833
bellard7775e9e2003-05-14 22:46:48 +00005834 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005835 ret = copy_from_user_flock64(&fl64, arg);
5836 if (ret) {
5837 return ret;
5838 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005839 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005840 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005841 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00005842 }
bellard9ee1fa22007-11-11 15:11:19 +00005843 break;
bellard7775e9e2003-05-14 22:46:48 +00005844 case TARGET_F_SETLK64:
5845 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005846 ret = copy_from_user_flock64(&fl64, arg);
5847 if (ret) {
5848 return ret;
5849 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005850 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005851 break;
5852
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005853 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005854 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005855 if (ret >= 0) {
5856 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5857 }
bellardffa65c32004-01-04 23:57:22 +00005858 break;
5859
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005860 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005861 ret = get_errno(safe_fcntl(fd, host_cmd,
5862 target_to_host_bitmask(arg,
5863 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005864 break;
5865
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005866#ifdef F_GETOWN_EX
5867 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01005868 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005869 if (ret >= 0) {
5870 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5871 return -TARGET_EFAULT;
5872 target_fox->type = tswap32(fox.type);
5873 target_fox->pid = tswap32(fox.pid);
5874 unlock_user_struct(target_fox, arg, 1);
5875 }
5876 break;
5877#endif
5878
5879#ifdef F_SETOWN_EX
5880 case TARGET_F_SETOWN_EX:
5881 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5882 return -TARGET_EFAULT;
5883 fox.type = tswap32(target_fox->type);
5884 fox.pid = tswap32(target_fox->pid);
5885 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01005886 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005887 break;
5888#endif
5889
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005890 case TARGET_F_SETOWN:
5891 case TARGET_F_GETOWN:
5892 case TARGET_F_SETSIG:
5893 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005894 case TARGET_F_SETLEASE:
5895 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01005896 case TARGET_F_SETPIPE_SZ:
5897 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01005898 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005899 break;
5900
bellard7775e9e2003-05-14 22:46:48 +00005901 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01005902 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005903 break;
5904 }
5905 return ret;
5906}
5907
bellard67867302003-11-23 17:05:30 +00005908#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005909
bellard67867302003-11-23 17:05:30 +00005910static inline int high2lowuid(int uid)
5911{
5912 if (uid > 65535)
5913 return 65534;
5914 else
5915 return uid;
5916}
5917
5918static inline int high2lowgid(int gid)
5919{
5920 if (gid > 65535)
5921 return 65534;
5922 else
5923 return gid;
5924}
5925
5926static inline int low2highuid(int uid)
5927{
5928 if ((int16_t)uid == -1)
5929 return -1;
5930 else
5931 return uid;
5932}
5933
5934static inline int low2highgid(int gid)
5935{
5936 if ((int16_t)gid == -1)
5937 return -1;
5938 else
5939 return gid;
5940}
Riku Voipio0c866a72011-04-18 15:23:06 +03005941static inline int tswapid(int id)
5942{
5943 return tswap16(id);
5944}
Peter Maydell76ca3102014-03-02 19:36:41 +00005945
5946#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5947
Riku Voipio0c866a72011-04-18 15:23:06 +03005948#else /* !USE_UID16 */
5949static inline int high2lowuid(int uid)
5950{
5951 return uid;
5952}
5953static inline int high2lowgid(int gid)
5954{
5955 return gid;
5956}
5957static inline int low2highuid(int uid)
5958{
5959 return uid;
5960}
5961static inline int low2highgid(int gid)
5962{
5963 return gid;
5964}
5965static inline int tswapid(int id)
5966{
5967 return tswap32(id);
5968}
Peter Maydell76ca3102014-03-02 19:36:41 +00005969
5970#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5971
bellard67867302003-11-23 17:05:30 +00005972#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005973
Peter Maydellfd6f7792016-03-01 16:33:02 +00005974/* We must do direct syscalls for setting UID/GID, because we want to
5975 * implement the Linux system call semantics of "change only for this thread",
5976 * not the libc/POSIX semantics of "change for all threads in process".
5977 * (See http://ewontfix.com/17/ for more details.)
5978 * We use the 32-bit version of the syscalls if present; if it is not
5979 * then either the host architecture supports 32-bit UIDs natively with
5980 * the standard syscall, or the 16-bit UID is the best we can do.
5981 */
5982#ifdef __NR_setuid32
5983#define __NR_sys_setuid __NR_setuid32
5984#else
5985#define __NR_sys_setuid __NR_setuid
5986#endif
5987#ifdef __NR_setgid32
5988#define __NR_sys_setgid __NR_setgid32
5989#else
5990#define __NR_sys_setgid __NR_setgid
5991#endif
5992#ifdef __NR_setresuid32
5993#define __NR_sys_setresuid __NR_setresuid32
5994#else
5995#define __NR_sys_setresuid __NR_setresuid
5996#endif
5997#ifdef __NR_setresgid32
5998#define __NR_sys_setresgid __NR_setresgid32
5999#else
6000#define __NR_sys_setresgid __NR_setresgid
6001#endif
6002
6003_syscall1(int, sys_setuid, uid_t, uid)
6004_syscall1(int, sys_setgid, gid_t, gid)
6005_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6006_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6007
bellard31e31b82003-02-18 22:55:36 +00006008void syscall_init(void)
6009{
bellard2ab83ea2003-06-15 19:56:46 +00006010 IOCTLEntry *ie;
6011 const argtype *arg_type;
6012 int size;
thsb92c47c2007-11-01 00:07:38 +00006013 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006014
Alexander Graf8be656b2015-05-06 23:47:32 +02006015 thunk_init(STRUCT_MAX);
6016
Blue Swirl001faf32009-05-13 17:53:17 +00006017#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006018#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006019#include "syscall_types.h"
6020#undef STRUCT
6021#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006022
Peter Maydelldd6e9572012-07-23 08:07:22 +00006023 /* Build target_to_host_errno_table[] table from
6024 * host_to_target_errno_table[]. */
6025 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6026 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6027 }
6028
bellard2ab83ea2003-06-15 19:56:46 +00006029 /* we patch the ioctl size if necessary. We rely on the fact that
6030 no ioctl has all the bits at '1' in the size field */
6031 ie = ioctl_entries;
6032 while (ie->target_cmd != 0) {
6033 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6034 TARGET_IOC_SIZEMASK) {
6035 arg_type = ie->arg_type;
6036 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006037 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006038 ie->target_cmd);
6039 exit(1);
6040 }
6041 arg_type++;
6042 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006043 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006044 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6045 (size << TARGET_IOC_SIZESHIFT);
6046 }
thsb92c47c2007-11-01 00:07:38 +00006047
bellard2ab83ea2003-06-15 19:56:46 +00006048 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006049#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6050 (defined(__x86_64__) && defined(TARGET_X86_64))
6051 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6052 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6053 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006054 }
6055#endif
6056 ie++;
6057 }
bellard31e31b82003-02-18 22:55:36 +00006058}
bellardc573ff62004-01-04 15:51:36 +00006059
blueswir1992f48a2007-10-14 16:27:31 +00006060#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006061static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6062{
thsaf325d32008-06-10 15:29:15 +00006063#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006064 return ((uint64_t)word0 << 32) | word1;
6065#else
6066 return ((uint64_t)word1 << 32) | word0;
6067#endif
6068}
blueswir1992f48a2007-10-14 16:27:31 +00006069#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006070static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6071{
6072 return word0;
6073}
blueswir1992f48a2007-10-14 16:27:31 +00006074#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006075
6076#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006077static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6078 abi_long arg2,
6079 abi_long arg3,
6080 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006081{
Riku Voipio48e515d2011-07-12 15:40:51 +03006082 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006083 arg2 = arg3;
6084 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006085 }
pbrookce4defa2006-02-09 16:49:55 +00006086 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6087}
6088#endif
6089
6090#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006091static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6092 abi_long arg2,
6093 abi_long arg3,
6094 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006095{
Riku Voipio48e515d2011-07-12 15:40:51 +03006096 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006097 arg2 = arg3;
6098 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006099 }
pbrookce4defa2006-02-09 16:49:55 +00006100 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6101}
6102#endif
6103
bellard579a97f2007-11-11 14:26:47 +00006104static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6105 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006106{
6107 struct target_timespec *target_ts;
6108
bellard579a97f2007-11-11 14:26:47 +00006109 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6110 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006111 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6112 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006113 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006114 return 0;
pbrook53a59602006-03-25 19:31:22 +00006115}
6116
bellard579a97f2007-11-11 14:26:47 +00006117static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6118 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006119{
6120 struct target_timespec *target_ts;
6121
bellard579a97f2007-11-11 14:26:47 +00006122 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6123 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006124 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6125 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006126 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006127 return 0;
pbrook53a59602006-03-25 19:31:22 +00006128}
6129
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006130static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6131 abi_ulong target_addr)
6132{
6133 struct target_itimerspec *target_itspec;
6134
6135 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6136 return -TARGET_EFAULT;
6137 }
6138
6139 host_itspec->it_interval.tv_sec =
6140 tswapal(target_itspec->it_interval.tv_sec);
6141 host_itspec->it_interval.tv_nsec =
6142 tswapal(target_itspec->it_interval.tv_nsec);
6143 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6144 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6145
6146 unlock_user_struct(target_itspec, target_addr, 1);
6147 return 0;
6148}
6149
6150static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6151 struct itimerspec *host_its)
6152{
6153 struct target_itimerspec *target_itspec;
6154
6155 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6156 return -TARGET_EFAULT;
6157 }
6158
6159 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6160 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6161
6162 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6163 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6164
6165 unlock_user_struct(target_itspec, target_addr, 0);
6166 return 0;
6167}
6168
Peter Maydellc0659762014-08-09 15:42:32 +01006169static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6170 abi_ulong target_addr)
6171{
6172 struct target_sigevent *target_sevp;
6173
6174 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6175 return -TARGET_EFAULT;
6176 }
6177
6178 /* This union is awkward on 64 bit systems because it has a 32 bit
6179 * integer and a pointer in it; we follow the conversion approach
6180 * used for handling sigval types in signal.c so the guest should get
6181 * the correct value back even if we did a 64 bit byteswap and it's
6182 * using the 32 bit integer.
6183 */
6184 host_sevp->sigev_value.sival_ptr =
6185 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6186 host_sevp->sigev_signo =
6187 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6188 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6189 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6190
6191 unlock_user_struct(target_sevp, target_addr, 1);
6192 return 0;
6193}
6194
Tom Musta6f6a4032014-08-12 13:53:42 -05006195#if defined(TARGET_NR_mlockall)
6196static inline int target_to_host_mlockall_arg(int arg)
6197{
6198 int result = 0;
6199
6200 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6201 result |= MCL_CURRENT;
6202 }
6203 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6204 result |= MCL_FUTURE;
6205 }
6206 return result;
6207}
6208#endif
6209
balrog6a24a772008-09-20 02:23:36 +00006210static inline abi_long host_to_target_stat64(void *cpu_env,
6211 abi_ulong target_addr,
6212 struct stat *host_st)
6213{
Alexander Graf09701192013-09-03 20:12:15 +01006214#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006215 if (((CPUARMState *)cpu_env)->eabi) {
6216 struct target_eabi_stat64 *target_st;
6217
6218 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6219 return -TARGET_EFAULT;
6220 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6221 __put_user(host_st->st_dev, &target_st->st_dev);
6222 __put_user(host_st->st_ino, &target_st->st_ino);
6223#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6224 __put_user(host_st->st_ino, &target_st->__st_ino);
6225#endif
6226 __put_user(host_st->st_mode, &target_st->st_mode);
6227 __put_user(host_st->st_nlink, &target_st->st_nlink);
6228 __put_user(host_st->st_uid, &target_st->st_uid);
6229 __put_user(host_st->st_gid, &target_st->st_gid);
6230 __put_user(host_st->st_rdev, &target_st->st_rdev);
6231 __put_user(host_st->st_size, &target_st->st_size);
6232 __put_user(host_st->st_blksize, &target_st->st_blksize);
6233 __put_user(host_st->st_blocks, &target_st->st_blocks);
6234 __put_user(host_st->st_atime, &target_st->target_st_atime);
6235 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6236 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6237 unlock_user_struct(target_st, target_addr, 1);
6238 } else
6239#endif
6240 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006241#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006242 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006243#else
6244 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006245#endif
balrog6a24a772008-09-20 02:23:36 +00006246
6247 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6248 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006249 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006250 __put_user(host_st->st_dev, &target_st->st_dev);
6251 __put_user(host_st->st_ino, &target_st->st_ino);
6252#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6253 __put_user(host_st->st_ino, &target_st->__st_ino);
6254#endif
6255 __put_user(host_st->st_mode, &target_st->st_mode);
6256 __put_user(host_st->st_nlink, &target_st->st_nlink);
6257 __put_user(host_st->st_uid, &target_st->st_uid);
6258 __put_user(host_st->st_gid, &target_st->st_gid);
6259 __put_user(host_st->st_rdev, &target_st->st_rdev);
6260 /* XXX: better use of kernel struct */
6261 __put_user(host_st->st_size, &target_st->st_size);
6262 __put_user(host_st->st_blksize, &target_st->st_blksize);
6263 __put_user(host_st->st_blocks, &target_st->st_blocks);
6264 __put_user(host_st->st_atime, &target_st->target_st_atime);
6265 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6266 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6267 unlock_user_struct(target_st, target_addr, 1);
6268 }
6269
6270 return 0;
6271}
balrog6a24a772008-09-20 02:23:36 +00006272
pbrookbd0c5662008-05-29 14:34:11 +00006273/* ??? Using host futex calls even when target atomic operations
6274 are not really atomic probably breaks things. However implementing
6275 futexes locally would make futexes shared between multiple processes
6276 tricky. However they're probably useless because guest atomic
6277 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006278static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6279 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006280{
6281 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006282 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006283
6284 /* ??? We assume FUTEX_* constants are the same on both host
6285 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006286#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006287 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006288#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006289 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006290#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006291 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006292 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006293 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006294 if (timeout) {
6295 pts = &ts;
6296 target_to_host_timespec(pts, timeout);
6297 } else {
6298 pts = NULL;
6299 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006300 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006301 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006302 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006303 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006304 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006305 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006306 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006307 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006308 case FUTEX_WAKE_OP:
6309 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6310 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6311 But the prototype takes a `struct timespec *'; insert casts
6312 to satisfy the compiler. We do not need to tswap TIMEOUT
6313 since it's not compared to guest memory. */
6314 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006315 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6316 g2h(uaddr2),
6317 (base_op == FUTEX_CMP_REQUEUE
6318 ? tswap32(val3)
6319 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006320 default:
6321 return -TARGET_ENOSYS;
6322 }
6323}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006324#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6325static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6326 abi_long handle, abi_long mount_id,
6327 abi_long flags)
6328{
6329 struct file_handle *target_fh;
6330 struct file_handle *fh;
6331 int mid = 0;
6332 abi_long ret;
6333 char *name;
6334 unsigned int size, total_size;
6335
6336 if (get_user_s32(size, handle)) {
6337 return -TARGET_EFAULT;
6338 }
6339
6340 name = lock_user_string(pathname);
6341 if (!name) {
6342 return -TARGET_EFAULT;
6343 }
6344
6345 total_size = sizeof(struct file_handle) + size;
6346 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6347 if (!target_fh) {
6348 unlock_user(name, pathname, 0);
6349 return -TARGET_EFAULT;
6350 }
6351
6352 fh = g_malloc0(total_size);
6353 fh->handle_bytes = size;
6354
6355 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6356 unlock_user(name, pathname, 0);
6357
6358 /* man name_to_handle_at(2):
6359 * Other than the use of the handle_bytes field, the caller should treat
6360 * the file_handle structure as an opaque data type
6361 */
6362
6363 memcpy(target_fh, fh, total_size);
6364 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6365 target_fh->handle_type = tswap32(fh->handle_type);
6366 g_free(fh);
6367 unlock_user(target_fh, handle, total_size);
6368
6369 if (put_user_s32(mid, mount_id)) {
6370 return -TARGET_EFAULT;
6371 }
6372
6373 return ret;
6374
6375}
6376#endif
6377
6378#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6379static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6380 abi_long flags)
6381{
6382 struct file_handle *target_fh;
6383 struct file_handle *fh;
6384 unsigned int size, total_size;
6385 abi_long ret;
6386
6387 if (get_user_s32(size, handle)) {
6388 return -TARGET_EFAULT;
6389 }
6390
6391 total_size = sizeof(struct file_handle) + size;
6392 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6393 if (!target_fh) {
6394 return -TARGET_EFAULT;
6395 }
6396
Thomas Huthe9d49d52015-10-09 17:56:38 +02006397 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006398 fh->handle_bytes = size;
6399 fh->handle_type = tswap32(target_fh->handle_type);
6400
6401 ret = get_errno(open_by_handle_at(mount_fd, fh,
6402 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6403
6404 g_free(fh);
6405
6406 unlock_user(target_fh, handle, total_size);
6407
6408 return ret;
6409}
6410#endif
pbrookbd0c5662008-05-29 14:34:11 +00006411
Laurent Viviere36800c2015-10-02 14:48:09 +02006412#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6413
6414/* signalfd siginfo conversion */
6415
6416static void
6417host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6418 const struct signalfd_siginfo *info)
6419{
6420 int sig = host_to_target_signal(info->ssi_signo);
6421
6422 /* linux/signalfd.h defines a ssi_addr_lsb
6423 * not defined in sys/signalfd.h but used by some kernels
6424 */
6425
6426#ifdef BUS_MCEERR_AO
6427 if (tinfo->ssi_signo == SIGBUS &&
6428 (tinfo->ssi_code == BUS_MCEERR_AR ||
6429 tinfo->ssi_code == BUS_MCEERR_AO)) {
6430 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6431 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6432 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6433 }
6434#endif
6435
6436 tinfo->ssi_signo = tswap32(sig);
6437 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6438 tinfo->ssi_code = tswap32(info->ssi_code);
6439 tinfo->ssi_pid = tswap32(info->ssi_pid);
6440 tinfo->ssi_uid = tswap32(info->ssi_uid);
6441 tinfo->ssi_fd = tswap32(info->ssi_fd);
6442 tinfo->ssi_tid = tswap32(info->ssi_tid);
6443 tinfo->ssi_band = tswap32(info->ssi_band);
6444 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6445 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6446 tinfo->ssi_status = tswap32(info->ssi_status);
6447 tinfo->ssi_int = tswap32(info->ssi_int);
6448 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6449 tinfo->ssi_utime = tswap64(info->ssi_utime);
6450 tinfo->ssi_stime = tswap64(info->ssi_stime);
6451 tinfo->ssi_addr = tswap64(info->ssi_addr);
6452}
6453
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006454static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006455{
6456 int i;
6457
6458 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6459 host_to_target_signalfd_siginfo(buf + i, buf + i);
6460 }
6461
6462 return len;
6463}
6464
6465static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006466 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006467};
6468
6469static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6470{
6471 int host_flags;
6472 target_sigset_t *target_mask;
6473 sigset_t host_mask;
6474 abi_long ret;
6475
6476 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6477 return -TARGET_EINVAL;
6478 }
6479 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6480 return -TARGET_EFAULT;
6481 }
6482
6483 target_to_host_sigset(&host_mask, target_mask);
6484
6485 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6486
6487 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6488 if (ret >= 0) {
6489 fd_trans_register(ret, &target_signalfd_trans);
6490 }
6491
6492 unlock_user_struct(target_mask, mask, 0);
6493
6494 return ret;
6495}
6496#endif
6497
pbrook1d9d8b52009-04-16 15:17:02 +00006498/* Map host to target signal numbers for the wait family of syscalls.
6499 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006500int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006501{
6502 if (WIFSIGNALED(status)) {
6503 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6504 }
6505 if (WIFSTOPPED(status)) {
6506 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6507 | (status & 0xff);
6508 }
6509 return status;
6510}
6511
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006512static int open_self_cmdline(void *cpu_env, int fd)
6513{
6514 int fd_orig = -1;
6515 bool word_skipped = false;
6516
6517 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6518 if (fd_orig < 0) {
6519 return fd_orig;
6520 }
6521
6522 while (true) {
6523 ssize_t nb_read;
6524 char buf[128];
6525 char *cp_buf = buf;
6526
6527 nb_read = read(fd_orig, buf, sizeof(buf));
6528 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006529 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006530 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006531 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006532 return -1;
6533 } else if (nb_read == 0) {
6534 break;
6535 }
6536
6537 if (!word_skipped) {
6538 /* Skip the first string, which is the path to qemu-*-static
6539 instead of the actual command. */
6540 cp_buf = memchr(buf, 0, sizeof(buf));
6541 if (cp_buf) {
6542 /* Null byte found, skip one string */
6543 cp_buf++;
6544 nb_read -= cp_buf - buf;
6545 word_skipped = true;
6546 }
6547 }
6548
6549 if (word_skipped) {
6550 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006551 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006552 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006553 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006554 return -1;
6555 }
6556 }
6557 }
6558
6559 return close(fd_orig);
6560}
6561
Alexander Graf36c08d42011-11-02 20:23:24 +01006562static int open_self_maps(void *cpu_env, int fd)
6563{
Andreas Färber0429a972013-08-26 18:14:44 +02006564 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6565 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006566 FILE *fp;
6567 char *line = NULL;
6568 size_t len = 0;
6569 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006570
Alexander Graf1a49ef22012-05-01 16:30:28 +01006571 fp = fopen("/proc/self/maps", "r");
6572 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006573 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006574 }
6575
6576 while ((read = getline(&line, &len, fp)) != -1) {
6577 int fields, dev_maj, dev_min, inode;
6578 uint64_t min, max, offset;
6579 char flag_r, flag_w, flag_x, flag_p;
6580 char path[512] = "";
6581 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6582 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6583 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6584
6585 if ((fields < 10) || (fields > 11)) {
6586 continue;
6587 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006588 if (h2g_valid(min)) {
6589 int flags = page_get_flags(h2g(min));
6590 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6591 if (page_check_range(h2g(min), max - min, flags) == -1) {
6592 continue;
6593 }
6594 if (h2g(min) == ts->info->stack_limit) {
6595 pstrcpy(path, sizeof(path), " [stack]");
6596 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006597 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006598 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006599 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006600 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006601 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006602 }
6603 }
6604
6605 free(line);
6606 fclose(fp);
6607
Alexander Graf36c08d42011-11-02 20:23:24 +01006608 return 0;
6609}
6610
Alexander Graf480b8e72011-11-02 20:23:25 +01006611static int open_self_stat(void *cpu_env, int fd)
6612{
Andreas Färber0429a972013-08-26 18:14:44 +02006613 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6614 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006615 abi_ulong start_stack = ts->info->start_stack;
6616 int i;
6617
6618 for (i = 0; i < 44; i++) {
6619 char buf[128];
6620 int len;
6621 uint64_t val = 0;
6622
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006623 if (i == 0) {
6624 /* pid */
6625 val = getpid();
6626 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6627 } else if (i == 1) {
6628 /* app name */
6629 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6630 } else if (i == 27) {
6631 /* stack bottom */
6632 val = start_stack;
6633 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6634 } else {
6635 /* for the rest, there is MasterCard */
6636 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006637 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006638
Alexander Graf480b8e72011-11-02 20:23:25 +01006639 len = strlen(buf);
6640 if (write(fd, buf, len) != len) {
6641 return -1;
6642 }
6643 }
6644
6645 return 0;
6646}
6647
Alexander Graf257450e2011-11-02 20:23:26 +01006648static int open_self_auxv(void *cpu_env, int fd)
6649{
Andreas Färber0429a972013-08-26 18:14:44 +02006650 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6651 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006652 abi_ulong auxv = ts->info->saved_auxv;
6653 abi_ulong len = ts->info->auxv_len;
6654 char *ptr;
6655
6656 /*
6657 * Auxiliary vector is stored in target process stack.
6658 * read in whole auxv vector and copy it to file
6659 */
6660 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6661 if (ptr != NULL) {
6662 while (len > 0) {
6663 ssize_t r;
6664 r = write(fd, ptr, len);
6665 if (r <= 0) {
6666 break;
6667 }
6668 len -= r;
6669 ptr += r;
6670 }
6671 lseek(fd, 0, SEEK_SET);
6672 unlock_user(ptr, auxv, len);
6673 }
6674
6675 return 0;
6676}
6677
Andreas Schwab463d8e72013-07-02 14:04:12 +01006678static int is_proc_myself(const char *filename, const char *entry)
6679{
6680 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6681 filename += strlen("/proc/");
6682 if (!strncmp(filename, "self/", strlen("self/"))) {
6683 filename += strlen("self/");
6684 } else if (*filename >= '1' && *filename <= '9') {
6685 char myself[80];
6686 snprintf(myself, sizeof(myself), "%d/", getpid());
6687 if (!strncmp(filename, myself, strlen(myself))) {
6688 filename += strlen(myself);
6689 } else {
6690 return 0;
6691 }
6692 } else {
6693 return 0;
6694 }
6695 if (!strcmp(filename, entry)) {
6696 return 1;
6697 }
6698 }
6699 return 0;
6700}
6701
Laurent Vivierde6b9932013-08-30 01:46:40 +02006702#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6703static int is_proc(const char *filename, const char *entry)
6704{
6705 return strcmp(filename, entry) == 0;
6706}
6707
6708static int open_net_route(void *cpu_env, int fd)
6709{
6710 FILE *fp;
6711 char *line = NULL;
6712 size_t len = 0;
6713 ssize_t read;
6714
6715 fp = fopen("/proc/net/route", "r");
6716 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006717 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006718 }
6719
6720 /* read header */
6721
6722 read = getline(&line, &len, fp);
6723 dprintf(fd, "%s", line);
6724
6725 /* read routes */
6726
6727 while ((read = getline(&line, &len, fp)) != -1) {
6728 char iface[16];
6729 uint32_t dest, gw, mask;
6730 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6731 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6732 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6733 &mask, &mtu, &window, &irtt);
6734 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6735 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6736 metric, tswap32(mask), mtu, window, irtt);
6737 }
6738
6739 free(line);
6740 fclose(fp);
6741
6742 return 0;
6743}
6744#endif
6745
Riku Voipio0b2effd2014-08-06 10:36:37 +03006746static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006747{
6748 struct fake_open {
6749 const char *filename;
6750 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006751 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006752 };
6753 const struct fake_open *fake_open;
6754 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006755 { "maps", open_self_maps, is_proc_myself },
6756 { "stat", open_self_stat, is_proc_myself },
6757 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006758 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006759#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6760 { "/proc/net/route", open_net_route, is_proc },
6761#endif
6762 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006763 };
6764
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006765 if (is_proc_myself(pathname, "exe")) {
6766 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006767 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006768 }
6769
Alexander Graf3be14d02011-11-02 20:23:23 +01006770 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006771 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006772 break;
6773 }
6774 }
6775
6776 if (fake_open->filename) {
6777 const char *tmpdir;
6778 char filename[PATH_MAX];
6779 int fd, r;
6780
6781 /* create temporary file to map stat to */
6782 tmpdir = getenv("TMPDIR");
6783 if (!tmpdir)
6784 tmpdir = "/tmp";
6785 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6786 fd = mkstemp(filename);
6787 if (fd < 0) {
6788 return fd;
6789 }
6790 unlink(filename);
6791
6792 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006793 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006794 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006795 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006796 return r;
6797 }
6798 lseek(fd, 0, SEEK_SET);
6799
6800 return fd;
6801 }
6802
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006803 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006804}
6805
Alexander Grafaecc8862014-11-10 21:33:03 +01006806#define TIMER_MAGIC 0x0caf0000
6807#define TIMER_MAGIC_MASK 0xffff0000
6808
6809/* Convert QEMU provided timer ID back to internal 16bit index format */
6810static target_timer_t get_timer_id(abi_long arg)
6811{
6812 target_timer_t timerid = arg;
6813
6814 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6815 return -TARGET_EINVAL;
6816 }
6817
6818 timerid &= 0xffff;
6819
6820 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6821 return -TARGET_EINVAL;
6822 }
6823
6824 return timerid;
6825}
6826
ths0da46a62007-10-20 20:23:07 +00006827/* do_syscall() should always have a single exit point at the end so
6828 that actions, such as logging of syscall results, can be performed.
6829 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006830abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6831 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006832 abi_long arg5, abi_long arg6, abi_long arg7,
6833 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006834{
Andreas Färber182735e2013-05-29 22:29:20 +02006835 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006836 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006837 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006838 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006839 void *p;
ths3b46e622007-09-17 08:09:54 +00006840
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006841#if defined(DEBUG_ERESTARTSYS)
6842 /* Debug-only code for exercising the syscall-restart code paths
6843 * in the per-architecture cpu main loops: restart every syscall
6844 * the guest makes once before letting it through.
6845 */
6846 {
6847 static int flag;
6848
6849 flag = !flag;
6850 if (flag) {
6851 return -TARGET_ERESTARTSYS;
6852 }
6853 }
6854#endif
6855
bellard72f03902003-02-18 23:33:18 +00006856#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006857 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006858#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02006859 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00006860 if(do_strace)
6861 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6862
bellard31e31b82003-02-18 22:55:36 +00006863 switch(num) {
6864 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006865 /* In old applications this may be used to implement _exit(2).
6866 However in threaded applictions it is used for thread termination,
6867 and _exit_group is used for application termination.
6868 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01006869
6870 if (block_signals()) {
6871 ret = -TARGET_ERESTARTSYS;
6872 break;
6873 }
6874
Andreas Färberbdc44642013-06-24 23:50:24 +02006875 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006876 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006877
Andreas Färber9b056fc2013-06-24 23:53:10 +02006878 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006879 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006880 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006881 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006882 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006883 if (ts->child_tidptr) {
6884 put_user_u32(0, ts->child_tidptr);
6885 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6886 NULL, NULL, 0);
6887 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006888 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006889 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006890 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006891 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006892 pthread_exit(NULL);
6893 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006894#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006895 _mcleanup();
6896#endif
bellarde9009672005-04-26 20:42:36 +00006897 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006898 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006899 ret = 0; /* avoid warning */
6900 break;
6901 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006902 if (arg3 == 0)
6903 ret = 0;
6904 else {
6905 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6906 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006907 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006908 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006909 fd_trans_host_to_target_data(arg1)) {
6910 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006911 }
aurel3238d840e2009-01-30 19:48:17 +00006912 unlock_user(p, arg2, ret);
6913 }
bellard31e31b82003-02-18 22:55:36 +00006914 break;
6915 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006916 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6917 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006918 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006919 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006920 break;
Chen Gang704eff62015-08-21 05:37:33 +08006921#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006922 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006923 if (!(p = lock_user_string(arg1)))
6924 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006925 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6926 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6927 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006928 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006929 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006930 break;
Chen Gang704eff62015-08-21 05:37:33 +08006931#endif
ths82424832007-09-24 09:21:55 +00006932 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006933 if (!(p = lock_user_string(arg2)))
6934 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006935 ret = get_errno(do_openat(cpu_env, arg1, p,
6936 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6937 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006938 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006939 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006940 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006941#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6942 case TARGET_NR_name_to_handle_at:
6943 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6944 break;
6945#endif
6946#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6947 case TARGET_NR_open_by_handle_at:
6948 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006949 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006950 break;
6951#endif
bellard31e31b82003-02-18 22:55:36 +00006952 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006953 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006954 ret = get_errno(close(arg1));
6955 break;
6956 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006957 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006958 break;
Chen Gang704eff62015-08-21 05:37:33 +08006959#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006960 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006961 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006962 break;
Chen Gang704eff62015-08-21 05:37:33 +08006963#endif
thse5febef2007-04-01 18:31:35 +00006964#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006965 case TARGET_NR_waitpid:
6966 {
pbrook53a59602006-03-25 19:31:22 +00006967 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006968 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006969 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006970 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006971 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006972 }
6973 break;
thse5febef2007-04-01 18:31:35 +00006974#endif
pbrookf0cbb612008-05-30 18:20:05 +00006975#ifdef TARGET_NR_waitid
6976 case TARGET_NR_waitid:
6977 {
6978 siginfo_t info;
6979 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006980 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006981 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006982 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006983 goto efault;
6984 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006985 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006986 }
6987 }
6988 break;
6989#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006990#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006991 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006992 if (!(p = lock_user_string(arg1)))
6993 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006994 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006995 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006996 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006997 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006998#endif
Chen Gang704eff62015-08-21 05:37:33 +08006999#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007000 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007001 {
7002 void * p2;
7003 p = lock_user_string(arg1);
7004 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007005 if (!p || !p2)
7006 ret = -TARGET_EFAULT;
7007 else
7008 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007009 unlock_user(p2, arg2, 0);
7010 unlock_user(p, arg1, 0);
7011 }
bellard31e31b82003-02-18 22:55:36 +00007012 break;
Chen Gang704eff62015-08-21 05:37:33 +08007013#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007014#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007015 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007016 {
7017 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007018 if (!arg2 || !arg4)
7019 goto efault;
ths64f0ce42007-09-24 09:25:06 +00007020 p = lock_user_string(arg2);
7021 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007022 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007023 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007024 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007025 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007026 unlock_user(p, arg2, 0);
7027 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007028 }
7029 break;
7030#endif
Chen Gang704eff62015-08-21 05:37:33 +08007031#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007032 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007033 if (!(p = lock_user_string(arg1)))
7034 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007035 ret = get_errno(unlink(p));
7036 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007037 break;
Chen Gang704eff62015-08-21 05:37:33 +08007038#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007039#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007040 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007041 if (!(p = lock_user_string(arg2)))
7042 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007043 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007044 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007045 break;
balrogb7d35e62007-12-12 00:40:24 +00007046#endif
bellard31e31b82003-02-18 22:55:36 +00007047 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007048 {
7049 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007050 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007051 abi_ulong gp;
7052 abi_ulong guest_argp;
7053 abi_ulong guest_envp;
7054 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007055 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007056 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007057
bellardf7341ff2003-03-30 21:00:25 +00007058 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007059 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007060 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007061 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007062 goto efault;
ths03aa1972007-12-02 06:28:08 +00007063 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007064 break;
bellard7854b052003-03-29 17:22:23 +00007065 argc++;
bellard2f619692007-11-16 10:46:05 +00007066 }
bellardf7341ff2003-03-30 21:00:25 +00007067 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007068 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007069 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007070 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007071 goto efault;
ths03aa1972007-12-02 06:28:08 +00007072 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007073 break;
bellard7854b052003-03-29 17:22:23 +00007074 envc++;
bellard2f619692007-11-16 10:46:05 +00007075 }
bellard7854b052003-03-29 17:22:23 +00007076
bellardf7341ff2003-03-30 21:00:25 +00007077 argp = alloca((argc + 1) * sizeof(void *));
7078 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007079
pbrookda94d262008-05-30 18:24:00 +00007080 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007081 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007082 if (get_user_ual(addr, gp))
7083 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007084 if (!addr)
7085 break;
bellard2f619692007-11-16 10:46:05 +00007086 if (!(*q = lock_user_string(addr)))
7087 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007088 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007089 }
bellardf7341ff2003-03-30 21:00:25 +00007090 *q = NULL;
7091
pbrookda94d262008-05-30 18:24:00 +00007092 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007093 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007094 if (get_user_ual(addr, gp))
7095 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007096 if (!addr)
7097 break;
bellard2f619692007-11-16 10:46:05 +00007098 if (!(*q = lock_user_string(addr)))
7099 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007100 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007101 }
bellardf7341ff2003-03-30 21:00:25 +00007102 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007103
bellard2f619692007-11-16 10:46:05 +00007104 if (!(p = lock_user_string(arg1)))
7105 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007106 /* Although execve() is not an interruptible syscall it is
7107 * a special case where we must use the safe_syscall wrapper:
7108 * if we allow a signal to happen before we make the host
7109 * syscall then we will 'lose' it, because at the point of
7110 * execve the process leaves QEMU's control. So we use the
7111 * safe syscall wrapper to ensure that we either take the
7112 * signal as a guest signal, or else it does not happen
7113 * before the execve completes and makes it the other
7114 * program's problem.
7115 */
7116 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007117 unlock_user(p, arg1, 0);
7118
bellard2f619692007-11-16 10:46:05 +00007119 goto execve_end;
7120
7121 execve_efault:
7122 ret = -TARGET_EFAULT;
7123
7124 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007125 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007126 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007127 if (get_user_ual(addr, gp)
7128 || !addr)
7129 break;
pbrook53a59602006-03-25 19:31:22 +00007130 unlock_user(*q, addr, 0);
7131 }
7132 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007133 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007134 if (get_user_ual(addr, gp)
7135 || !addr)
7136 break;
pbrook53a59602006-03-25 19:31:22 +00007137 unlock_user(*q, addr, 0);
7138 }
bellard7854b052003-03-29 17:22:23 +00007139 }
bellard31e31b82003-02-18 22:55:36 +00007140 break;
7141 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007142 if (!(p = lock_user_string(arg1)))
7143 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007144 ret = get_errno(chdir(p));
7145 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007146 break;
bellarda315a142005-01-30 22:59:18 +00007147#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007148 case TARGET_NR_time:
7149 {
pbrook53a59602006-03-25 19:31:22 +00007150 time_t host_time;
7151 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007152 if (!is_error(ret)
7153 && arg1
7154 && put_user_sal(host_time, arg1))
7155 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007156 }
7157 break;
bellarda315a142005-01-30 22:59:18 +00007158#endif
Chen Gang704eff62015-08-21 05:37:33 +08007159#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007160 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007161 if (!(p = lock_user_string(arg1)))
7162 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007163 ret = get_errno(mknod(p, arg2, arg3));
7164 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007165 break;
Chen Gang704eff62015-08-21 05:37:33 +08007166#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007167#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007168 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007169 if (!(p = lock_user_string(arg2)))
7170 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007171 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007172 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007173 break;
7174#endif
Chen Gang704eff62015-08-21 05:37:33 +08007175#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007176 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007177 if (!(p = lock_user_string(arg1)))
7178 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007179 ret = get_errno(chmod(p, arg2));
7180 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007181 break;
Chen Gang704eff62015-08-21 05:37:33 +08007182#endif
bellardebc05482003-09-30 21:08:41 +00007183#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007184 case TARGET_NR_break:
7185 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007186#endif
7187#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007188 case TARGET_NR_oldstat:
7189 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007190#endif
bellard31e31b82003-02-18 22:55:36 +00007191 case TARGET_NR_lseek:
7192 ret = get_errno(lseek(arg1, arg2, arg3));
7193 break;
Richard Henderson92317332010-05-03 10:07:53 -07007194#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7195 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007196 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007197 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007198 ret = get_errno(getpid());
7199 break;
Richard Henderson92317332010-05-03 10:07:53 -07007200#endif
7201#ifdef TARGET_NR_getpid
7202 case TARGET_NR_getpid:
7203 ret = get_errno(getpid());
7204 break;
7205#endif
bellard31e31b82003-02-18 22:55:36 +00007206 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007207 {
7208 /* need to look at the data field */
7209 void *p2, *p3;
7210
7211 if (arg1) {
7212 p = lock_user_string(arg1);
7213 if (!p) {
7214 goto efault;
7215 }
7216 } else {
7217 p = NULL;
7218 }
7219
7220 p2 = lock_user_string(arg2);
7221 if (!p2) {
7222 if (arg1) {
7223 unlock_user(p, arg1, 0);
7224 }
7225 goto efault;
7226 }
7227
7228 if (arg3) {
7229 p3 = lock_user_string(arg3);
7230 if (!p3) {
7231 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007232 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007233 }
7234 unlock_user(p2, arg2, 0);
7235 goto efault;
7236 }
7237 } else {
7238 p3 = NULL;
7239 }
7240
7241 /* FIXME - arg5 should be locked, but it isn't clear how to
7242 * do that since it's not guaranteed to be a NULL-terminated
7243 * string.
7244 */
7245 if (!arg5) {
7246 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7247 } else {
7248 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7249 }
7250 ret = get_errno(ret);
7251
7252 if (arg1) {
7253 unlock_user(p, arg1, 0);
7254 }
7255 unlock_user(p2, arg2, 0);
7256 if (arg3) {
7257 unlock_user(p3, arg3, 0);
7258 }
7259 }
7260 break;
thse5febef2007-04-01 18:31:35 +00007261#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007262 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007263 if (!(p = lock_user_string(arg1)))
7264 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007265 ret = get_errno(umount(p));
7266 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007267 break;
thse5febef2007-04-01 18:31:35 +00007268#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007269#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007270 case TARGET_NR_stime:
7271 {
pbrook53a59602006-03-25 19:31:22 +00007272 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007273 if (get_user_sal(host_time, arg1))
7274 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007275 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007276 }
7277 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007278#endif
bellard31e31b82003-02-18 22:55:36 +00007279 case TARGET_NR_ptrace:
7280 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007281#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007282 case TARGET_NR_alarm:
7283 ret = alarm(arg1);
7284 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007285#endif
bellardebc05482003-09-30 21:08:41 +00007286#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007287 case TARGET_NR_oldfstat:
7288 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007289#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007290#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007291 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007292 if (!block_signals()) {
7293 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7294 }
7295 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007296 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007297#endif
thse5febef2007-04-01 18:31:35 +00007298#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007299 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007300 {
pbrook53a59602006-03-25 19:31:22 +00007301 struct utimbuf tbuf, *host_tbuf;
7302 struct target_utimbuf *target_tbuf;
7303 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007304 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7305 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007306 tbuf.actime = tswapal(target_tbuf->actime);
7307 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007308 unlock_user_struct(target_tbuf, arg2, 0);
7309 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007310 } else {
pbrook53a59602006-03-25 19:31:22 +00007311 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007312 }
bellard579a97f2007-11-11 14:26:47 +00007313 if (!(p = lock_user_string(arg1)))
7314 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007315 ret = get_errno(utime(p, host_tbuf));
7316 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007317 }
7318 break;
thse5febef2007-04-01 18:31:35 +00007319#endif
Chen Gang704eff62015-08-21 05:37:33 +08007320#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007321 case TARGET_NR_utimes:
7322 {
bellard978a66f2004-12-06 22:58:05 +00007323 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007324 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007325 if (copy_from_user_timeval(&tv[0], arg2)
7326 || copy_from_user_timeval(&tv[1],
7327 arg2 + sizeof(struct target_timeval)))
7328 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007329 tvp = tv;
7330 } else {
7331 tvp = NULL;
7332 }
bellard579a97f2007-11-11 14:26:47 +00007333 if (!(p = lock_user_string(arg1)))
7334 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007335 ret = get_errno(utimes(p, tvp));
7336 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007337 }
7338 break;
Chen Gang704eff62015-08-21 05:37:33 +08007339#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007340#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007341 case TARGET_NR_futimesat:
7342 {
7343 struct timeval *tvp, tv[2];
7344 if (arg3) {
7345 if (copy_from_user_timeval(&tv[0], arg3)
7346 || copy_from_user_timeval(&tv[1],
7347 arg3 + sizeof(struct target_timeval)))
7348 goto efault;
7349 tvp = tv;
7350 } else {
7351 tvp = NULL;
7352 }
7353 if (!(p = lock_user_string(arg2)))
7354 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007355 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007356 unlock_user(p, arg2, 0);
7357 }
7358 break;
7359#endif
bellardebc05482003-09-30 21:08:41 +00007360#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007361 case TARGET_NR_stty:
7362 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007363#endif
7364#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007365 case TARGET_NR_gtty:
7366 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007367#endif
Chen Gang704eff62015-08-21 05:37:33 +08007368#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007369 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007370 if (!(p = lock_user_string(arg1)))
7371 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007372 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007373 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007374 break;
Chen Gang704eff62015-08-21 05:37:33 +08007375#endif
ths92a34c12007-09-24 09:27:49 +00007376#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7377 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007378 if (!(p = lock_user_string(arg2)))
7379 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007380 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007381 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007382 break;
7383#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007384#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007385 case TARGET_NR_nice:
7386 ret = get_errno(nice(arg1));
7387 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007388#endif
bellardebc05482003-09-30 21:08:41 +00007389#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007390 case TARGET_NR_ftime:
7391 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007392#endif
bellard31e31b82003-02-18 22:55:36 +00007393 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007394 sync();
7395 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007396 break;
7397 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007398 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007399 break;
Chen Gang704eff62015-08-21 05:37:33 +08007400#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007401 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007402 {
7403 void *p2;
7404 p = lock_user_string(arg1);
7405 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007406 if (!p || !p2)
7407 ret = -TARGET_EFAULT;
7408 else
7409 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007410 unlock_user(p2, arg2, 0);
7411 unlock_user(p, arg1, 0);
7412 }
bellard31e31b82003-02-18 22:55:36 +00007413 break;
Chen Gang704eff62015-08-21 05:37:33 +08007414#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007415#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007416 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007417 {
bellard579a97f2007-11-11 14:26:47 +00007418 void *p2;
ths722183f2007-09-24 09:24:37 +00007419 p = lock_user_string(arg2);
7420 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007421 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007422 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007423 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007424 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007425 unlock_user(p2, arg4, 0);
7426 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007427 }
7428 break;
7429#endif
Chen Gang704eff62015-08-21 05:37:33 +08007430#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007431 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007432 if (!(p = lock_user_string(arg1)))
7433 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007434 ret = get_errno(mkdir(p, arg2));
7435 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007436 break;
Chen Gang704eff62015-08-21 05:37:33 +08007437#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007438#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007439 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007440 if (!(p = lock_user_string(arg2)))
7441 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007442 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007443 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007444 break;
7445#endif
Chen Gang704eff62015-08-21 05:37:33 +08007446#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007447 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007448 if (!(p = lock_user_string(arg1)))
7449 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007450 ret = get_errno(rmdir(p));
7451 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007452 break;
Chen Gang704eff62015-08-21 05:37:33 +08007453#endif
bellard31e31b82003-02-18 22:55:36 +00007454 case TARGET_NR_dup:
7455 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007456 if (ret >= 0) {
7457 fd_trans_dup(arg1, ret);
7458 }
bellard31e31b82003-02-18 22:55:36 +00007459 break;
Chen Gang704eff62015-08-21 05:37:33 +08007460#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007461 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007462 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007463 break;
Chen Gang704eff62015-08-21 05:37:33 +08007464#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007465#ifdef TARGET_NR_pipe2
7466 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007467 ret = do_pipe(cpu_env, arg1,
7468 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007469 break;
7470#endif
bellard31e31b82003-02-18 22:55:36 +00007471 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007472 {
pbrook53a59602006-03-25 19:31:22 +00007473 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007474 struct tms tms;
7475 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007476 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007477 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7478 if (!tmsp)
7479 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007480 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7481 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7482 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7483 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007484 }
bellardc596ed12003-07-13 17:32:31 +00007485 if (!is_error(ret))
7486 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007487 }
7488 break;
bellardebc05482003-09-30 21:08:41 +00007489#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007490 case TARGET_NR_prof:
7491 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007492#endif
thse5febef2007-04-01 18:31:35 +00007493#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007494 case TARGET_NR_signal:
7495 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007496#endif
bellard31e31b82003-02-18 22:55:36 +00007497 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007498 if (arg1 == 0) {
7499 ret = get_errno(acct(NULL));
7500 } else {
7501 if (!(p = lock_user_string(arg1)))
7502 goto efault;
7503 ret = get_errno(acct(path(p)));
7504 unlock_user(p, arg1, 0);
7505 }
pbrook24836682006-04-16 14:14:53 +00007506 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007507#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007508 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007509 if (!(p = lock_user_string(arg1)))
7510 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007511 ret = get_errno(umount2(p, arg2));
7512 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007513 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007514#endif
bellardebc05482003-09-30 21:08:41 +00007515#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007516 case TARGET_NR_lock:
7517 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007518#endif
bellard31e31b82003-02-18 22:55:36 +00007519 case TARGET_NR_ioctl:
7520 ret = do_ioctl(arg1, arg2, arg3);
7521 break;
7522 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007523 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007524 break;
bellardebc05482003-09-30 21:08:41 +00007525#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007526 case TARGET_NR_mpx:
7527 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007528#endif
bellard31e31b82003-02-18 22:55:36 +00007529 case TARGET_NR_setpgid:
7530 ret = get_errno(setpgid(arg1, arg2));
7531 break;
bellardebc05482003-09-30 21:08:41 +00007532#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007533 case TARGET_NR_ulimit:
7534 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007535#endif
7536#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007537 case TARGET_NR_oldolduname:
7538 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007539#endif
bellard31e31b82003-02-18 22:55:36 +00007540 case TARGET_NR_umask:
7541 ret = get_errno(umask(arg1));
7542 break;
7543 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007544 if (!(p = lock_user_string(arg1)))
7545 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007546 ret = get_errno(chroot(p));
7547 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007548 break;
Chen Gang704eff62015-08-21 05:37:33 +08007549#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007550 case TARGET_NR_ustat:
7551 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007552#endif
7553#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007554 case TARGET_NR_dup2:
7555 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007556 if (ret >= 0) {
7557 fd_trans_dup(arg1, arg2);
7558 }
bellard31e31b82003-02-18 22:55:36 +00007559 break;
Chen Gang704eff62015-08-21 05:37:33 +08007560#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007561#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7562 case TARGET_NR_dup3:
7563 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007564 if (ret >= 0) {
7565 fd_trans_dup(arg1, arg2);
7566 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007567 break;
7568#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007569#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007570 case TARGET_NR_getppid:
7571 ret = get_errno(getppid());
7572 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007573#endif
Chen Gang704eff62015-08-21 05:37:33 +08007574#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007575 case TARGET_NR_getpgrp:
7576 ret = get_errno(getpgrp());
7577 break;
Chen Gang704eff62015-08-21 05:37:33 +08007578#endif
bellard31e31b82003-02-18 22:55:36 +00007579 case TARGET_NR_setsid:
7580 ret = get_errno(setsid());
7581 break;
thse5febef2007-04-01 18:31:35 +00007582#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007583 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007584 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007585#if defined(TARGET_ALPHA)
7586 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007587 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007588 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007589 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7590 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007591 act._sa_handler = old_act->_sa_handler;
7592 target_siginitset(&act.sa_mask, old_act->sa_mask);
7593 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007594 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007595 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007596 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007597 }
7598 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007599 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007600 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7601 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007602 old_act->_sa_handler = oact._sa_handler;
7603 old_act->sa_mask = oact.sa_mask.sig[0];
7604 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007605 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007606 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007607#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007608 struct target_sigaction act, oact, *pact, *old_act;
7609
7610 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007611 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7612 goto efault;
bellard106ec872006-06-27 21:08:10 +00007613 act._sa_handler = old_act->_sa_handler;
7614 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7615 act.sa_flags = old_act->sa_flags;
7616 unlock_user_struct(old_act, arg2, 0);
7617 pact = &act;
7618 } else {
7619 pact = NULL;
7620 }
7621
7622 ret = get_errno(do_sigaction(arg1, pact, &oact));
7623
7624 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007625 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7626 goto efault;
bellard106ec872006-06-27 21:08:10 +00007627 old_act->_sa_handler = oact._sa_handler;
7628 old_act->sa_flags = oact.sa_flags;
7629 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7630 old_act->sa_mask.sig[1] = 0;
7631 old_act->sa_mask.sig[2] = 0;
7632 old_act->sa_mask.sig[3] = 0;
7633 unlock_user_struct(old_act, arg3, 1);
7634 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007635#else
7636 struct target_old_sigaction *old_act;
7637 struct target_sigaction act, oact, *pact;
7638 if (arg2) {
7639 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7640 goto efault;
7641 act._sa_handler = old_act->_sa_handler;
7642 target_siginitset(&act.sa_mask, old_act->sa_mask);
7643 act.sa_flags = old_act->sa_flags;
7644 act.sa_restorer = old_act->sa_restorer;
7645 unlock_user_struct(old_act, arg2, 0);
7646 pact = &act;
7647 } else {
7648 pact = NULL;
7649 }
7650 ret = get_errno(do_sigaction(arg1, pact, &oact));
7651 if (!is_error(ret) && arg3) {
7652 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7653 goto efault;
7654 old_act->_sa_handler = oact._sa_handler;
7655 old_act->sa_mask = oact.sa_mask.sig[0];
7656 old_act->sa_flags = oact.sa_flags;
7657 old_act->sa_restorer = oact.sa_restorer;
7658 unlock_user_struct(old_act, arg3, 1);
7659 }
ths388bb212007-05-13 13:58:00 +00007660#endif
bellard31e31b82003-02-18 22:55:36 +00007661 }
7662 break;
thse5febef2007-04-01 18:31:35 +00007663#endif
bellard66fb9762003-03-23 01:06:05 +00007664 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007665 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007666#if defined(TARGET_ALPHA)
7667 struct target_sigaction act, oact, *pact = 0;
7668 struct target_rt_sigaction *rt_act;
7669 /* ??? arg4 == sizeof(sigset_t). */
7670 if (arg2) {
7671 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7672 goto efault;
7673 act._sa_handler = rt_act->_sa_handler;
7674 act.sa_mask = rt_act->sa_mask;
7675 act.sa_flags = rt_act->sa_flags;
7676 act.sa_restorer = arg5;
7677 unlock_user_struct(rt_act, arg2, 0);
7678 pact = &act;
7679 }
7680 ret = get_errno(do_sigaction(arg1, pact, &oact));
7681 if (!is_error(ret) && arg3) {
7682 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7683 goto efault;
7684 rt_act->_sa_handler = oact._sa_handler;
7685 rt_act->sa_mask = oact.sa_mask;
7686 rt_act->sa_flags = oact.sa_flags;
7687 unlock_user_struct(rt_act, arg3, 1);
7688 }
7689#else
pbrook53a59602006-03-25 19:31:22 +00007690 struct target_sigaction *act;
7691 struct target_sigaction *oact;
7692
bellard579a97f2007-11-11 14:26:47 +00007693 if (arg2) {
7694 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7695 goto efault;
7696 } else
pbrook53a59602006-03-25 19:31:22 +00007697 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007698 if (arg3) {
7699 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7700 ret = -TARGET_EFAULT;
7701 goto rt_sigaction_fail;
7702 }
7703 } else
pbrook53a59602006-03-25 19:31:22 +00007704 oact = NULL;
7705 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007706 rt_sigaction_fail:
7707 if (act)
pbrook53a59602006-03-25 19:31:22 +00007708 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007709 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007710 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007711#endif
pbrook53a59602006-03-25 19:31:22 +00007712 }
bellard66fb9762003-03-23 01:06:05 +00007713 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007714#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007715 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007716 {
7717 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007718 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007719 ret = do_sigprocmask(0, NULL, &cur_set);
7720 if (!ret) {
7721 host_to_target_old_sigset(&target_set, &cur_set);
7722 ret = target_set;
7723 }
bellard66fb9762003-03-23 01:06:05 +00007724 }
7725 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007726#endif
7727#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007728 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007729 {
7730 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007731 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007732 /* We only have one word of the new mask so we must read
7733 * the rest of it with do_sigprocmask() and OR in this word.
7734 * We are guaranteed that a do_sigprocmask() that only queries
7735 * the signal mask will not fail.
7736 */
7737 ret = do_sigprocmask(0, NULL, &cur_set);
7738 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00007739 target_to_host_old_sigset(&set, &target_set);
7740 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007741 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7742 if (!ret) {
7743 host_to_target_old_sigset(&target_set, &oset);
7744 ret = target_set;
7745 }
bellard66fb9762003-03-23 01:06:05 +00007746 }
7747 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007748#endif
thse5febef2007-04-01 18:31:35 +00007749#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007750 case TARGET_NR_sigprocmask:
7751 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007752#if defined(TARGET_ALPHA)
7753 sigset_t set, oldset;
7754 abi_ulong mask;
7755 int how;
7756
7757 switch (arg1) {
7758 case TARGET_SIG_BLOCK:
7759 how = SIG_BLOCK;
7760 break;
7761 case TARGET_SIG_UNBLOCK:
7762 how = SIG_UNBLOCK;
7763 break;
7764 case TARGET_SIG_SETMASK:
7765 how = SIG_SETMASK;
7766 break;
7767 default:
7768 ret = -TARGET_EINVAL;
7769 goto fail;
7770 }
7771 mask = arg2;
7772 target_to_host_old_sigset(&set, &mask);
7773
Peter Maydell3d3efba2016-05-27 15:51:49 +01007774 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007775 if (!is_error(ret)) {
7776 host_to_target_old_sigset(&mask, &oldset);
7777 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007778 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007779 }
7780#else
bellard66fb9762003-03-23 01:06:05 +00007781 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007782 int how;
ths3b46e622007-09-17 08:09:54 +00007783
pbrook53a59602006-03-25 19:31:22 +00007784 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007785 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007786 case TARGET_SIG_BLOCK:
7787 how = SIG_BLOCK;
7788 break;
7789 case TARGET_SIG_UNBLOCK:
7790 how = SIG_UNBLOCK;
7791 break;
7792 case TARGET_SIG_SETMASK:
7793 how = SIG_SETMASK;
7794 break;
7795 default:
ths0da46a62007-10-20 20:23:07 +00007796 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007797 goto fail;
7798 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007799 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007800 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007801 target_to_host_old_sigset(&set, p);
7802 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007803 set_ptr = &set;
7804 } else {
7805 how = 0;
7806 set_ptr = NULL;
7807 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007808 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007809 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007810 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007811 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007812 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007813 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007814 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007815#endif
bellard66fb9762003-03-23 01:06:05 +00007816 }
7817 break;
thse5febef2007-04-01 18:31:35 +00007818#endif
bellard66fb9762003-03-23 01:06:05 +00007819 case TARGET_NR_rt_sigprocmask:
7820 {
7821 int how = arg1;
7822 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007823
pbrook53a59602006-03-25 19:31:22 +00007824 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007825 switch(how) {
7826 case TARGET_SIG_BLOCK:
7827 how = SIG_BLOCK;
7828 break;
7829 case TARGET_SIG_UNBLOCK:
7830 how = SIG_UNBLOCK;
7831 break;
7832 case TARGET_SIG_SETMASK:
7833 how = SIG_SETMASK;
7834 break;
7835 default:
ths0da46a62007-10-20 20:23:07 +00007836 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007837 goto fail;
7838 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007839 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007840 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007841 target_to_host_sigset(&set, p);
7842 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007843 set_ptr = &set;
7844 } else {
7845 how = 0;
7846 set_ptr = NULL;
7847 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007848 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007849 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007850 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007851 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007852 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007853 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007854 }
7855 }
7856 break;
thse5febef2007-04-01 18:31:35 +00007857#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007858 case TARGET_NR_sigpending:
7859 {
7860 sigset_t set;
7861 ret = get_errno(sigpending(&set));
7862 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007863 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007864 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007865 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007866 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007867 }
7868 }
7869 break;
thse5febef2007-04-01 18:31:35 +00007870#endif
bellard66fb9762003-03-23 01:06:05 +00007871 case TARGET_NR_rt_sigpending:
7872 {
7873 sigset_t set;
7874 ret = get_errno(sigpending(&set));
7875 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007876 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007877 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007878 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007879 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007880 }
7881 }
7882 break;
thse5febef2007-04-01 18:31:35 +00007883#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007884 case TARGET_NR_sigsuspend:
7885 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007886 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007887#if defined(TARGET_ALPHA)
7888 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007889 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007890#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007891 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007892 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007893 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007894 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007895#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01007896 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7897 SIGSET_T_SIZE));
7898 if (ret != -TARGET_ERESTARTSYS) {
7899 ts->in_sigsuspend = 1;
7900 }
bellard66fb9762003-03-23 01:06:05 +00007901 }
7902 break;
thse5febef2007-04-01 18:31:35 +00007903#endif
bellard66fb9762003-03-23 01:06:05 +00007904 case TARGET_NR_rt_sigsuspend:
7905 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007906 TaskState *ts = cpu->opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05007907 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007908 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007909 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007910 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007911 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7912 SIGSET_T_SIZE));
7913 if (ret != -TARGET_ERESTARTSYS) {
7914 ts->in_sigsuspend = 1;
7915 }
bellard66fb9762003-03-23 01:06:05 +00007916 }
7917 break;
7918 case TARGET_NR_rt_sigtimedwait:
7919 {
bellard66fb9762003-03-23 01:06:05 +00007920 sigset_t set;
7921 struct timespec uts, *puts;
7922 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007923
Anthony Liguoric227f092009-10-01 16:12:16 -05007924 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007925 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007926 target_to_host_sigset(&set, p);
7927 unlock_user(p, arg1, 0);
7928 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007929 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007930 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007931 } else {
7932 puts = NULL;
7933 }
Peter Maydellb3f82332016-06-06 19:58:08 +01007934 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
7935 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007936 if (!is_error(ret)) {
7937 if (arg2) {
7938 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7939 0);
7940 if (!p) {
7941 goto efault;
7942 }
7943 host_to_target_siginfo(p, &uinfo);
7944 unlock_user(p, arg2, sizeof(target_siginfo_t));
7945 }
7946 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007947 }
7948 }
7949 break;
7950 case TARGET_NR_rt_sigqueueinfo:
7951 {
7952 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01007953
7954 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
7955 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00007956 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01007957 }
pbrook53a59602006-03-25 19:31:22 +00007958 target_to_host_siginfo(&uinfo, p);
7959 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007960 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7961 }
7962 break;
thse5febef2007-04-01 18:31:35 +00007963#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007964 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007965 if (block_signals()) {
7966 ret = -TARGET_ERESTARTSYS;
7967 } else {
7968 ret = do_sigreturn(cpu_env);
7969 }
bellard66fb9762003-03-23 01:06:05 +00007970 break;
thse5febef2007-04-01 18:31:35 +00007971#endif
bellard66fb9762003-03-23 01:06:05 +00007972 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007973 if (block_signals()) {
7974 ret = -TARGET_ERESTARTSYS;
7975 } else {
7976 ret = do_rt_sigreturn(cpu_env);
7977 }
bellard66fb9762003-03-23 01:06:05 +00007978 break;
bellard31e31b82003-02-18 22:55:36 +00007979 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007980 if (!(p = lock_user_string(arg1)))
7981 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007982 ret = get_errno(sethostname(p, arg2));
7983 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007984 break;
7985 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007986 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007987 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007988 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007989 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007990 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7991 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007992 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7993 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007994 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007995 ret = get_errno(setrlimit(resource, &rlim));
7996 }
7997 break;
bellard31e31b82003-02-18 22:55:36 +00007998 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007999 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008000 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008001 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008002 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008003
bellard9de5e442003-03-23 16:49:39 +00008004 ret = get_errno(getrlimit(resource, &rlim));
8005 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008006 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8007 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008008 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8009 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008010 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008011 }
8012 }
8013 break;
bellard31e31b82003-02-18 22:55:36 +00008014 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008015 {
8016 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008017 ret = get_errno(getrusage(arg1, &rusage));
8018 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008019 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008020 }
8021 }
8022 break;
bellard31e31b82003-02-18 22:55:36 +00008023 case TARGET_NR_gettimeofday:
8024 {
bellard31e31b82003-02-18 22:55:36 +00008025 struct timeval tv;
8026 ret = get_errno(gettimeofday(&tv, NULL));
8027 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008028 if (copy_to_user_timeval(arg1, &tv))
8029 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008030 }
8031 }
8032 break;
8033 case TARGET_NR_settimeofday:
8034 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008035 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008036 struct timezone tz, *ptz = NULL;
8037
Paul Burtonb67d8032014-06-22 11:25:41 +01008038 if (arg1) {
8039 if (copy_from_user_timeval(&tv, arg1)) {
8040 goto efault;
8041 }
8042 ptv = &tv;
8043 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008044
8045 if (arg2) {
8046 if (copy_from_user_timezone(&tz, arg2)) {
8047 goto efault;
8048 }
8049 ptz = &tz;
8050 }
8051
Paul Burtonb67d8032014-06-22 11:25:41 +01008052 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008053 }
8054 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008055#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008056 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008057#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
8058 ret = do_select(arg1, arg2, arg3, arg4, arg5);
8059#else
bellardf2674e32003-07-09 12:26:09 +00008060 {
pbrook53a59602006-03-25 19:31:22 +00008061 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00008062 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00008063 long nsel;
8064
bellard579a97f2007-11-11 14:26:47 +00008065 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
8066 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008067 nsel = tswapal(sel->n);
8068 inp = tswapal(sel->inp);
8069 outp = tswapal(sel->outp);
8070 exp = tswapal(sel->exp);
8071 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00008072 unlock_user_struct(sel, arg1, 0);
8073 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00008074 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008075#endif
bellardf2674e32003-07-09 12:26:09 +00008076 break;
bellard048f6b42005-11-26 18:47:20 +00008077#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008078#ifdef TARGET_NR_pselect6
8079 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008080 {
8081 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8082 fd_set rfds, wfds, efds;
8083 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8084 struct timespec ts, *ts_ptr;
8085
8086 /*
8087 * The 6th arg is actually two args smashed together,
8088 * so we cannot use the C library.
8089 */
8090 sigset_t set;
8091 struct {
8092 sigset_t *set;
8093 size_t size;
8094 } sig, *sig_ptr;
8095
8096 abi_ulong arg_sigset, arg_sigsize, *arg7;
8097 target_sigset_t *target_sigset;
8098
8099 n = arg1;
8100 rfd_addr = arg2;
8101 wfd_addr = arg3;
8102 efd_addr = arg4;
8103 ts_addr = arg5;
8104
8105 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8106 if (ret) {
8107 goto fail;
8108 }
8109 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8110 if (ret) {
8111 goto fail;
8112 }
8113 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8114 if (ret) {
8115 goto fail;
8116 }
8117
8118 /*
8119 * This takes a timespec, and not a timeval, so we cannot
8120 * use the do_select() helper ...
8121 */
8122 if (ts_addr) {
8123 if (target_to_host_timespec(&ts, ts_addr)) {
8124 goto efault;
8125 }
8126 ts_ptr = &ts;
8127 } else {
8128 ts_ptr = NULL;
8129 }
8130
8131 /* Extract the two packed args for the sigset */
8132 if (arg6) {
8133 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008134 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008135
8136 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8137 if (!arg7) {
8138 goto efault;
8139 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008140 arg_sigset = tswapal(arg7[0]);
8141 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008142 unlock_user(arg7, arg6, 0);
8143
8144 if (arg_sigset) {
8145 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008146 if (arg_sigsize != sizeof(*target_sigset)) {
8147 /* Like the kernel, we enforce correct size sigsets */
8148 ret = -TARGET_EINVAL;
8149 goto fail;
8150 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008151 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8152 sizeof(*target_sigset), 1);
8153 if (!target_sigset) {
8154 goto efault;
8155 }
8156 target_to_host_sigset(&set, target_sigset);
8157 unlock_user(target_sigset, arg_sigset, 0);
8158 } else {
8159 sig.set = NULL;
8160 }
8161 } else {
8162 sig_ptr = NULL;
8163 }
8164
Peter Maydell6df9d382016-05-12 18:47:51 +01008165 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8166 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008167
8168 if (!is_error(ret)) {
8169 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8170 goto efault;
8171 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8172 goto efault;
8173 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8174 goto efault;
8175
8176 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8177 goto efault;
8178 }
8179 }
8180 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008181#endif
Chen Gang704eff62015-08-21 05:37:33 +08008182#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008183 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008184 {
8185 void *p2;
8186 p = lock_user_string(arg1);
8187 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008188 if (!p || !p2)
8189 ret = -TARGET_EFAULT;
8190 else
8191 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008192 unlock_user(p2, arg2, 0);
8193 unlock_user(p, arg1, 0);
8194 }
bellard31e31b82003-02-18 22:55:36 +00008195 break;
Chen Gang704eff62015-08-21 05:37:33 +08008196#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008197#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008198 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008199 {
bellard579a97f2007-11-11 14:26:47 +00008200 void *p2;
thsf0b62432007-09-24 09:25:40 +00008201 p = lock_user_string(arg1);
8202 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008203 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008204 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008205 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008206 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008207 unlock_user(p2, arg3, 0);
8208 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008209 }
8210 break;
8211#endif
bellardebc05482003-09-30 21:08:41 +00008212#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008213 case TARGET_NR_oldlstat:
8214 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008215#endif
Chen Gang704eff62015-08-21 05:37:33 +08008216#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008217 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008218 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008219 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008220 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008221 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008222 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008223 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008224 } else if (!arg3) {
8225 /* Short circuit this for the magic exe check. */
8226 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008227 } else if (is_proc_myself((const char *)p, "exe")) {
8228 char real[PATH_MAX], *temp;
8229 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008230 /* Return value is # of bytes that we wrote to the buffer. */
8231 if (temp == NULL) {
8232 ret = get_errno(-1);
8233 } else {
8234 /* Don't worry about sign mismatch as earlier mapping
8235 * logic would have thrown a bad address error. */
8236 ret = MIN(strlen(real), arg3);
8237 /* We cannot NUL terminate the string. */
8238 memcpy(p2, real, ret);
8239 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008240 } else {
8241 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008242 }
pbrook53a59602006-03-25 19:31:22 +00008243 unlock_user(p2, arg2, ret);
8244 unlock_user(p, arg1, 0);
8245 }
bellard31e31b82003-02-18 22:55:36 +00008246 break;
Chen Gang704eff62015-08-21 05:37:33 +08008247#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008248#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008249 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008250 {
bellard579a97f2007-11-11 14:26:47 +00008251 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008252 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008253 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008254 if (!p || !p2) {
8255 ret = -TARGET_EFAULT;
8256 } else if (is_proc_myself((const char *)p, "exe")) {
8257 char real[PATH_MAX], *temp;
8258 temp = realpath(exec_path, real);
8259 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8260 snprintf((char *)p2, arg4, "%s", real);
8261 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008262 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008263 }
bellard579a97f2007-11-11 14:26:47 +00008264 unlock_user(p2, arg3, ret);
8265 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008266 }
8267 break;
8268#endif
thse5febef2007-04-01 18:31:35 +00008269#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008270 case TARGET_NR_uselib:
8271 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008272#endif
8273#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008274 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008275 if (!(p = lock_user_string(arg1)))
8276 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008277 ret = get_errno(swapon(p, arg2));
8278 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008279 break;
thse5febef2007-04-01 18:31:35 +00008280#endif
bellard31e31b82003-02-18 22:55:36 +00008281 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008282 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8283 /* arg4 must be ignored in all other cases */
8284 p = lock_user_string(arg4);
8285 if (!p) {
8286 goto efault;
8287 }
8288 ret = get_errno(reboot(arg1, arg2, arg3, p));
8289 unlock_user(p, arg4, 0);
8290 } else {
8291 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8292 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008293 break;
thse5febef2007-04-01 18:31:35 +00008294#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008295 case TARGET_NR_readdir:
8296 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008297#endif
8298#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008299 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008300#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8301 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008302 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8303 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008304 {
blueswir1992f48a2007-10-14 16:27:31 +00008305 abi_ulong *v;
8306 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008307 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8308 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008309 v1 = tswapal(v[0]);
8310 v2 = tswapal(v[1]);
8311 v3 = tswapal(v[2]);
8312 v4 = tswapal(v[3]);
8313 v5 = tswapal(v[4]);
8314 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008315 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008316 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008317 target_to_host_bitmask(v4, mmap_flags_tbl),
8318 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008319 }
bellard31e31b82003-02-18 22:55:36 +00008320#else
ths5fafdf22007-09-16 21:08:06 +00008321 ret = get_errno(target_mmap(arg1, arg2, arg3,
8322 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008323 arg5,
8324 arg6));
bellard31e31b82003-02-18 22:55:36 +00008325#endif
bellard6fb883e2003-07-09 17:12:39 +00008326 break;
thse5febef2007-04-01 18:31:35 +00008327#endif
bellarda315a142005-01-30 22:59:18 +00008328#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008329 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008330#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008331#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008332#endif
ths5fafdf22007-09-16 21:08:06 +00008333 ret = get_errno(target_mmap(arg1, arg2, arg3,
8334 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008335 arg5,
bellardc573ff62004-01-04 15:51:36 +00008336 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008337 break;
bellarda315a142005-01-30 22:59:18 +00008338#endif
bellard31e31b82003-02-18 22:55:36 +00008339 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008340 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008341 break;
bellard9de5e442003-03-23 16:49:39 +00008342 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008343 {
Andreas Färber0429a972013-08-26 18:14:44 +02008344 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008345 /* Special hack to detect libc making the stack executable. */
8346 if ((arg3 & PROT_GROWSDOWN)
8347 && arg1 >= ts->info->stack_limit
8348 && arg1 <= ts->info->start_stack) {
8349 arg3 &= ~PROT_GROWSDOWN;
8350 arg2 = arg2 + arg1 - ts->info->stack_limit;
8351 arg1 = ts->info->stack_limit;
8352 }
8353 }
bellard54936002003-05-13 00:25:15 +00008354 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008355 break;
thse5febef2007-04-01 18:31:35 +00008356#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008357 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008358 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008359 break;
thse5febef2007-04-01 18:31:35 +00008360#endif
pbrook53a59602006-03-25 19:31:22 +00008361 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008362#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008363 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008364 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008365 break;
thse5febef2007-04-01 18:31:35 +00008366#endif
8367#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008368 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008369 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008370 break;
thse5febef2007-04-01 18:31:35 +00008371#endif
8372#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008373 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008374 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008375 break;
thse5febef2007-04-01 18:31:35 +00008376#endif
8377#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008378 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008379 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008380 break;
thse5febef2007-04-01 18:31:35 +00008381#endif
8382#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008383 case TARGET_NR_munlockall:
8384 ret = get_errno(munlockall());
8385 break;
thse5febef2007-04-01 18:31:35 +00008386#endif
bellard31e31b82003-02-18 22:55:36 +00008387 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008388 if (!(p = lock_user_string(arg1)))
8389 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008390 ret = get_errno(truncate(p, arg2));
8391 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008392 break;
8393 case TARGET_NR_ftruncate:
8394 ret = get_errno(ftruncate(arg1, arg2));
8395 break;
8396 case TARGET_NR_fchmod:
8397 ret = get_errno(fchmod(arg1, arg2));
8398 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008399#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008400 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008401 if (!(p = lock_user_string(arg2)))
8402 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008403 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008404 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008405 break;
8406#endif
bellard31e31b82003-02-18 22:55:36 +00008407 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008408 /* Note that negative values are valid for getpriority, so we must
8409 differentiate based on errno settings. */
8410 errno = 0;
8411 ret = getpriority(arg1, arg2);
8412 if (ret == -1 && errno != 0) {
8413 ret = -host_to_target_errno(errno);
8414 break;
8415 }
8416#ifdef TARGET_ALPHA
8417 /* Return value is the unbiased priority. Signal no error. */
8418 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8419#else
8420 /* Return value is a biased priority to avoid negative numbers. */
8421 ret = 20 - ret;
8422#endif
bellard31e31b82003-02-18 22:55:36 +00008423 break;
8424 case TARGET_NR_setpriority:
8425 ret = get_errno(setpriority(arg1, arg2, arg3));
8426 break;
bellardebc05482003-09-30 21:08:41 +00008427#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008428 case TARGET_NR_profil:
8429 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008430#endif
bellard31e31b82003-02-18 22:55:36 +00008431 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008432 if (!(p = lock_user_string(arg1)))
8433 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008434 ret = get_errno(statfs(path(p), &stfs));
8435 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008436 convert_statfs:
8437 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008438 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008439
bellard579a97f2007-11-11 14:26:47 +00008440 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8441 goto efault;
8442 __put_user(stfs.f_type, &target_stfs->f_type);
8443 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8444 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8445 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8446 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8447 __put_user(stfs.f_files, &target_stfs->f_files);
8448 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8449 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8450 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8451 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008452 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8453 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008454 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008455 }
8456 break;
8457 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008458 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008459 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008460#ifdef TARGET_NR_statfs64
8461 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008462 if (!(p = lock_user_string(arg1)))
8463 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008464 ret = get_errno(statfs(path(p), &stfs));
8465 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008466 convert_statfs64:
8467 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008468 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008469
bellard579a97f2007-11-11 14:26:47 +00008470 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8471 goto efault;
8472 __put_user(stfs.f_type, &target_stfs->f_type);
8473 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8474 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8475 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8476 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8477 __put_user(stfs.f_files, &target_stfs->f_files);
8478 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8479 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8480 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8481 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008482 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8483 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008484 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008485 }
8486 break;
8487 case TARGET_NR_fstatfs64:
8488 ret = get_errno(fstatfs(arg1, &stfs));
8489 goto convert_statfs64;
8490#endif
bellardebc05482003-09-30 21:08:41 +00008491#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008492 case TARGET_NR_ioperm:
8493 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008494#endif
thse5febef2007-04-01 18:31:35 +00008495#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008496 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008497 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008498 break;
thse5febef2007-04-01 18:31:35 +00008499#endif
bellard3532fa72006-06-24 15:06:03 +00008500#ifdef TARGET_NR_accept
8501 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008502 ret = do_accept4(arg1, arg2, arg3, 0);
8503 break;
8504#endif
8505#ifdef TARGET_NR_accept4
8506 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00008507 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008508 break;
8509#endif
8510#ifdef TARGET_NR_bind
8511 case TARGET_NR_bind:
8512 ret = do_bind(arg1, arg2, arg3);
8513 break;
8514#endif
8515#ifdef TARGET_NR_connect
8516 case TARGET_NR_connect:
8517 ret = do_connect(arg1, arg2, arg3);
8518 break;
8519#endif
8520#ifdef TARGET_NR_getpeername
8521 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008522 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008523 break;
8524#endif
8525#ifdef TARGET_NR_getsockname
8526 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008527 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008528 break;
8529#endif
8530#ifdef TARGET_NR_getsockopt
8531 case TARGET_NR_getsockopt:
8532 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8533 break;
8534#endif
8535#ifdef TARGET_NR_listen
8536 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008537 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008538 break;
8539#endif
8540#ifdef TARGET_NR_recv
8541 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008542 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008543 break;
8544#endif
8545#ifdef TARGET_NR_recvfrom
8546 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008547 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008548 break;
8549#endif
8550#ifdef TARGET_NR_recvmsg
8551 case TARGET_NR_recvmsg:
8552 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8553 break;
8554#endif
8555#ifdef TARGET_NR_send
8556 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008557 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008558 break;
8559#endif
8560#ifdef TARGET_NR_sendmsg
8561 case TARGET_NR_sendmsg:
8562 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8563 break;
8564#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008565#ifdef TARGET_NR_sendmmsg
8566 case TARGET_NR_sendmmsg:
8567 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8568 break;
8569 case TARGET_NR_recvmmsg:
8570 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8571 break;
8572#endif
bellard3532fa72006-06-24 15:06:03 +00008573#ifdef TARGET_NR_sendto
8574 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008575 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008576 break;
8577#endif
8578#ifdef TARGET_NR_shutdown
8579 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008580 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008581 break;
8582#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008583#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8584 case TARGET_NR_getrandom:
8585 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8586 if (!p) {
8587 goto efault;
8588 }
8589 ret = get_errno(getrandom(p, arg2, arg3));
8590 unlock_user(p, arg1, ret);
8591 break;
8592#endif
bellard3532fa72006-06-24 15:06:03 +00008593#ifdef TARGET_NR_socket
8594 case TARGET_NR_socket:
8595 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008596 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008597 break;
8598#endif
8599#ifdef TARGET_NR_socketpair
8600 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008601 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008602 break;
8603#endif
8604#ifdef TARGET_NR_setsockopt
8605 case TARGET_NR_setsockopt:
8606 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8607 break;
8608#endif
ths7494b0f2007-02-11 18:26:53 +00008609
bellard31e31b82003-02-18 22:55:36 +00008610 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008611 if (!(p = lock_user_string(arg2)))
8612 goto efault;
thse5574482007-02-11 20:03:13 +00008613 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8614 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008615 break;
8616
bellard31e31b82003-02-18 22:55:36 +00008617 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008618 {
bellard66fb9762003-03-23 01:06:05 +00008619 struct itimerval value, ovalue, *pvalue;
8620
pbrook53a59602006-03-25 19:31:22 +00008621 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008622 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008623 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8624 || copy_from_user_timeval(&pvalue->it_value,
8625 arg2 + sizeof(struct target_timeval)))
8626 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008627 } else {
8628 pvalue = NULL;
8629 }
8630 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008631 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008632 if (copy_to_user_timeval(arg3,
8633 &ovalue.it_interval)
8634 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8635 &ovalue.it_value))
8636 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008637 }
8638 }
8639 break;
bellard31e31b82003-02-18 22:55:36 +00008640 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008641 {
bellard66fb9762003-03-23 01:06:05 +00008642 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008643
bellard66fb9762003-03-23 01:06:05 +00008644 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008645 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008646 if (copy_to_user_timeval(arg2,
8647 &value.it_interval)
8648 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8649 &value.it_value))
8650 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008651 }
8652 }
8653 break;
Chen Gang704eff62015-08-21 05:37:33 +08008654#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008655 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008656 if (!(p = lock_user_string(arg1)))
8657 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008658 ret = get_errno(stat(path(p), &st));
8659 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008660 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008661#endif
8662#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008663 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008664 if (!(p = lock_user_string(arg1)))
8665 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008666 ret = get_errno(lstat(path(p), &st));
8667 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008668 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008669#endif
bellard31e31b82003-02-18 22:55:36 +00008670 case TARGET_NR_fstat:
8671 {
8672 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008673#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008674 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008675#endif
bellard31e31b82003-02-18 22:55:36 +00008676 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008677 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008678
bellard579a97f2007-11-11 14:26:47 +00008679 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8680 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008681 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008682 __put_user(st.st_dev, &target_st->st_dev);
8683 __put_user(st.st_ino, &target_st->st_ino);
8684 __put_user(st.st_mode, &target_st->st_mode);
8685 __put_user(st.st_uid, &target_st->st_uid);
8686 __put_user(st.st_gid, &target_st->st_gid);
8687 __put_user(st.st_nlink, &target_st->st_nlink);
8688 __put_user(st.st_rdev, &target_st->st_rdev);
8689 __put_user(st.st_size, &target_st->st_size);
8690 __put_user(st.st_blksize, &target_st->st_blksize);
8691 __put_user(st.st_blocks, &target_st->st_blocks);
8692 __put_user(st.st_atime, &target_st->target_st_atime);
8693 __put_user(st.st_mtime, &target_st->target_st_mtime);
8694 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008695 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008696 }
8697 }
8698 break;
bellardebc05482003-09-30 21:08:41 +00008699#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008700 case TARGET_NR_olduname:
8701 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008702#endif
8703#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008704 case TARGET_NR_iopl:
8705 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008706#endif
bellard31e31b82003-02-18 22:55:36 +00008707 case TARGET_NR_vhangup:
8708 ret = get_errno(vhangup());
8709 break;
bellardebc05482003-09-30 21:08:41 +00008710#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008711 case TARGET_NR_idle:
8712 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008713#endif
bellard42ad6ae2005-01-03 22:48:11 +00008714#ifdef TARGET_NR_syscall
8715 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008716 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8717 arg6, arg7, arg8, 0);
8718 break;
bellard42ad6ae2005-01-03 22:48:11 +00008719#endif
bellard31e31b82003-02-18 22:55:36 +00008720 case TARGET_NR_wait4:
8721 {
8722 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008723 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008724 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008725 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008726 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008727 if (target_rusage)
8728 rusage_ptr = &rusage;
8729 else
8730 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008731 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008732 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008733 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008734 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008735 if (put_user_s32(status, status_ptr))
8736 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008737 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008738 if (target_rusage) {
8739 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8740 if (rusage_err) {
8741 ret = rusage_err;
8742 }
8743 }
bellard31e31b82003-02-18 22:55:36 +00008744 }
8745 }
8746 break;
thse5febef2007-04-01 18:31:35 +00008747#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008748 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008749 if (!(p = lock_user_string(arg1)))
8750 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008751 ret = get_errno(swapoff(p));
8752 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008753 break;
thse5febef2007-04-01 18:31:35 +00008754#endif
bellard31e31b82003-02-18 22:55:36 +00008755 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008756 {
pbrook53a59602006-03-25 19:31:22 +00008757 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008758 struct sysinfo value;
8759 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008760 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008761 {
bellard579a97f2007-11-11 14:26:47 +00008762 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8763 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008764 __put_user(value.uptime, &target_value->uptime);
8765 __put_user(value.loads[0], &target_value->loads[0]);
8766 __put_user(value.loads[1], &target_value->loads[1]);
8767 __put_user(value.loads[2], &target_value->loads[2]);
8768 __put_user(value.totalram, &target_value->totalram);
8769 __put_user(value.freeram, &target_value->freeram);
8770 __put_user(value.sharedram, &target_value->sharedram);
8771 __put_user(value.bufferram, &target_value->bufferram);
8772 __put_user(value.totalswap, &target_value->totalswap);
8773 __put_user(value.freeswap, &target_value->freeswap);
8774 __put_user(value.procs, &target_value->procs);
8775 __put_user(value.totalhigh, &target_value->totalhigh);
8776 __put_user(value.freehigh, &target_value->freehigh);
8777 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008778 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008779 }
8780 }
8781 break;
thse5febef2007-04-01 18:31:35 +00008782#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008783 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008784 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8785 break;
thse5febef2007-04-01 18:31:35 +00008786#endif
aurel32e5289082009-04-18 16:16:12 +00008787#ifdef TARGET_NR_semget
8788 case TARGET_NR_semget:
8789 ret = get_errno(semget(arg1, arg2, arg3));
8790 break;
8791#endif
8792#ifdef TARGET_NR_semop
8793 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008794 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008795 break;
8796#endif
8797#ifdef TARGET_NR_semctl
8798 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008799 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008800 break;
8801#endif
aurel32eeb438c2008-10-13 21:08:55 +00008802#ifdef TARGET_NR_msgctl
8803 case TARGET_NR_msgctl:
8804 ret = do_msgctl(arg1, arg2, arg3);
8805 break;
8806#endif
8807#ifdef TARGET_NR_msgget
8808 case TARGET_NR_msgget:
8809 ret = get_errno(msgget(arg1, arg2));
8810 break;
8811#endif
8812#ifdef TARGET_NR_msgrcv
8813 case TARGET_NR_msgrcv:
8814 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8815 break;
8816#endif
8817#ifdef TARGET_NR_msgsnd
8818 case TARGET_NR_msgsnd:
8819 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8820 break;
8821#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008822#ifdef TARGET_NR_shmget
8823 case TARGET_NR_shmget:
8824 ret = get_errno(shmget(arg1, arg2, arg3));
8825 break;
8826#endif
8827#ifdef TARGET_NR_shmctl
8828 case TARGET_NR_shmctl:
8829 ret = do_shmctl(arg1, arg2, arg3);
8830 break;
8831#endif
8832#ifdef TARGET_NR_shmat
8833 case TARGET_NR_shmat:
8834 ret = do_shmat(arg1, arg2, arg3);
8835 break;
8836#endif
8837#ifdef TARGET_NR_shmdt
8838 case TARGET_NR_shmdt:
8839 ret = do_shmdt(arg1);
8840 break;
8841#endif
bellard31e31b82003-02-18 22:55:36 +00008842 case TARGET_NR_fsync:
8843 ret = get_errno(fsync(arg1));
8844 break;
bellard31e31b82003-02-18 22:55:36 +00008845 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008846 /* Linux manages to have three different orderings for its
8847 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8848 * match the kernel's CONFIG_CLONE_* settings.
8849 * Microblaze is further special in that it uses a sixth
8850 * implicit argument to clone for the TLS pointer.
8851 */
8852#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008853 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008854#elif defined(TARGET_CLONE_BACKWARDS)
8855 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8856#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008857 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008858#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008859 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008860#endif
bellard1b6b0292003-03-22 17:31:38 +00008861 break;
bellardec86b0f2003-04-11 00:15:04 +00008862#ifdef __NR_exit_group
8863 /* new thread calls */
8864 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008865#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008866 _mcleanup();
8867#endif
bellarde9009672005-04-26 20:42:36 +00008868 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008869 ret = get_errno(exit_group(arg1));
8870 break;
8871#endif
bellard31e31b82003-02-18 22:55:36 +00008872 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008873 if (!(p = lock_user_string(arg1)))
8874 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008875 ret = get_errno(setdomainname(p, arg2));
8876 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008877 break;
8878 case TARGET_NR_uname:
8879 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008880 {
8881 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008882
bellard579a97f2007-11-11 14:26:47 +00008883 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8884 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008885 ret = get_errno(sys_uname(buf));
8886 if (!is_error(ret)) {
8887 /* Overrite the native machine name with whatever is being
8888 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01008889 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008890 /* Allow the user to override the reported release. */
8891 if (qemu_uname_release && *qemu_uname_release)
8892 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008893 }
pbrook53a59602006-03-25 19:31:22 +00008894 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008895 }
bellard31e31b82003-02-18 22:55:36 +00008896 break;
bellard6dbad632003-03-16 18:05:05 +00008897#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008898 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008899 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008900 break;
j_mayer84409dd2007-04-06 08:56:50 +00008901#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008902 case TARGET_NR_vm86old:
8903 goto unimplemented;
8904 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008905 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008906 break;
8907#endif
j_mayer84409dd2007-04-06 08:56:50 +00008908#endif
bellard31e31b82003-02-18 22:55:36 +00008909 case TARGET_NR_adjtimex:
8910 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008911#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008912 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008913#endif
bellard31e31b82003-02-18 22:55:36 +00008914 case TARGET_NR_init_module:
8915 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008916#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008917 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008918#endif
bellard31e31b82003-02-18 22:55:36 +00008919 goto unimplemented;
8920 case TARGET_NR_quotactl:
8921 goto unimplemented;
8922 case TARGET_NR_getpgid:
8923 ret = get_errno(getpgid(arg1));
8924 break;
8925 case TARGET_NR_fchdir:
8926 ret = get_errno(fchdir(arg1));
8927 break;
j_mayer84409dd2007-04-06 08:56:50 +00008928#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008929 case TARGET_NR_bdflush:
8930 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008931#endif
thse5febef2007-04-01 18:31:35 +00008932#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008933 case TARGET_NR_sysfs:
8934 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008935#endif
bellard31e31b82003-02-18 22:55:36 +00008936 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008937 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008938 break;
thse5febef2007-04-01 18:31:35 +00008939#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008940 case TARGET_NR_afs_syscall:
8941 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008942#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008943#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008944 case TARGET_NR__llseek:
8945 {
8946 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008947#if !defined(__NR_llseek)
8948 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8949 if (res == -1) {
8950 ret = get_errno(res);
8951 } else {
8952 ret = 0;
8953 }
8954#else
bellard31e31b82003-02-18 22:55:36 +00008955 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008956#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008957 if ((ret == 0) && put_user_s64(res, arg4)) {
8958 goto efault;
8959 }
bellard31e31b82003-02-18 22:55:36 +00008960 }
8961 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008962#endif
Chen Gang704eff62015-08-21 05:37:33 +08008963#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008964 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008965#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008966#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008967 {
pbrook53a59602006-03-25 19:31:22 +00008968 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008969 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008970 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008971
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308972 dirp = g_try_malloc(count);
8973 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008974 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008975 goto fail;
8976 }
ths3b46e622007-09-17 08:09:54 +00008977
bellard4add45b2003-06-05 01:52:59 +00008978 ret = get_errno(sys_getdents(arg1, dirp, count));
8979 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008980 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008981 struct target_dirent *tde;
8982 int len = ret;
8983 int reclen, treclen;
8984 int count1, tnamelen;
8985
8986 count1 = 0;
8987 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008988 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8989 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008990 tde = target_dirp;
8991 while (len > 0) {
8992 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008993 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8994 assert(tnamelen >= 0);
8995 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8996 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008997 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008998 tde->d_ino = tswapal(de->d_ino);
8999 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009000 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009001 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009002 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009003 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009004 count1 += treclen;
9005 }
9006 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009007 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009008 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309009 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009010 }
9011#else
bellard31e31b82003-02-18 22:55:36 +00009012 {
aurel326556a832008-10-13 21:08:17 +00009013 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009014 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009015
bellard579a97f2007-11-11 14:26:47 +00009016 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9017 goto efault;
bellard72f03902003-02-18 23:33:18 +00009018 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009019 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009020 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00009021 int len = ret;
9022 int reclen;
9023 de = dirp;
9024 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009025 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009026 if (reclen > len)
9027 break;
bellard8083a3e2003-03-24 23:12:16 +00009028 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009029 tswapls(&de->d_ino);
9030 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009031 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009032 len -= reclen;
9033 }
9034 }
pbrook53a59602006-03-25 19:31:22 +00009035 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009036 }
bellard4add45b2003-06-05 01:52:59 +00009037#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009038#else
9039 /* Implement getdents in terms of getdents64 */
9040 {
9041 struct linux_dirent64 *dirp;
9042 abi_long count = arg3;
9043
9044 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9045 if (!dirp) {
9046 goto efault;
9047 }
9048 ret = get_errno(sys_getdents64(arg1, dirp, count));
9049 if (!is_error(ret)) {
9050 /* Convert the dirent64 structs to target dirent. We do this
9051 * in-place, since we can guarantee that a target_dirent is no
9052 * larger than a dirent64; however this means we have to be
9053 * careful to read everything before writing in the new format.
9054 */
9055 struct linux_dirent64 *de;
9056 struct target_dirent *tde;
9057 int len = ret;
9058 int tlen = 0;
9059
9060 de = dirp;
9061 tde = (struct target_dirent *)dirp;
9062 while (len > 0) {
9063 int namelen, treclen;
9064 int reclen = de->d_reclen;
9065 uint64_t ino = de->d_ino;
9066 int64_t off = de->d_off;
9067 uint8_t type = de->d_type;
9068
9069 namelen = strlen(de->d_name);
9070 treclen = offsetof(struct target_dirent, d_name)
9071 + namelen + 2;
9072 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9073
9074 memmove(tde->d_name, de->d_name, namelen + 1);
9075 tde->d_ino = tswapal(ino);
9076 tde->d_off = tswapal(off);
9077 tde->d_reclen = tswap16(treclen);
9078 /* The target_dirent type is in what was formerly a padding
9079 * byte at the end of the structure:
9080 */
9081 *(((char *)tde) + treclen - 1) = type;
9082
9083 de = (struct linux_dirent64 *)((char *)de + reclen);
9084 tde = (struct target_dirent *)((char *)tde + treclen);
9085 len -= reclen;
9086 tlen += treclen;
9087 }
9088 ret = tlen;
9089 }
9090 unlock_user(dirp, arg2, ret);
9091 }
9092#endif
bellard31e31b82003-02-18 22:55:36 +00009093 break;
Chen Gang704eff62015-08-21 05:37:33 +08009094#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009095#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009096 case TARGET_NR_getdents64:
9097 {
aurel326556a832008-10-13 21:08:17 +00009098 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009099 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009100 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9101 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009102 ret = get_errno(sys_getdents64(arg1, dirp, count));
9103 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009104 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009105 int len = ret;
9106 int reclen;
9107 de = dirp;
9108 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009109 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009110 if (reclen > len)
9111 break;
bellard8083a3e2003-03-24 23:12:16 +00009112 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009113 tswap64s((uint64_t *)&de->d_ino);
9114 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009115 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009116 len -= reclen;
9117 }
9118 }
pbrook53a59602006-03-25 19:31:22 +00009119 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009120 }
9121 break;
bellarda541f292004-04-12 20:39:29 +00009122#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009123#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009124 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009125 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009126 break;
thse5febef2007-04-01 18:31:35 +00009127#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009128#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9129# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009130 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009131# endif
9132# ifdef TARGET_NR_ppoll
9133 case TARGET_NR_ppoll:
9134# endif
bellard9de5e442003-03-23 16:49:39 +00009135 {
pbrook53a59602006-03-25 19:31:22 +00009136 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009137 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009138 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009139 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009140
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009141 pfd = NULL;
9142 target_pfd = NULL;
9143 if (nfds) {
9144 target_pfd = lock_user(VERIFY_WRITE, arg1,
9145 sizeof(struct target_pollfd) * nfds, 1);
9146 if (!target_pfd) {
9147 goto efault;
9148 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009149
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009150 pfd = alloca(sizeof(struct pollfd) * nfds);
9151 for (i = 0; i < nfds; i++) {
9152 pfd[i].fd = tswap32(target_pfd[i].fd);
9153 pfd[i].events = tswap16(target_pfd[i].events);
9154 }
bellard9de5e442003-03-23 16:49:39 +00009155 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009156
Peter Maydella6130232016-06-06 19:58:10 +01009157 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009158# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009159 case TARGET_NR_ppoll:
9160 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009161 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9162 target_sigset_t *target_set;
9163 sigset_t _set, *set = &_set;
9164
9165 if (arg3) {
9166 if (target_to_host_timespec(timeout_ts, arg3)) {
9167 unlock_user(target_pfd, arg1, 0);
9168 goto efault;
9169 }
9170 } else {
9171 timeout_ts = NULL;
9172 }
9173
9174 if (arg4) {
9175 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9176 if (!target_set) {
9177 unlock_user(target_pfd, arg1, 0);
9178 goto efault;
9179 }
9180 target_to_host_sigset(set, target_set);
9181 } else {
9182 set = NULL;
9183 }
9184
Peter Maydella6130232016-06-06 19:58:10 +01009185 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9186 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009187
9188 if (!is_error(ret) && arg3) {
9189 host_to_target_timespec(arg3, timeout_ts);
9190 }
9191 if (arg4) {
9192 unlock_user(target_set, arg4, 0);
9193 }
Peter Maydella6130232016-06-06 19:58:10 +01009194 break;
9195 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009196# endif
Peter Maydella6130232016-06-06 19:58:10 +01009197# ifdef TARGET_NR_poll
9198 case TARGET_NR_poll:
9199 {
9200 struct timespec ts, *pts;
9201
9202 if (arg3 >= 0) {
9203 /* Convert ms to secs, ns */
9204 ts.tv_sec = arg3 / 1000;
9205 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9206 pts = &ts;
9207 } else {
9208 /* -ve poll() timeout means "infinite" */
9209 pts = NULL;
9210 }
9211 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9212 break;
9213 }
9214# endif
9215 default:
9216 g_assert_not_reached();
9217 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009218
bellard9de5e442003-03-23 16:49:39 +00009219 if (!is_error(ret)) {
9220 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009221 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009222 }
9223 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009224 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009225 }
9226 break;
thse5febef2007-04-01 18:31:35 +00009227#endif
bellard31e31b82003-02-18 22:55:36 +00009228 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009229 /* NOTE: the flock constant seems to be the same for every
9230 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009231 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009232 break;
9233 case TARGET_NR_readv:
9234 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009235 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9236 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009237 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009238 unlock_iovec(vec, arg2, arg3, 1);
9239 } else {
9240 ret = -host_to_target_errno(errno);
9241 }
bellard31e31b82003-02-18 22:55:36 +00009242 }
9243 break;
9244 case TARGET_NR_writev:
9245 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009246 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9247 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009248 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009249 unlock_iovec(vec, arg2, arg3, 0);
9250 } else {
9251 ret = -host_to_target_errno(errno);
9252 }
bellard31e31b82003-02-18 22:55:36 +00009253 }
9254 break;
9255 case TARGET_NR_getsid:
9256 ret = get_errno(getsid(arg1));
9257 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009258#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009259 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009260 ret = get_errno(fdatasync(arg1));
9261 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009262#endif
Chen Gang704eff62015-08-21 05:37:33 +08009263#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009264 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009265 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009266 return value. */
ths0da46a62007-10-20 20:23:07 +00009267 ret = -TARGET_ENOTDIR;
9268 break;
Chen Gang704eff62015-08-21 05:37:33 +08009269#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009270 case TARGET_NR_sched_getaffinity:
9271 {
9272 unsigned int mask_size;
9273 unsigned long *mask;
9274
9275 /*
9276 * sched_getaffinity needs multiples of ulong, so need to take
9277 * care of mismatches between target ulong and host ulong sizes.
9278 */
9279 if (arg2 & (sizeof(abi_ulong) - 1)) {
9280 ret = -TARGET_EINVAL;
9281 break;
9282 }
9283 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9284
9285 mask = alloca(mask_size);
9286 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9287
9288 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009289 if (ret > arg2) {
9290 /* More data returned than the caller's buffer will fit.
9291 * This only happens if sizeof(abi_long) < sizeof(long)
9292 * and the caller passed us a buffer holding an odd number
9293 * of abi_longs. If the host kernel is actually using the
9294 * extra 4 bytes then fail EINVAL; otherwise we can just
9295 * ignore them and only copy the interesting part.
9296 */
9297 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9298 if (numcpus > arg2 * 8) {
9299 ret = -TARGET_EINVAL;
9300 break;
9301 }
9302 ret = arg2;
9303 }
9304
Mike McCormackcd18f052011-04-18 14:43:36 +09009305 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009306 goto efault;
9307 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009308 }
9309 }
9310 break;
9311 case TARGET_NR_sched_setaffinity:
9312 {
9313 unsigned int mask_size;
9314 unsigned long *mask;
9315
9316 /*
9317 * sched_setaffinity needs multiples of ulong, so need to take
9318 * care of mismatches between target ulong and host ulong sizes.
9319 */
9320 if (arg2 & (sizeof(abi_ulong) - 1)) {
9321 ret = -TARGET_EINVAL;
9322 break;
9323 }
9324 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9325
9326 mask = alloca(mask_size);
9327 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9328 goto efault;
9329 }
9330 memcpy(mask, p, arg2);
9331 unlock_user_struct(p, arg2, 0);
9332
9333 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9334 }
9335 break;
bellard31e31b82003-02-18 22:55:36 +00009336 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009337 {
pbrook53a59602006-03-25 19:31:22 +00009338 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009339 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009340
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009341 if (arg2 == 0) {
9342 return -TARGET_EINVAL;
9343 }
bellard579a97f2007-11-11 14:26:47 +00009344 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9345 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009346 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009347 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009348 ret = get_errno(sched_setparam(arg1, &schp));
9349 }
9350 break;
bellard31e31b82003-02-18 22:55:36 +00009351 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009352 {
pbrook53a59602006-03-25 19:31:22 +00009353 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009354 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009355
9356 if (arg2 == 0) {
9357 return -TARGET_EINVAL;
9358 }
bellard5cd43932003-03-29 16:54:36 +00009359 ret = get_errno(sched_getparam(arg1, &schp));
9360 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009361 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9362 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009363 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009364 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009365 }
9366 }
9367 break;
bellard31e31b82003-02-18 22:55:36 +00009368 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009369 {
pbrook53a59602006-03-25 19:31:22 +00009370 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009371 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009372 if (arg3 == 0) {
9373 return -TARGET_EINVAL;
9374 }
bellard579a97f2007-11-11 14:26:47 +00009375 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9376 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009377 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009378 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009379 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9380 }
9381 break;
bellard31e31b82003-02-18 22:55:36 +00009382 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009383 ret = get_errno(sched_getscheduler(arg1));
9384 break;
bellard31e31b82003-02-18 22:55:36 +00009385 case TARGET_NR_sched_yield:
9386 ret = get_errno(sched_yield());
9387 break;
9388 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009389 ret = get_errno(sched_get_priority_max(arg1));
9390 break;
bellard31e31b82003-02-18 22:55:36 +00009391 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009392 ret = get_errno(sched_get_priority_min(arg1));
9393 break;
bellard31e31b82003-02-18 22:55:36 +00009394 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009395 {
bellard5cd43932003-03-29 16:54:36 +00009396 struct timespec ts;
9397 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9398 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009399 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009400 }
9401 }
9402 break;
bellard31e31b82003-02-18 22:55:36 +00009403 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009404 {
bellard1b6b0292003-03-22 17:31:38 +00009405 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009406 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009407 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009408 if (is_error(ret) && arg2) {
9409 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009410 }
9411 }
9412 break;
thse5febef2007-04-01 18:31:35 +00009413#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009414 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009415 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009416#endif
9417#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009418 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009419 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009420#endif
bellard31e31b82003-02-18 22:55:36 +00009421 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009422 switch (arg1) {
9423 case PR_GET_PDEATHSIG:
9424 {
9425 int deathsig;
9426 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9427 if (!is_error(ret) && arg2
9428 && put_user_ual(deathsig, arg2)) {
9429 goto efault;
thse5574482007-02-11 20:03:13 +00009430 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009431 break;
9432 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009433#ifdef PR_GET_NAME
9434 case PR_GET_NAME:
9435 {
9436 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9437 if (!name) {
9438 goto efault;
9439 }
9440 ret = get_errno(prctl(arg1, (unsigned long)name,
9441 arg3, arg4, arg5));
9442 unlock_user(name, arg2, 16);
9443 break;
9444 }
9445 case PR_SET_NAME:
9446 {
9447 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9448 if (!name) {
9449 goto efault;
9450 }
9451 ret = get_errno(prctl(arg1, (unsigned long)name,
9452 arg3, arg4, arg5));
9453 unlock_user(name, arg2, 0);
9454 break;
9455 }
9456#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009457 default:
9458 /* Most prctl options have no pointer arguments */
9459 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9460 break;
9461 }
ths39b9aae2007-02-11 18:36:44 +00009462 break;
bellardd2fd1af2007-11-14 18:08:56 +00009463#ifdef TARGET_NR_arch_prctl
9464 case TARGET_NR_arch_prctl:
9465#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9466 ret = do_arch_prctl(cpu_env, arg1, arg2);
9467 break;
9468#else
9469 goto unimplemented;
9470#endif
9471#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009472#ifdef TARGET_NR_pread64
9473 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009474 if (regpairs_aligned(cpu_env)) {
9475 arg4 = arg5;
9476 arg5 = arg6;
9477 }
aurel32f2c7ba12008-03-28 22:32:06 +00009478 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9479 goto efault;
9480 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9481 unlock_user(p, arg2, ret);
9482 break;
9483 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009484 if (regpairs_aligned(cpu_env)) {
9485 arg4 = arg5;
9486 arg5 = arg6;
9487 }
aurel32f2c7ba12008-03-28 22:32:06 +00009488 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9489 goto efault;
9490 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9491 unlock_user(p, arg2, 0);
9492 break;
9493#endif
bellard31e31b82003-02-18 22:55:36 +00009494 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009495 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9496 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009497 ret = get_errno(sys_getcwd1(p, arg2));
9498 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009499 break;
9500 case TARGET_NR_capget:
9501 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009502 {
9503 struct target_user_cap_header *target_header;
9504 struct target_user_cap_data *target_data = NULL;
9505 struct __user_cap_header_struct header;
9506 struct __user_cap_data_struct data[2];
9507 struct __user_cap_data_struct *dataptr = NULL;
9508 int i, target_datalen;
9509 int data_items = 1;
9510
9511 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9512 goto efault;
9513 }
9514 header.version = tswap32(target_header->version);
9515 header.pid = tswap32(target_header->pid);
9516
Peter Maydellec864872014-03-19 16:07:30 +00009517 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009518 /* Version 2 and up takes pointer to two user_data structs */
9519 data_items = 2;
9520 }
9521
9522 target_datalen = sizeof(*target_data) * data_items;
9523
9524 if (arg2) {
9525 if (num == TARGET_NR_capget) {
9526 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9527 } else {
9528 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9529 }
9530 if (!target_data) {
9531 unlock_user_struct(target_header, arg1, 0);
9532 goto efault;
9533 }
9534
9535 if (num == TARGET_NR_capset) {
9536 for (i = 0; i < data_items; i++) {
9537 data[i].effective = tswap32(target_data[i].effective);
9538 data[i].permitted = tswap32(target_data[i].permitted);
9539 data[i].inheritable = tswap32(target_data[i].inheritable);
9540 }
9541 }
9542
9543 dataptr = data;
9544 }
9545
9546 if (num == TARGET_NR_capget) {
9547 ret = get_errno(capget(&header, dataptr));
9548 } else {
9549 ret = get_errno(capset(&header, dataptr));
9550 }
9551
9552 /* The kernel always updates version for both capget and capset */
9553 target_header->version = tswap32(header.version);
9554 unlock_user_struct(target_header, arg1, 1);
9555
9556 if (arg2) {
9557 if (num == TARGET_NR_capget) {
9558 for (i = 0; i < data_items; i++) {
9559 target_data[i].effective = tswap32(data[i].effective);
9560 target_data[i].permitted = tswap32(data[i].permitted);
9561 target_data[i].inheritable = tswap32(data[i].inheritable);
9562 }
9563 unlock_user(target_data, arg2, target_datalen);
9564 } else {
9565 unlock_user(target_data, arg2, 0);
9566 }
9567 }
9568 break;
9569 }
bellard31e31b82003-02-18 22:55:36 +00009570 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009571 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009572 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009573
9574#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009575 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009576 {
9577 off_t *offp = NULL;
9578 off_t off;
9579 if (arg3) {
9580 ret = get_user_sal(off, arg3);
9581 if (is_error(ret)) {
9582 break;
9583 }
9584 offp = &off;
9585 }
9586 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9587 if (!is_error(ret) && arg3) {
9588 abi_long ret2 = put_user_sal(off, arg3);
9589 if (is_error(ret2)) {
9590 ret = ret2;
9591 }
9592 }
9593 break;
9594 }
9595#ifdef TARGET_NR_sendfile64
9596 case TARGET_NR_sendfile64:
9597 {
9598 off_t *offp = NULL;
9599 off_t off;
9600 if (arg3) {
9601 ret = get_user_s64(off, arg3);
9602 if (is_error(ret)) {
9603 break;
9604 }
9605 offp = &off;
9606 }
9607 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9608 if (!is_error(ret) && arg3) {
9609 abi_long ret2 = put_user_s64(off, arg3);
9610 if (is_error(ret2)) {
9611 ret = ret2;
9612 }
9613 }
9614 break;
9615 }
9616#endif
9617#else
9618 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009619#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009620 case TARGET_NR_sendfile64:
9621#endif
bellard5cd43932003-03-29 16:54:36 +00009622 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009623#endif
9624
bellardebc05482003-09-30 21:08:41 +00009625#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009626 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009627 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009628#endif
9629#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009630 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009631 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009632#endif
bellard048f6b42005-11-26 18:47:20 +00009633#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009634 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009635 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9636 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009637 break;
bellard048f6b42005-11-26 18:47:20 +00009638#endif
bellardebc05482003-09-30 21:08:41 +00009639#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009640 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009641 {
9642 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009643 int resource = target_to_host_resource(arg1);
9644 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009645 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009646 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009647 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9648 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009649 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9650 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009651 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009652 }
9653 break;
9654 }
bellardebc05482003-09-30 21:08:41 +00009655#endif
bellarda315a142005-01-30 22:59:18 +00009656#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009657 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009658 if (!(p = lock_user_string(arg1)))
9659 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009660 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9661 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009662 break;
bellarda315a142005-01-30 22:59:18 +00009663#endif
9664#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009665 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009666 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009667 break;
bellarda315a142005-01-30 22:59:18 +00009668#endif
9669#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009670 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009671 if (!(p = lock_user_string(arg1)))
9672 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009673 ret = get_errno(stat(path(p), &st));
9674 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009675 if (!is_error(ret))
9676 ret = host_to_target_stat64(cpu_env, arg2, &st);
9677 break;
bellarda315a142005-01-30 22:59:18 +00009678#endif
9679#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009680 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009681 if (!(p = lock_user_string(arg1)))
9682 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009683 ret = get_errno(lstat(path(p), &st));
9684 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009685 if (!is_error(ret))
9686 ret = host_to_target_stat64(cpu_env, arg2, &st);
9687 break;
bellarda315a142005-01-30 22:59:18 +00009688#endif
9689#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009690 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009691 ret = get_errno(fstat(arg1, &st));
9692 if (!is_error(ret))
9693 ret = host_to_target_stat64(cpu_env, arg2, &st);
9694 break;
bellardec86b0f2003-04-11 00:15:04 +00009695#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009696#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009697#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009698 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009699#endif
9700#ifdef TARGET_NR_newfstatat
9701 case TARGET_NR_newfstatat:
9702#endif
balrog6a24a772008-09-20 02:23:36 +00009703 if (!(p = lock_user_string(arg2)))
9704 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009705 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009706 if (!is_error(ret))
9707 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009708 break;
bellarda315a142005-01-30 22:59:18 +00009709#endif
Chen Gang704eff62015-08-21 05:37:33 +08009710#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009711 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009712 if (!(p = lock_user_string(arg1)))
9713 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009714 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9715 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009716 break;
Chen Gang704eff62015-08-21 05:37:33 +08009717#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009718#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009719 case TARGET_NR_getuid:
9720 ret = get_errno(high2lowuid(getuid()));
9721 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009722#endif
9723#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009724 case TARGET_NR_getgid:
9725 ret = get_errno(high2lowgid(getgid()));
9726 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009727#endif
9728#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009729 case TARGET_NR_geteuid:
9730 ret = get_errno(high2lowuid(geteuid()));
9731 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009732#endif
9733#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009734 case TARGET_NR_getegid:
9735 ret = get_errno(high2lowgid(getegid()));
9736 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009737#endif
bellard67867302003-11-23 17:05:30 +00009738 case TARGET_NR_setreuid:
9739 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9740 break;
9741 case TARGET_NR_setregid:
9742 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9743 break;
9744 case TARGET_NR_getgroups:
9745 {
9746 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009747 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009748 gid_t *grouplist;
9749 int i;
9750
9751 grouplist = alloca(gidsetsize * sizeof(gid_t));
9752 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009753 if (gidsetsize == 0)
9754 break;
bellard67867302003-11-23 17:05:30 +00009755 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009756 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009757 if (!target_grouplist)
9758 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009759 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009760 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009761 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009762 }
9763 }
9764 break;
9765 case TARGET_NR_setgroups:
9766 {
9767 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009768 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009769 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009770 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009771 if (gidsetsize) {
9772 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009773 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009774 if (!target_grouplist) {
9775 ret = -TARGET_EFAULT;
9776 goto fail;
9777 }
9778 for (i = 0; i < gidsetsize; i++) {
9779 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9780 }
9781 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009782 }
bellard67867302003-11-23 17:05:30 +00009783 ret = get_errno(setgroups(gidsetsize, grouplist));
9784 }
9785 break;
9786 case TARGET_NR_fchown:
9787 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9788 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009789#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009790 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009791 if (!(p = lock_user_string(arg2)))
9792 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009793 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9794 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009795 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009796 break;
9797#endif
bellard67867302003-11-23 17:05:30 +00009798#ifdef TARGET_NR_setresuid
9799 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009800 ret = get_errno(sys_setresuid(low2highuid(arg1),
9801 low2highuid(arg2),
9802 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009803 break;
9804#endif
9805#ifdef TARGET_NR_getresuid
9806 case TARGET_NR_getresuid:
9807 {
pbrook53a59602006-03-25 19:31:22 +00009808 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009809 ret = get_errno(getresuid(&ruid, &euid, &suid));
9810 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009811 if (put_user_id(high2lowuid(ruid), arg1)
9812 || put_user_id(high2lowuid(euid), arg2)
9813 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009814 goto efault;
bellard67867302003-11-23 17:05:30 +00009815 }
9816 }
9817 break;
9818#endif
9819#ifdef TARGET_NR_getresgid
9820 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009821 ret = get_errno(sys_setresgid(low2highgid(arg1),
9822 low2highgid(arg2),
9823 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009824 break;
9825#endif
9826#ifdef TARGET_NR_getresgid
9827 case TARGET_NR_getresgid:
9828 {
pbrook53a59602006-03-25 19:31:22 +00009829 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009830 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9831 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009832 if (put_user_id(high2lowgid(rgid), arg1)
9833 || put_user_id(high2lowgid(egid), arg2)
9834 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009835 goto efault;
bellard67867302003-11-23 17:05:30 +00009836 }
9837 }
9838 break;
9839#endif
Chen Gang704eff62015-08-21 05:37:33 +08009840#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009841 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009842 if (!(p = lock_user_string(arg1)))
9843 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009844 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9845 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009846 break;
Chen Gang704eff62015-08-21 05:37:33 +08009847#endif
bellard67867302003-11-23 17:05:30 +00009848 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009849 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009850 break;
9851 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009852 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009853 break;
9854 case TARGET_NR_setfsuid:
9855 ret = get_errno(setfsuid(arg1));
9856 break;
9857 case TARGET_NR_setfsgid:
9858 ret = get_errno(setfsgid(arg1));
9859 break;
bellard67867302003-11-23 17:05:30 +00009860
bellarda315a142005-01-30 22:59:18 +00009861#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009862 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009863 if (!(p = lock_user_string(arg1)))
9864 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009865 ret = get_errno(lchown(p, arg2, arg3));
9866 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009867 break;
bellarda315a142005-01-30 22:59:18 +00009868#endif
9869#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009870 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009871 ret = get_errno(getuid());
9872 break;
bellarda315a142005-01-30 22:59:18 +00009873#endif
aurel3264b4d282008-11-14 17:20:15 +00009874
9875#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9876 /* Alpha specific */
9877 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009878 {
9879 uid_t euid;
9880 euid=geteuid();
9881 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9882 }
aurel3264b4d282008-11-14 17:20:15 +00009883 ret = get_errno(getuid());
9884 break;
9885#endif
9886#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9887 /* Alpha specific */
9888 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009889 {
9890 uid_t egid;
9891 egid=getegid();
9892 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9893 }
aurel3264b4d282008-11-14 17:20:15 +00009894 ret = get_errno(getgid());
9895 break;
9896#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009897#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9898 /* Alpha specific */
9899 case TARGET_NR_osf_getsysinfo:
9900 ret = -TARGET_EOPNOTSUPP;
9901 switch (arg1) {
9902 case TARGET_GSI_IEEE_FP_CONTROL:
9903 {
9904 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9905
9906 /* Copied from linux ieee_fpcr_to_swcr. */
9907 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9908 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9909 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9910 | SWCR_TRAP_ENABLE_DZE
9911 | SWCR_TRAP_ENABLE_OVF);
9912 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9913 | SWCR_TRAP_ENABLE_INE);
9914 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9915 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9916
9917 if (put_user_u64 (swcr, arg2))
9918 goto efault;
9919 ret = 0;
9920 }
9921 break;
9922
9923 /* case GSI_IEEE_STATE_AT_SIGNAL:
9924 -- Not implemented in linux kernel.
9925 case GSI_UACPROC:
9926 -- Retrieves current unaligned access state; not much used.
9927 case GSI_PROC_TYPE:
9928 -- Retrieves implver information; surely not used.
9929 case GSI_GET_HWRPB:
9930 -- Grabs a copy of the HWRPB; surely not used.
9931 */
9932 }
9933 break;
9934#endif
9935#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9936 /* Alpha specific */
9937 case TARGET_NR_osf_setsysinfo:
9938 ret = -TARGET_EOPNOTSUPP;
9939 switch (arg1) {
9940 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009941 {
9942 uint64_t swcr, fpcr, orig_fpcr;
9943
Richard Henderson6e06d512012-06-01 09:08:21 -07009944 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009945 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009946 }
9947 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009948 fpcr = orig_fpcr & FPCR_DYN_MASK;
9949
9950 /* Copied from linux ieee_swcr_to_fpcr. */
9951 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9952 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9953 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9954 | SWCR_TRAP_ENABLE_DZE
9955 | SWCR_TRAP_ENABLE_OVF)) << 48;
9956 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9957 | SWCR_TRAP_ENABLE_INE)) << 57;
9958 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9959 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9960
Richard Henderson6e06d512012-06-01 09:08:21 -07009961 cpu_alpha_store_fpcr(cpu_env, fpcr);
9962 ret = 0;
9963 }
9964 break;
9965
9966 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9967 {
9968 uint64_t exc, fpcr, orig_fpcr;
9969 int si_code;
9970
9971 if (get_user_u64(exc, arg2)) {
9972 goto efault;
9973 }
9974
9975 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9976
9977 /* We only add to the exception status here. */
9978 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9979
9980 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009981 ret = 0;
9982
Richard Henderson6e06d512012-06-01 09:08:21 -07009983 /* Old exceptions are not signaled. */
9984 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009985
Richard Henderson6e06d512012-06-01 09:08:21 -07009986 /* If any exceptions set by this call,
9987 and are unmasked, send a signal. */
9988 si_code = 0;
9989 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9990 si_code = TARGET_FPE_FLTRES;
9991 }
9992 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9993 si_code = TARGET_FPE_FLTUND;
9994 }
9995 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9996 si_code = TARGET_FPE_FLTOVF;
9997 }
9998 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9999 si_code = TARGET_FPE_FLTDIV;
10000 }
10001 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
10002 si_code = TARGET_FPE_FLTINV;
10003 }
10004 if (si_code != 0) {
10005 target_siginfo_t info;
10006 info.si_signo = SIGFPE;
10007 info.si_errno = 0;
10008 info.si_code = si_code;
10009 info._sifields._sigfault._addr
10010 = ((CPUArchState *)cpu_env)->pc;
10011 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010012 }
10013 }
10014 break;
10015
10016 /* case SSI_NVPAIRS:
10017 -- Used with SSIN_UACPROC to enable unaligned accesses.
10018 case SSI_IEEE_STATE_AT_SIGNAL:
10019 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
10020 -- Not implemented in linux kernel
10021 */
10022 }
10023 break;
10024#endif
10025#ifdef TARGET_NR_osf_sigprocmask
10026 /* Alpha specific. */
10027 case TARGET_NR_osf_sigprocmask:
10028 {
10029 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010030 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010031 sigset_t set, oldset;
10032
10033 switch(arg1) {
10034 case TARGET_SIG_BLOCK:
10035 how = SIG_BLOCK;
10036 break;
10037 case TARGET_SIG_UNBLOCK:
10038 how = SIG_UNBLOCK;
10039 break;
10040 case TARGET_SIG_SETMASK:
10041 how = SIG_SETMASK;
10042 break;
10043 default:
10044 ret = -TARGET_EINVAL;
10045 goto fail;
10046 }
10047 mask = arg2;
10048 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010049 ret = do_sigprocmask(how, &set, &oldset);
10050 if (!ret) {
10051 host_to_target_old_sigset(&mask, &oldset);
10052 ret = mask;
10053 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010054 }
10055 break;
10056#endif
aurel3264b4d282008-11-14 17:20:15 +000010057
bellarda315a142005-01-30 22:59:18 +000010058#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010059 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000010060 ret = get_errno(getgid());
10061 break;
bellarda315a142005-01-30 22:59:18 +000010062#endif
10063#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010064 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000010065 ret = get_errno(geteuid());
10066 break;
bellarda315a142005-01-30 22:59:18 +000010067#endif
10068#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010069 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010070 ret = get_errno(getegid());
10071 break;
bellarda315a142005-01-30 22:59:18 +000010072#endif
10073#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010074 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010075 ret = get_errno(setreuid(arg1, arg2));
10076 break;
bellarda315a142005-01-30 22:59:18 +000010077#endif
10078#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010079 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010080 ret = get_errno(setregid(arg1, arg2));
10081 break;
bellarda315a142005-01-30 22:59:18 +000010082#endif
10083#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010084 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010085 {
10086 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010087 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010088 gid_t *grouplist;
10089 int i;
10090
10091 grouplist = alloca(gidsetsize * sizeof(gid_t));
10092 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010093 if (gidsetsize == 0)
10094 break;
bellard99c475a2005-01-31 20:45:13 +000010095 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010096 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10097 if (!target_grouplist) {
10098 ret = -TARGET_EFAULT;
10099 goto fail;
10100 }
balroga2155fc2008-09-20 02:12:08 +000010101 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010102 target_grouplist[i] = tswap32(grouplist[i]);
10103 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010104 }
10105 }
10106 break;
bellarda315a142005-01-30 22:59:18 +000010107#endif
10108#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010109 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010110 {
10111 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010112 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010113 gid_t *grouplist;
10114 int i;
ths3b46e622007-09-17 08:09:54 +000010115
bellard99c475a2005-01-31 20:45:13 +000010116 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010117 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10118 if (!target_grouplist) {
10119 ret = -TARGET_EFAULT;
10120 goto fail;
10121 }
bellard99c475a2005-01-31 20:45:13 +000010122 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010123 grouplist[i] = tswap32(target_grouplist[i]);
10124 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010125 ret = get_errno(setgroups(gidsetsize, grouplist));
10126 }
10127 break;
bellarda315a142005-01-30 22:59:18 +000010128#endif
10129#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010130 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010131 ret = get_errno(fchown(arg1, arg2, arg3));
10132 break;
bellarda315a142005-01-30 22:59:18 +000010133#endif
10134#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010135 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010136 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010137 break;
bellarda315a142005-01-30 22:59:18 +000010138#endif
10139#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010140 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010141 {
pbrook53a59602006-03-25 19:31:22 +000010142 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010143 ret = get_errno(getresuid(&ruid, &euid, &suid));
10144 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010145 if (put_user_u32(ruid, arg1)
10146 || put_user_u32(euid, arg2)
10147 || put_user_u32(suid, arg3))
10148 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010149 }
10150 }
10151 break;
bellarda315a142005-01-30 22:59:18 +000010152#endif
10153#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010154 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010155 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010156 break;
bellarda315a142005-01-30 22:59:18 +000010157#endif
10158#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010159 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010160 {
pbrook53a59602006-03-25 19:31:22 +000010161 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010162 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10163 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010164 if (put_user_u32(rgid, arg1)
10165 || put_user_u32(egid, arg2)
10166 || put_user_u32(sgid, arg3))
10167 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000010168 }
10169 }
10170 break;
bellarda315a142005-01-30 22:59:18 +000010171#endif
10172#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010173 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010174 if (!(p = lock_user_string(arg1)))
10175 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010176 ret = get_errno(chown(p, arg2, arg3));
10177 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010178 break;
bellarda315a142005-01-30 22:59:18 +000010179#endif
10180#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010181 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010182 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010183 break;
bellarda315a142005-01-30 22:59:18 +000010184#endif
10185#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010186 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010187 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000010188 break;
bellarda315a142005-01-30 22:59:18 +000010189#endif
10190#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010191 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000010192 ret = get_errno(setfsuid(arg1));
10193 break;
bellarda315a142005-01-30 22:59:18 +000010194#endif
10195#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010196 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010197 ret = get_errno(setfsgid(arg1));
10198 break;
bellarda315a142005-01-30 22:59:18 +000010199#endif
bellard67867302003-11-23 17:05:30 +000010200
bellard31e31b82003-02-18 22:55:36 +000010201 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010202 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010203#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010204 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010205 {
10206 void *a;
10207 ret = -TARGET_EFAULT;
10208 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10209 goto efault;
10210 if (!(p = lock_user_string(arg3)))
10211 goto mincore_fail;
10212 ret = get_errno(mincore(a, arg2, p));
10213 unlock_user(p, arg3, ret);
10214 mincore_fail:
10215 unlock_user(a, arg1, 0);
10216 }
10217 break;
bellardffa65c32004-01-04 23:57:22 +000010218#endif
aurel32408321b2008-10-01 21:46:32 +000010219#ifdef TARGET_NR_arm_fadvise64_64
10220 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010221 /* arm_fadvise64_64 looks like fadvise64_64 but
10222 * with different argument order: fd, advice, offset, len
10223 * rather than the usual fd, offset, len, advice.
10224 * Note that offset and len are both 64-bit so appear as
10225 * pairs of 32-bit registers.
10226 */
10227 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10228 target_offset64(arg5, arg6), arg2);
10229 ret = -host_to_target_errno(ret);
10230 break;
aurel32408321b2008-10-01 21:46:32 +000010231#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010232
10233#if TARGET_ABI_BITS == 32
10234
10235#ifdef TARGET_NR_fadvise64_64
10236 case TARGET_NR_fadvise64_64:
10237 /* 6 args: fd, offset (high, low), len (high, low), advice */
10238 if (regpairs_aligned(cpu_env)) {
10239 /* offset is in (3,4), len in (5,6) and advice in 7 */
10240 arg2 = arg3;
10241 arg3 = arg4;
10242 arg4 = arg5;
10243 arg5 = arg6;
10244 arg6 = arg7;
10245 }
10246 ret = -host_to_target_errno(posix_fadvise(arg1,
10247 target_offset64(arg2, arg3),
10248 target_offset64(arg4, arg5),
10249 arg6));
10250 break;
10251#endif
10252
10253#ifdef TARGET_NR_fadvise64
10254 case TARGET_NR_fadvise64:
10255 /* 5 args: fd, offset (high, low), len, advice */
10256 if (regpairs_aligned(cpu_env)) {
10257 /* offset is in (3,4), len in 5 and advice in 6 */
10258 arg2 = arg3;
10259 arg3 = arg4;
10260 arg4 = arg5;
10261 arg5 = arg6;
10262 }
10263 ret = -host_to_target_errno(posix_fadvise(arg1,
10264 target_offset64(arg2, arg3),
10265 arg4, arg5));
10266 break;
10267#endif
10268
10269#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010270#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010271#ifdef TARGET_NR_fadvise64_64
10272 case TARGET_NR_fadvise64_64:
10273#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010274#ifdef TARGET_NR_fadvise64
10275 case TARGET_NR_fadvise64:
10276#endif
10277#ifdef TARGET_S390X
10278 switch (arg4) {
10279 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10280 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10281 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10282 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10283 default: break;
10284 }
10285#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010286 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10287 break;
aurel32408321b2008-10-01 21:46:32 +000010288#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010289#endif /* end of 64-bit ABI fadvise handling */
10290
bellardffa65c32004-01-04 23:57:22 +000010291#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010292 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010293 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010294 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010295 This will break MADV_DONTNEED.
10296 This is a hint, so ignoring and returning success is ok. */
10297 ret = get_errno(0);
10298 break;
bellardffa65c32004-01-04 23:57:22 +000010299#endif
blueswir1992f48a2007-10-14 16:27:31 +000010300#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010301 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010302 {
thsb1e341e2007-03-20 21:50:52 +000010303 int cmd;
bellard77e46722003-04-29 20:39:06 +000010304 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010305 from_flock64_fn *copyfrom = copy_from_user_flock64;
10306 to_flock64_fn *copyto = copy_to_user_flock64;
10307
pbrookce4defa2006-02-09 16:49:55 +000010308#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010010309 if (((CPUARMState *)cpu_env)->eabi) {
10310 copyfrom = copy_from_user_eabi_flock64;
10311 copyto = copy_to_user_eabi_flock64;
10312 }
pbrookce4defa2006-02-09 16:49:55 +000010313#endif
bellard77e46722003-04-29 20:39:06 +000010314
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010315 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010316 if (cmd == -TARGET_EINVAL) {
10317 ret = cmd;
10318 break;
10319 }
thsb1e341e2007-03-20 21:50:52 +000010320
bellard60cd49d2003-03-16 22:53:56 +000010321 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010322 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010323 ret = copyfrom(&fl, arg3);
10324 if (ret) {
10325 break;
ths58134272007-03-31 18:59:32 +000010326 }
thsb1e341e2007-03-20 21:50:52 +000010327 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010328 if (ret == 0) {
10329 ret = copyto(arg3, &fl);
10330 }
bellard77e46722003-04-29 20:39:06 +000010331 break;
10332
thsb1e341e2007-03-20 21:50:52 +000010333 case TARGET_F_SETLK64:
10334 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010335 ret = copyfrom(&fl, arg3);
10336 if (ret) {
10337 break;
pbrookce4defa2006-02-09 16:49:55 +000010338 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010339 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010340 break;
bellard60cd49d2003-03-16 22:53:56 +000010341 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010342 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010343 break;
10344 }
bellard77e46722003-04-29 20:39:06 +000010345 break;
10346 }
bellard60cd49d2003-03-16 22:53:56 +000010347#endif
ths7d600c82006-12-08 01:32:58 +000010348#ifdef TARGET_NR_cacheflush
10349 case TARGET_NR_cacheflush:
10350 /* self-modifying code is handled automatically, so nothing needed */
10351 ret = 0;
10352 break;
10353#endif
bellardebc05482003-09-30 21:08:41 +000010354#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010355 case TARGET_NR_security:
10356 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010357#endif
bellardc573ff62004-01-04 15:51:36 +000010358#ifdef TARGET_NR_getpagesize
10359 case TARGET_NR_getpagesize:
10360 ret = TARGET_PAGE_SIZE;
10361 break;
10362#endif
bellard31e31b82003-02-18 22:55:36 +000010363 case TARGET_NR_gettid:
10364 ret = get_errno(gettid());
10365 break;
thse5febef2007-04-01 18:31:35 +000010366#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010367 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010368#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010369 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010370 arg2 = arg3;
10371 arg3 = arg4;
10372 arg4 = arg5;
10373 }
aurel322054ac92008-10-13 21:08:07 +000010374 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10375#else
10376 ret = get_errno(readahead(arg1, arg2, arg3));
10377#endif
10378 break;
thse5febef2007-04-01 18:31:35 +000010379#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010380#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010381#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010382 case TARGET_NR_listxattr:
10383 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010384 {
10385 void *p, *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 p = lock_user_string(arg1);
10394 if (p) {
10395 if (num == TARGET_NR_listxattr) {
10396 ret = get_errno(listxattr(p, b, arg3));
10397 } else {
10398 ret = get_errno(llistxattr(p, b, arg3));
10399 }
10400 } else {
10401 ret = -TARGET_EFAULT;
10402 }
10403 unlock_user(p, arg1, 0);
10404 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010405 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010406 }
10407 case TARGET_NR_flistxattr:
10408 {
10409 void *b = 0;
10410 if (arg2) {
10411 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10412 if (!b) {
10413 ret = -TARGET_EFAULT;
10414 break;
10415 }
10416 }
10417 ret = get_errno(flistxattr(arg1, b, arg3));
10418 unlock_user(b, arg2, arg3);
10419 break;
10420 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010421 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010422 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010423 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010424 void *p, *n, *v = 0;
10425 if (arg3) {
10426 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10427 if (!v) {
10428 ret = -TARGET_EFAULT;
10429 break;
10430 }
10431 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010432 p = lock_user_string(arg1);
10433 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010434 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010435 if (num == TARGET_NR_setxattr) {
10436 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10437 } else {
10438 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10439 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010440 } else {
10441 ret = -TARGET_EFAULT;
10442 }
10443 unlock_user(p, arg1, 0);
10444 unlock_user(n, arg2, 0);
10445 unlock_user(v, arg3, 0);
10446 }
10447 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010448 case TARGET_NR_fsetxattr:
10449 {
10450 void *n, *v = 0;
10451 if (arg3) {
10452 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10453 if (!v) {
10454 ret = -TARGET_EFAULT;
10455 break;
10456 }
10457 }
10458 n = lock_user_string(arg2);
10459 if (n) {
10460 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10461 } else {
10462 ret = -TARGET_EFAULT;
10463 }
10464 unlock_user(n, arg2, 0);
10465 unlock_user(v, arg3, 0);
10466 }
10467 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010468 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010469 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010470 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010471 void *p, *n, *v = 0;
10472 if (arg3) {
10473 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10474 if (!v) {
10475 ret = -TARGET_EFAULT;
10476 break;
10477 }
10478 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010479 p = lock_user_string(arg1);
10480 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010481 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010482 if (num == TARGET_NR_getxattr) {
10483 ret = get_errno(getxattr(p, n, v, arg4));
10484 } else {
10485 ret = get_errno(lgetxattr(p, n, v, arg4));
10486 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010487 } else {
10488 ret = -TARGET_EFAULT;
10489 }
10490 unlock_user(p, arg1, 0);
10491 unlock_user(n, arg2, 0);
10492 unlock_user(v, arg3, arg4);
10493 }
10494 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010495 case TARGET_NR_fgetxattr:
10496 {
10497 void *n, *v = 0;
10498 if (arg3) {
10499 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10500 if (!v) {
10501 ret = -TARGET_EFAULT;
10502 break;
10503 }
10504 }
10505 n = lock_user_string(arg2);
10506 if (n) {
10507 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10508 } else {
10509 ret = -TARGET_EFAULT;
10510 }
10511 unlock_user(n, arg2, 0);
10512 unlock_user(v, arg3, arg4);
10513 }
10514 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010515 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010516 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010517 {
10518 void *p, *n;
10519 p = lock_user_string(arg1);
10520 n = lock_user_string(arg2);
10521 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010522 if (num == TARGET_NR_removexattr) {
10523 ret = get_errno(removexattr(p, n));
10524 } else {
10525 ret = get_errno(lremovexattr(p, n));
10526 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010527 } else {
10528 ret = -TARGET_EFAULT;
10529 }
10530 unlock_user(p, arg1, 0);
10531 unlock_user(n, arg2, 0);
10532 }
10533 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010534 case TARGET_NR_fremovexattr:
10535 {
10536 void *n;
10537 n = lock_user_string(arg2);
10538 if (n) {
10539 ret = get_errno(fremovexattr(arg1, n));
10540 } else {
10541 ret = -TARGET_EFAULT;
10542 }
10543 unlock_user(n, arg2, 0);
10544 }
10545 break;
bellardebc05482003-09-30 21:08:41 +000010546#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010547#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010548#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010549 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010550#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010551 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010552 ret = 0;
10553 break;
edgar_iglef967792009-01-07 14:19:38 +000010554#elif defined(TARGET_CRIS)
10555 if (arg1 & 0xff)
10556 ret = -TARGET_EINVAL;
10557 else {
10558 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10559 ret = 0;
10560 }
10561 break;
bellard8d18e892007-11-14 15:18:40 +000010562#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10563 ret = do_set_thread_area(cpu_env, arg1);
10564 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010565#elif defined(TARGET_M68K)
10566 {
Andreas Färber0429a972013-08-26 18:14:44 +020010567 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010568 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010569 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010570 break;
10571 }
ths6f5b89a2007-03-02 20:48:00 +000010572#else
10573 goto unimplemented_nowarn;
10574#endif
10575#endif
10576#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010577 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010578#if defined(TARGET_I386) && defined(TARGET_ABI32)
10579 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010580 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010581#elif defined(TARGET_M68K)
10582 {
Andreas Färber0429a972013-08-26 18:14:44 +020010583 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010584 ret = ts->tp_value;
10585 break;
10586 }
bellard8d18e892007-11-14 15:18:40 +000010587#else
bellard5cd43932003-03-29 16:54:36 +000010588 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010589#endif
bellard8d18e892007-11-14 15:18:40 +000010590#endif
bellard48dc41e2006-06-21 18:15:50 +000010591#ifdef TARGET_NR_getdomainname
10592 case TARGET_NR_getdomainname:
10593 goto unimplemented_nowarn;
10594#endif
ths6f5b89a2007-03-02 20:48:00 +000010595
thsb5906f92007-03-19 13:32:45 +000010596#ifdef TARGET_NR_clock_gettime
10597 case TARGET_NR_clock_gettime:
10598 {
10599 struct timespec ts;
10600 ret = get_errno(clock_gettime(arg1, &ts));
10601 if (!is_error(ret)) {
10602 host_to_target_timespec(arg2, &ts);
10603 }
10604 break;
10605 }
10606#endif
10607#ifdef TARGET_NR_clock_getres
10608 case TARGET_NR_clock_getres:
10609 {
10610 struct timespec ts;
10611 ret = get_errno(clock_getres(arg1, &ts));
10612 if (!is_error(ret)) {
10613 host_to_target_timespec(arg2, &ts);
10614 }
10615 break;
10616 }
10617#endif
pbrook63d76512008-05-29 13:43:29 +000010618#ifdef TARGET_NR_clock_nanosleep
10619 case TARGET_NR_clock_nanosleep:
10620 {
10621 struct timespec ts;
10622 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010010623 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
10624 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000010625 if (arg4)
10626 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010627
10628#if defined(TARGET_PPC)
10629 /* clock_nanosleep is odd in that it returns positive errno values.
10630 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010010631 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010632 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10633 }
10634#endif
pbrook63d76512008-05-29 13:43:29 +000010635 break;
10636 }
10637#endif
thsb5906f92007-03-19 13:32:45 +000010638
ths6f5b89a2007-03-02 20:48:00 +000010639#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10640 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010641 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10642 break;
ths6f5b89a2007-03-02 20:48:00 +000010643#endif
10644
ths4cae1d12007-07-12 11:06:53 +000010645 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010646 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010647 break;
ths4cae1d12007-07-12 11:06:53 +000010648
ths71455572007-06-21 21:45:30 +000010649 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010650 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000010651 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010010652 break;
ths71455572007-06-21 21:45:30 +000010653
ths4f2b1fe2007-06-21 21:57:12 +000010654#ifdef TARGET_NR_set_robust_list
10655 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010656 case TARGET_NR_get_robust_list:
10657 /* The ABI for supporting robust futexes has userspace pass
10658 * the kernel a pointer to a linked list which is updated by
10659 * userspace after the syscall; the list is walked by the kernel
10660 * when the thread exits. Since the linked list in QEMU guest
10661 * memory isn't a valid linked list for the host and we have
10662 * no way to reliably intercept the thread-death event, we can't
10663 * support these. Silently return ENOSYS so that guest userspace
10664 * falls back to a non-robust futex implementation (which should
10665 * be OK except in the corner case of the guest crashing while
10666 * holding a mutex that is shared with another process via
10667 * shared memory).
10668 */
10669 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010670#endif
10671
Peter Maydell1acae9f2013-07-02 14:04:12 +010010672#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010673 case TARGET_NR_utimensat:
10674 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010675 struct timespec *tsp, ts[2];
10676 if (!arg3) {
10677 tsp = NULL;
10678 } else {
10679 target_to_host_timespec(ts, arg3);
10680 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10681 tsp = ts;
10682 }
ths9007f0e2007-09-25 17:50:37 +000010683 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010684 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010685 else {
bellard579a97f2007-11-11 14:26:47 +000010686 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010687 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010688 goto fail;
10689 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010690 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010691 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010692 }
10693 }
10694 break;
10695#endif
pbrookbd0c5662008-05-29 14:34:11 +000010696 case TARGET_NR_futex:
10697 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10698 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010699#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010700 case TARGET_NR_inotify_init:
10701 ret = get_errno(sys_inotify_init());
10702 break;
10703#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010704#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010705#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10706 case TARGET_NR_inotify_init1:
10707 ret = get_errno(sys_inotify_init1(arg1));
10708 break;
10709#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010710#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010711#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010712 case TARGET_NR_inotify_add_watch:
10713 p = lock_user_string(arg2);
10714 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10715 unlock_user(p, arg2, 0);
10716 break;
10717#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010718#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010719 case TARGET_NR_inotify_rm_watch:
10720 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10721 break;
10722#endif
ths9007f0e2007-09-25 17:50:37 +000010723
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010724#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010725 case TARGET_NR_mq_open:
10726 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010727 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010728
10729 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010730 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010731 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010732 attrp = &posix_mq_attr;
10733 } else {
10734 attrp = 0;
10735 }
10736 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010737 unlock_user (p, arg1, 0);
10738 }
10739 break;
10740
10741 case TARGET_NR_mq_unlink:
10742 p = lock_user_string(arg1 - 1);
10743 ret = get_errno(mq_unlink(p));
10744 unlock_user (p, arg1, 0);
10745 break;
10746
10747 case TARGET_NR_mq_timedsend:
10748 {
10749 struct timespec ts;
10750
10751 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10752 if (arg5 != 0) {
10753 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010754 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000010755 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010756 } else {
10757 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000010758 }
aurel3224e10032009-04-15 16:11:43 +000010759 unlock_user (p, arg2, arg3);
10760 }
10761 break;
10762
10763 case TARGET_NR_mq_timedreceive:
10764 {
10765 struct timespec ts;
10766 unsigned int prio;
10767
10768 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10769 if (arg5 != 0) {
10770 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010771 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10772 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000010773 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010774 } else {
10775 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10776 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000010777 }
aurel3224e10032009-04-15 16:11:43 +000010778 unlock_user (p, arg2, arg3);
10779 if (arg4 != 0)
10780 put_user_u32(prio, arg4);
10781 }
10782 break;
10783
10784 /* Not implemented for now... */
10785/* case TARGET_NR_mq_notify: */
10786/* break; */
10787
10788 case TARGET_NR_mq_getsetattr:
10789 {
10790 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10791 ret = 0;
10792 if (arg3 != 0) {
10793 ret = mq_getattr(arg1, &posix_mq_attr_out);
10794 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10795 }
10796 if (arg2 != 0) {
10797 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10798 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10799 }
10800
10801 }
10802 break;
10803#endif
10804
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010805#ifdef CONFIG_SPLICE
10806#ifdef TARGET_NR_tee
10807 case TARGET_NR_tee:
10808 {
10809 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10810 }
10811 break;
10812#endif
10813#ifdef TARGET_NR_splice
10814 case TARGET_NR_splice:
10815 {
10816 loff_t loff_in, loff_out;
10817 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010818 if (arg2) {
10819 if (get_user_u64(loff_in, arg2)) {
10820 goto efault;
10821 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010822 ploff_in = &loff_in;
10823 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010824 if (arg4) {
10825 if (get_user_u64(loff_out, arg4)) {
10826 goto efault;
10827 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010828 ploff_out = &loff_out;
10829 }
10830 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010831 if (arg2) {
10832 if (put_user_u64(loff_in, arg2)) {
10833 goto efault;
10834 }
10835 }
10836 if (arg4) {
10837 if (put_user_u64(loff_out, arg4)) {
10838 goto efault;
10839 }
10840 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010841 }
10842 break;
10843#endif
10844#ifdef TARGET_NR_vmsplice
10845 case TARGET_NR_vmsplice:
10846 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010847 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10848 if (vec != NULL) {
10849 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10850 unlock_iovec(vec, arg2, arg3, 0);
10851 } else {
10852 ret = -host_to_target_errno(errno);
10853 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010854 }
10855 break;
10856#endif
10857#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010858#ifdef CONFIG_EVENTFD
10859#if defined(TARGET_NR_eventfd)
10860 case TARGET_NR_eventfd:
10861 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010862 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010863 break;
10864#endif
10865#if defined(TARGET_NR_eventfd2)
10866 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010867 {
10868 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10869 if (arg2 & TARGET_O_NONBLOCK) {
10870 host_flags |= O_NONBLOCK;
10871 }
10872 if (arg2 & TARGET_O_CLOEXEC) {
10873 host_flags |= O_CLOEXEC;
10874 }
10875 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010876 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010877 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010878 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010879#endif
10880#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010881#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10882 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010883#if TARGET_ABI_BITS == 32
10884 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10885 target_offset64(arg5, arg6)));
10886#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010887 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010888#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010889 break;
10890#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010891#if defined(CONFIG_SYNC_FILE_RANGE)
10892#if defined(TARGET_NR_sync_file_range)
10893 case TARGET_NR_sync_file_range:
10894#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010895#if defined(TARGET_MIPS)
10896 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10897 target_offset64(arg5, arg6), arg7));
10898#else
Peter Maydellc727f472011-01-06 11:05:10 +000010899 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10900 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010901#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010902#else
10903 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10904#endif
10905 break;
10906#endif
10907#if defined(TARGET_NR_sync_file_range2)
10908 case TARGET_NR_sync_file_range2:
10909 /* This is like sync_file_range but the arguments are reordered */
10910#if TARGET_ABI_BITS == 32
10911 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10912 target_offset64(arg5, arg6), arg2));
10913#else
10914 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10915#endif
10916 break;
10917#endif
10918#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010919#if defined(TARGET_NR_signalfd4)
10920 case TARGET_NR_signalfd4:
10921 ret = do_signalfd4(arg1, arg2, arg4);
10922 break;
10923#endif
10924#if defined(TARGET_NR_signalfd)
10925 case TARGET_NR_signalfd:
10926 ret = do_signalfd4(arg1, arg2, 0);
10927 break;
10928#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010929#if defined(CONFIG_EPOLL)
10930#if defined(TARGET_NR_epoll_create)
10931 case TARGET_NR_epoll_create:
10932 ret = get_errno(epoll_create(arg1));
10933 break;
10934#endif
10935#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10936 case TARGET_NR_epoll_create1:
10937 ret = get_errno(epoll_create1(arg1));
10938 break;
10939#endif
10940#if defined(TARGET_NR_epoll_ctl)
10941 case TARGET_NR_epoll_ctl:
10942 {
10943 struct epoll_event ep;
10944 struct epoll_event *epp = 0;
10945 if (arg4) {
10946 struct target_epoll_event *target_ep;
10947 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10948 goto efault;
10949 }
10950 ep.events = tswap32(target_ep->events);
10951 /* The epoll_data_t union is just opaque data to the kernel,
10952 * so we transfer all 64 bits across and need not worry what
10953 * actual data type it is.
10954 */
10955 ep.data.u64 = tswap64(target_ep->data.u64);
10956 unlock_user_struct(target_ep, arg4, 0);
10957 epp = &ep;
10958 }
10959 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10960 break;
10961 }
10962#endif
10963
Peter Maydell227f0212016-06-06 19:58:11 +010010964#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010965#if defined(TARGET_NR_epoll_wait)
10966 case TARGET_NR_epoll_wait:
10967#endif
Peter Maydell227f0212016-06-06 19:58:11 +010010968#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010969 case TARGET_NR_epoll_pwait:
10970#endif
10971 {
10972 struct target_epoll_event *target_ep;
10973 struct epoll_event *ep;
10974 int epfd = arg1;
10975 int maxevents = arg3;
10976 int timeout = arg4;
10977
10978 target_ep = lock_user(VERIFY_WRITE, arg2,
10979 maxevents * sizeof(struct target_epoll_event), 1);
10980 if (!target_ep) {
10981 goto efault;
10982 }
10983
10984 ep = alloca(maxevents * sizeof(struct epoll_event));
10985
10986 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010010987#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000010988 case TARGET_NR_epoll_pwait:
10989 {
10990 target_sigset_t *target_set;
10991 sigset_t _set, *set = &_set;
10992
10993 if (arg5) {
10994 target_set = lock_user(VERIFY_READ, arg5,
10995 sizeof(target_sigset_t), 1);
10996 if (!target_set) {
10997 unlock_user(target_ep, arg2, 0);
10998 goto efault;
10999 }
11000 target_to_host_sigset(set, target_set);
11001 unlock_user(target_set, arg5, 0);
11002 } else {
11003 set = NULL;
11004 }
11005
Peter Maydell227f0212016-06-06 19:58:11 +010011006 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11007 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011008 break;
11009 }
11010#endif
11011#if defined(TARGET_NR_epoll_wait)
11012 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010011013 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11014 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011015 break;
11016#endif
11017 default:
11018 ret = -TARGET_ENOSYS;
11019 }
11020 if (!is_error(ret)) {
11021 int i;
11022 for (i = 0; i < ret; i++) {
11023 target_ep[i].events = tswap32(ep[i].events);
11024 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11025 }
11026 }
11027 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
11028 break;
11029 }
11030#endif
11031#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011032#ifdef TARGET_NR_prlimit64
11033 case TARGET_NR_prlimit64:
11034 {
11035 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11036 struct target_rlimit64 *target_rnew, *target_rold;
11037 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011038 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011039 if (arg3) {
11040 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
11041 goto efault;
11042 }
11043 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11044 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11045 unlock_user_struct(target_rnew, arg3, 0);
11046 rnewp = &rnew;
11047 }
11048
Felix Janda95018012014-12-02 22:11:17 +010011049 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011050 if (!is_error(ret) && arg4) {
11051 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
11052 goto efault;
11053 }
11054 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11055 target_rold->rlim_max = tswap64(rold.rlim_max);
11056 unlock_user_struct(target_rold, arg4, 1);
11057 }
11058 break;
11059 }
11060#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011061#ifdef TARGET_NR_gethostname
11062 case TARGET_NR_gethostname:
11063 {
11064 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11065 if (name) {
11066 ret = get_errno(gethostname(name, arg2));
11067 unlock_user(name, arg1, arg2);
11068 } else {
11069 ret = -TARGET_EFAULT;
11070 }
11071 break;
11072 }
11073#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011074#ifdef TARGET_NR_atomic_cmpxchg_32
11075 case TARGET_NR_atomic_cmpxchg_32:
11076 {
11077 /* should use start_exclusive from main.c */
11078 abi_ulong mem_value;
11079 if (get_user_u32(mem_value, arg6)) {
11080 target_siginfo_t info;
11081 info.si_signo = SIGSEGV;
11082 info.si_errno = 0;
11083 info.si_code = TARGET_SEGV_MAPERR;
11084 info._sifields._sigfault._addr = arg6;
11085 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
11086 ret = 0xdeadbeef;
11087
11088 }
11089 if (mem_value == arg2)
11090 put_user_u32(arg1, arg6);
11091 ret = mem_value;
11092 break;
11093 }
11094#endif
11095#ifdef TARGET_NR_atomic_barrier
11096 case TARGET_NR_atomic_barrier:
11097 {
11098 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011099 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011100 break;
11101 }
11102#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011103
11104#ifdef TARGET_NR_timer_create
11105 case TARGET_NR_timer_create:
11106 {
11107 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11108
11109 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011110
11111 int clkid = arg1;
11112 int timer_index = next_free_host_timer();
11113
11114 if (timer_index < 0) {
11115 ret = -TARGET_EAGAIN;
11116 } else {
11117 timer_t *phtimer = g_posix_timers + timer_index;
11118
11119 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011120 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011121 ret = target_to_host_sigevent(phost_sevp, arg2);
11122 if (ret != 0) {
11123 break;
11124 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011125 }
11126
11127 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11128 if (ret) {
11129 phtimer = NULL;
11130 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011131 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011132 goto efault;
11133 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011134 }
11135 }
11136 break;
11137 }
11138#endif
11139
11140#ifdef TARGET_NR_timer_settime
11141 case TARGET_NR_timer_settime:
11142 {
11143 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11144 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011145 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011146
Alexander Grafaecc8862014-11-10 21:33:03 +010011147 if (timerid < 0) {
11148 ret = timerid;
11149 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011150 ret = -TARGET_EINVAL;
11151 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011152 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011153 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11154
11155 target_to_host_itimerspec(&hspec_new, arg3);
11156 ret = get_errno(
11157 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11158 host_to_target_itimerspec(arg2, &hspec_old);
11159 }
11160 break;
11161 }
11162#endif
11163
11164#ifdef TARGET_NR_timer_gettime
11165 case TARGET_NR_timer_gettime:
11166 {
11167 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011168 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011169
Alexander Grafaecc8862014-11-10 21:33:03 +010011170 if (timerid < 0) {
11171 ret = timerid;
11172 } else if (!arg2) {
11173 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011174 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011175 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011176 struct itimerspec hspec;
11177 ret = get_errno(timer_gettime(htimer, &hspec));
11178
11179 if (host_to_target_itimerspec(arg2, &hspec)) {
11180 ret = -TARGET_EFAULT;
11181 }
11182 }
11183 break;
11184 }
11185#endif
11186
11187#ifdef TARGET_NR_timer_getoverrun
11188 case TARGET_NR_timer_getoverrun:
11189 {
11190 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011191 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011192
Alexander Grafaecc8862014-11-10 21:33:03 +010011193 if (timerid < 0) {
11194 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011195 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011196 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011197 ret = get_errno(timer_getoverrun(htimer));
11198 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011199 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011200 break;
11201 }
11202#endif
11203
11204#ifdef TARGET_NR_timer_delete
11205 case TARGET_NR_timer_delete:
11206 {
11207 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011208 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011209
Alexander Grafaecc8862014-11-10 21:33:03 +010011210 if (timerid < 0) {
11211 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011212 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011213 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011214 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011215 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011216 }
11217 break;
11218 }
11219#endif
11220
Riku Voipio51834342014-06-22 11:25:42 +010011221#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11222 case TARGET_NR_timerfd_create:
11223 ret = get_errno(timerfd_create(arg1,
11224 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11225 break;
11226#endif
11227
11228#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11229 case TARGET_NR_timerfd_gettime:
11230 {
11231 struct itimerspec its_curr;
11232
11233 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11234
11235 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11236 goto efault;
11237 }
11238 }
11239 break;
11240#endif
11241
11242#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11243 case TARGET_NR_timerfd_settime:
11244 {
11245 struct itimerspec its_new, its_old, *p_new;
11246
11247 if (arg3) {
11248 if (target_to_host_itimerspec(&its_new, arg3)) {
11249 goto efault;
11250 }
11251 p_new = &its_new;
11252 } else {
11253 p_new = NULL;
11254 }
11255
11256 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11257
11258 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11259 goto efault;
11260 }
11261 }
11262 break;
11263#endif
11264
Paul Burtonab31cda2014-06-22 11:25:43 +010011265#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11266 case TARGET_NR_ioprio_get:
11267 ret = get_errno(ioprio_get(arg1, arg2));
11268 break;
11269#endif
11270
11271#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11272 case TARGET_NR_ioprio_set:
11273 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11274 break;
11275#endif
11276
Riku Voipio9af5c902014-08-12 15:58:57 +030011277#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11278 case TARGET_NR_setns:
11279 ret = get_errno(setns(arg1, arg2));
11280 break;
11281#endif
11282#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11283 case TARGET_NR_unshare:
11284 ret = get_errno(unshare(arg1));
11285 break;
11286#endif
11287
bellard31e31b82003-02-18 22:55:36 +000011288 default:
11289 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011290 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011291#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 +000011292 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011293#endif
ths0da46a62007-10-20 20:23:07 +000011294 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011295 break;
11296 }
bellard579a97f2007-11-11 14:26:47 +000011297fail:
bellardc573ff62004-01-04 15:51:36 +000011298#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011299 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011300#endif
thsb92c47c2007-11-01 00:07:38 +000011301 if(do_strace)
11302 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020011303 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000011304 return ret;
bellard579a97f2007-11-11 14:26:47 +000011305efault:
11306 ret = -TARGET_EFAULT;
11307 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011308}