blob: 143e4a959d117062f9c94fb03075f31d6e0d6233 [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>
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020038#include <sys/timex.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020039#ifdef __ia64__
40int __clone2(int (*fn)(void *), void *child_stack_base,
41 size_t stack_size, int flags, void *arg, ...);
42#endif
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000044#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000045#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040046#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000047#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000048#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000049#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000050#include <sys/statfs.h>
Aleksandar Markovic38860a02016-10-10 13:23:29 +020051#include <time.h>
bellardebc05482003-09-30 21:08:41 +000052#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000053#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020054#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000055//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000056#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000057#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020058#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000059#include <linux/icmp.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010060#include <linux/icmpv6.h>
61#include <linux/errqueue.h>
Marco A L Barbosad6d6d6f2017-10-05 10:55:30 -030062#include <linux/random.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020063#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030064#ifdef CONFIG_TIMERFD
65#include <sys/timerfd.h>
66#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020067#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000068#include <sys/gmon.h>
69#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030070#ifdef CONFIG_EVENTFD
71#include <sys/eventfd.h>
72#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000073#ifdef CONFIG_EPOLL
74#include <sys/epoll.h>
75#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070076#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010077#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070078#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000079#ifdef CONFIG_SENDFILE
80#include <sys/sendfile.h>
81#endif
bellard31e31b82003-02-18 22:55:36 +000082
83#define termios host_termios
84#define winsize host_winsize
85#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000086#define sgttyb host_sgttyb /* same as target */
87#define tchars host_tchars /* same as target */
88#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000089
90#include <linux/termios.h>
91#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000092#include <linux/cdrom.h>
93#include <linux/hdreg.h>
94#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000095#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000096#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030097#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000098#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000099#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000100#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200101#include <linux/fb.h>
102#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100103#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000104#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100105#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200106#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100107#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200108#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200109#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200110#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200111#include <linux/rtnetlink.h>
Laurent Vivierc5dff282016-06-27 18:54:30 +0200112#include <linux/if_bridge.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200113#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200114#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000115#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200116#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000117
bellard3ef693a2003-03-23 20:17:16 +0000118#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000119
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100120#ifndef CLONE_IO
121#define CLONE_IO 0x80000000 /* Clone io context */
122#endif
123
124/* We can't directly call the host clone syscall, because this will
125 * badly confuse libc (breaking mutexes, for example). So we must
126 * divide clone flags into:
127 * * flag combinations that look like pthread_create()
128 * * flag combinations that look like fork()
129 * * flags we can implement within QEMU itself
130 * * flags we can't support and will return an error for
131 */
132/* For thread creation, all these flags must be present; for
133 * fork, none must be present.
134 */
135#define CLONE_THREAD_FLAGS \
136 (CLONE_VM | CLONE_FS | CLONE_FILES | \
137 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
138
139/* These flags are ignored:
140 * CLONE_DETACHED is now ignored by the kernel;
141 * CLONE_IO is just an optimisation hint to the I/O scheduler
142 */
143#define CLONE_IGNORED_FLAGS \
144 (CLONE_DETACHED | CLONE_IO)
145
146/* Flags for fork which we can implement within QEMU itself */
147#define CLONE_OPTIONAL_FORK_FLAGS \
148 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
149 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
150
151/* Flags for thread creation which we can implement within QEMU itself */
152#define CLONE_OPTIONAL_THREAD_FLAGS \
153 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
154 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
155
156#define CLONE_INVALID_FORK_FLAGS \
157 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
158
159#define CLONE_INVALID_THREAD_FLAGS \
160 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
161 CLONE_IGNORED_FLAGS))
162
163/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
164 * have almost all been allocated. We cannot support any of
165 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
166 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
167 * The checks against the invalid thread masks above will catch these.
168 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
169 */
pbrook30813ce2008-06-02 15:45:44 +0000170
bellard72f03902003-02-18 23:33:18 +0000171//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100172/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
173 * once. This exercises the codepaths for restart.
174 */
175//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000176
bellard1a9353d2003-03-16 20:28:50 +0000177//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000178#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
179#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000180
bellard70a194b2003-08-11 22:20:16 +0000181#undef _syscall0
182#undef _syscall1
183#undef _syscall2
184#undef _syscall3
185#undef _syscall4
186#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000187#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000188
bellard83fcb512006-06-14 13:37:16 +0000189#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000190static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000191{ \
192 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000193}
194
bellard83fcb512006-06-14 13:37:16 +0000195#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000196static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000197{ \
198 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000199}
200
bellard83fcb512006-06-14 13:37:16 +0000201#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000202static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000203{ \
204 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000205}
206
bellard83fcb512006-06-14 13:37:16 +0000207#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000208static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000209{ \
210 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000211}
212
bellard83fcb512006-06-14 13:37:16 +0000213#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000214static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000215{ \
216 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000217}
218
bellard83fcb512006-06-14 13:37:16 +0000219#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
220 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000221static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000222{ \
223 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000224}
bellard83fcb512006-06-14 13:37:16 +0000225
226
227#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
228 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000229static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
230 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000231{ \
232 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
233}
234
bellard70a194b2003-08-11 22:20:16 +0000235
bellard31e31b82003-02-18 22:55:36 +0000236#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000237#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000238#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000239#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000240#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000241#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200242#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000243#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000244#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000245#define __NR_sys_inotify_init __NR_inotify_init
246#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
247#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000248
Alexander Graf42a39fb2011-04-15 17:32:45 +0200249#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
250 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000251#define __NR__llseek __NR_lseek
252#endif
253
James Hogana29e5ba2014-03-25 21:51:08 +0000254/* Newer kernel ports have llseek() instead of _llseek() */
255#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
256#define TARGET_NR__llseek TARGET_NR_llseek
257#endif
258
bellard72f03902003-02-18 23:33:18 +0000259#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000260_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000261#else
ths0da46a62007-10-20 20:23:07 +0000262/* This is a replacement for the host gettid() and must return a host
263 errno. */
bellard72f03902003-02-18 23:33:18 +0000264static int gettid(void) {
265 return -ENOSYS;
266}
267#endif
Chen Gang704eff62015-08-21 05:37:33 +0800268#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000269_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100270#endif
271#if !defined(__NR_getdents) || \
272 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000273_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
274#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700275#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000276_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
277 loff_t *, res, uint, wh);
278#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200279_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200280_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
281 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000282_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000283#ifdef __NR_exit_group
284_syscall1(int,exit_group,int,error_code)
285#endif
286#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
287_syscall1(int,set_tid_address,int *,tidptr)
288#endif
aurel323b3f24a2009-04-15 16:12:13 +0000289#if defined(TARGET_NR_futex) && defined(__NR_futex)
290_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
291 const struct timespec *,timeout,int *,uaddr2,int,val3)
292#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500293#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
294_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
295 unsigned long *, user_mask_ptr);
296#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
297_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
298 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200299_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
300 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000301_syscall2(int, capget, struct __user_cap_header_struct *, header,
302 struct __user_cap_data_struct *, data);
303_syscall2(int, capset, struct __user_cap_header_struct *, header,
304 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100305#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
306_syscall2(int, ioprio_get, int, which, int, who)
307#endif
308#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
309_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
310#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100311#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
312_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
313#endif
aurel323b3f24a2009-04-15 16:12:13 +0000314
Laurent Vivier2f147882016-09-25 22:20:20 +0200315#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
316_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
317 unsigned long, idx1, unsigned long, idx2)
318#endif
319
aurel323b3f24a2009-04-15 16:12:13 +0000320static bitmask_transtbl fcntl_flags_tbl[] = {
321 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
322 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
323 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
324 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
325 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
326 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
327 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
328 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700329 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000330 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
331 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
332 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
333 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000334#if defined(O_DIRECT)
335 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
336#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700337#if defined(O_NOATIME)
338 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
339#endif
340#if defined(O_CLOEXEC)
341 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
342#endif
343#if defined(O_PATH)
344 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
345#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300346#if defined(O_TMPFILE)
347 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
348#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700349 /* Don't terminate the list prematurely on 64-bit host+guest. */
350#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
351 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
352#endif
aurel323b3f24a2009-04-15 16:12:13 +0000353 { 0, 0, 0, 0 }
354};
355
Michal Privoznik60c6b792016-08-19 10:06:40 +0200356enum {
357 QEMU_IFLA_BR_UNSPEC,
358 QEMU_IFLA_BR_FORWARD_DELAY,
359 QEMU_IFLA_BR_HELLO_TIME,
360 QEMU_IFLA_BR_MAX_AGE,
361 QEMU_IFLA_BR_AGEING_TIME,
362 QEMU_IFLA_BR_STP_STATE,
363 QEMU_IFLA_BR_PRIORITY,
364 QEMU_IFLA_BR_VLAN_FILTERING,
365 QEMU_IFLA_BR_VLAN_PROTOCOL,
366 QEMU_IFLA_BR_GROUP_FWD_MASK,
367 QEMU_IFLA_BR_ROOT_ID,
368 QEMU_IFLA_BR_BRIDGE_ID,
369 QEMU_IFLA_BR_ROOT_PORT,
370 QEMU_IFLA_BR_ROOT_PATH_COST,
371 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
372 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
373 QEMU_IFLA_BR_HELLO_TIMER,
374 QEMU_IFLA_BR_TCN_TIMER,
375 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
376 QEMU_IFLA_BR_GC_TIMER,
377 QEMU_IFLA_BR_GROUP_ADDR,
378 QEMU_IFLA_BR_FDB_FLUSH,
379 QEMU_IFLA_BR_MCAST_ROUTER,
380 QEMU_IFLA_BR_MCAST_SNOOPING,
381 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
382 QEMU_IFLA_BR_MCAST_QUERIER,
383 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
384 QEMU_IFLA_BR_MCAST_HASH_MAX,
385 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
386 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
387 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
388 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
389 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
390 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
391 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
392 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
393 QEMU_IFLA_BR_NF_CALL_IPTABLES,
394 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
395 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
396 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
397 QEMU_IFLA_BR_PAD,
398 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
399 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
400 QEMU___IFLA_BR_MAX,
401};
402
403enum {
404 QEMU_IFLA_UNSPEC,
405 QEMU_IFLA_ADDRESS,
406 QEMU_IFLA_BROADCAST,
407 QEMU_IFLA_IFNAME,
408 QEMU_IFLA_MTU,
409 QEMU_IFLA_LINK,
410 QEMU_IFLA_QDISC,
411 QEMU_IFLA_STATS,
412 QEMU_IFLA_COST,
413 QEMU_IFLA_PRIORITY,
414 QEMU_IFLA_MASTER,
415 QEMU_IFLA_WIRELESS,
416 QEMU_IFLA_PROTINFO,
417 QEMU_IFLA_TXQLEN,
418 QEMU_IFLA_MAP,
419 QEMU_IFLA_WEIGHT,
420 QEMU_IFLA_OPERSTATE,
421 QEMU_IFLA_LINKMODE,
422 QEMU_IFLA_LINKINFO,
423 QEMU_IFLA_NET_NS_PID,
424 QEMU_IFLA_IFALIAS,
425 QEMU_IFLA_NUM_VF,
426 QEMU_IFLA_VFINFO_LIST,
427 QEMU_IFLA_STATS64,
428 QEMU_IFLA_VF_PORTS,
429 QEMU_IFLA_PORT_SELF,
430 QEMU_IFLA_AF_SPEC,
431 QEMU_IFLA_GROUP,
432 QEMU_IFLA_NET_NS_FD,
433 QEMU_IFLA_EXT_MASK,
434 QEMU_IFLA_PROMISCUITY,
435 QEMU_IFLA_NUM_TX_QUEUES,
436 QEMU_IFLA_NUM_RX_QUEUES,
437 QEMU_IFLA_CARRIER,
438 QEMU_IFLA_PHYS_PORT_ID,
439 QEMU_IFLA_CARRIER_CHANGES,
440 QEMU_IFLA_PHYS_SWITCH_ID,
441 QEMU_IFLA_LINK_NETNSID,
442 QEMU_IFLA_PHYS_PORT_NAME,
443 QEMU_IFLA_PROTO_DOWN,
444 QEMU_IFLA_GSO_MAX_SEGS,
445 QEMU_IFLA_GSO_MAX_SIZE,
446 QEMU_IFLA_PAD,
447 QEMU_IFLA_XDP,
448 QEMU___IFLA_MAX
449};
450
451enum {
452 QEMU_IFLA_BRPORT_UNSPEC,
453 QEMU_IFLA_BRPORT_STATE,
454 QEMU_IFLA_BRPORT_PRIORITY,
455 QEMU_IFLA_BRPORT_COST,
456 QEMU_IFLA_BRPORT_MODE,
457 QEMU_IFLA_BRPORT_GUARD,
458 QEMU_IFLA_BRPORT_PROTECT,
459 QEMU_IFLA_BRPORT_FAST_LEAVE,
460 QEMU_IFLA_BRPORT_LEARNING,
461 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
462 QEMU_IFLA_BRPORT_PROXYARP,
463 QEMU_IFLA_BRPORT_LEARNING_SYNC,
464 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
465 QEMU_IFLA_BRPORT_ROOT_ID,
466 QEMU_IFLA_BRPORT_BRIDGE_ID,
467 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
468 QEMU_IFLA_BRPORT_DESIGNATED_COST,
469 QEMU_IFLA_BRPORT_ID,
470 QEMU_IFLA_BRPORT_NO,
471 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
472 QEMU_IFLA_BRPORT_CONFIG_PENDING,
473 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
474 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
475 QEMU_IFLA_BRPORT_HOLD_TIMER,
476 QEMU_IFLA_BRPORT_FLUSH,
477 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
478 QEMU_IFLA_BRPORT_PAD,
479 QEMU___IFLA_BRPORT_MAX
480};
481
482enum {
483 QEMU_IFLA_INFO_UNSPEC,
484 QEMU_IFLA_INFO_KIND,
485 QEMU_IFLA_INFO_DATA,
486 QEMU_IFLA_INFO_XSTATS,
487 QEMU_IFLA_INFO_SLAVE_KIND,
488 QEMU_IFLA_INFO_SLAVE_DATA,
489 QEMU___IFLA_INFO_MAX,
490};
491
492enum {
493 QEMU_IFLA_INET_UNSPEC,
494 QEMU_IFLA_INET_CONF,
495 QEMU___IFLA_INET_MAX,
496};
497
498enum {
499 QEMU_IFLA_INET6_UNSPEC,
500 QEMU_IFLA_INET6_FLAGS,
501 QEMU_IFLA_INET6_CONF,
502 QEMU_IFLA_INET6_STATS,
503 QEMU_IFLA_INET6_MCAST,
504 QEMU_IFLA_INET6_CACHEINFO,
505 QEMU_IFLA_INET6_ICMP6STATS,
506 QEMU_IFLA_INET6_TOKEN,
507 QEMU_IFLA_INET6_ADDR_GEN_MODE,
508 QEMU___IFLA_INET6_MAX
509};
510
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100511typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100512typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200513typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100514 TargetFdDataFunc host_to_target_data;
515 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100516 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200517} TargetFdTrans;
518
519static TargetFdTrans **target_fd_trans;
520
521static unsigned int target_fd_max;
522
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200523static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
524{
525 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
526 return target_fd_trans[fd]->target_to_host_data;
527 }
528 return NULL;
529}
530
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100531static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200532{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100533 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100534 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200535 }
536 return NULL;
537}
538
Laurent Vivier7b36f782015-10-28 21:40:44 +0100539static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
540{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100541 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100542 return target_fd_trans[fd]->target_to_host_addr;
543 }
544 return NULL;
545}
546
Laurent Viviere36800c2015-10-02 14:48:09 +0200547static void fd_trans_register(int fd, TargetFdTrans *trans)
548{
549 unsigned int oldmax;
550
551 if (fd >= target_fd_max) {
552 oldmax = target_fd_max;
553 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100554 target_fd_trans = g_renew(TargetFdTrans *,
555 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200556 memset((void *)(target_fd_trans + oldmax), 0,
557 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
558 }
559 target_fd_trans[fd] = trans;
560}
561
562static void fd_trans_unregister(int fd)
563{
564 if (fd >= 0 && fd < target_fd_max) {
565 target_fd_trans[fd] = NULL;
566 }
567}
568
569static void fd_trans_dup(int oldfd, int newfd)
570{
571 fd_trans_unregister(newfd);
572 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
573 fd_trans_register(newfd, target_fd_trans[oldfd]);
574 }
575}
576
aurel323b3f24a2009-04-15 16:12:13 +0000577static int sys_getcwd1(char *buf, size_t size)
578{
579 if (getcwd(buf, size) == NULL) {
580 /* getcwd() sets errno */
581 return (-1);
582 }
aurel32aaf4ad32009-04-16 14:17:14 +0000583 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000584}
585
Peter Maydell1acae9f2013-07-02 14:04:12 +0100586#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100587#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100588#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000589_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
590 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100591#else
592static int sys_utimensat(int dirfd, const char *pathname,
593 const struct timespec times[2], int flags)
594{
595 errno = ENOSYS;
596 return -1;
597}
ths9007f0e2007-09-25 17:50:37 +0000598#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100599#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000600
601#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000602#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000603
aurel3239b59762008-10-01 21:46:50 +0000604#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000605static int sys_inotify_init(void)
606{
607 return (inotify_init());
608}
aurel3239b59762008-10-01 21:46:50 +0000609#endif
610#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000611static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
612{
613 return (inotify_add_watch(fd, pathname, mask));
614}
aurel3239b59762008-10-01 21:46:50 +0000615#endif
616#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000617static int sys_inotify_rm_watch(int fd, int32_t wd)
618{
aurel328690e422009-04-17 13:50:32 +0000619 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000620}
aurel3239b59762008-10-01 21:46:50 +0000621#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000622#ifdef CONFIG_INOTIFY1
623#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
624static int sys_inotify_init1(int flags)
625{
626 return (inotify_init1(flags));
627}
628#endif
629#endif
aurel323b3f24a2009-04-15 16:12:13 +0000630#else
631/* Userspace can usually survive runtime without inotify */
632#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000633#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000634#undef TARGET_NR_inotify_add_watch
635#undef TARGET_NR_inotify_rm_watch
636#endif /* CONFIG_INOTIFY */
637
Peter Maydell163a05a2011-06-27 17:44:52 +0100638#if defined(TARGET_NR_prlimit64)
639#ifndef __NR_prlimit64
640# define __NR_prlimit64 -1
641#endif
642#define __NR_sys_prlimit64 __NR_prlimit64
643/* The glibc rlimit structure may not be that used by the underlying syscall */
644struct host_rlimit64 {
645 uint64_t rlim_cur;
646 uint64_t rlim_max;
647};
648_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
649 const struct host_rlimit64 *, new_limit,
650 struct host_rlimit64 *, old_limit)
651#endif
652
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100653
654#if defined(TARGET_NR_timer_create)
655/* Maxiumum of 32 active POSIX timers allowed at any one time. */
656static timer_t g_posix_timers[32] = { 0, } ;
657
658static inline int next_free_host_timer(void)
659{
660 int k ;
661 /* FIXME: Does finding the next free slot require a lock? */
662 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
663 if (g_posix_timers[k] == 0) {
664 g_posix_timers[k] = (timer_t) 1;
665 return k;
666 }
667 }
668 return -1;
669}
670#endif
671
Riku Voipio48e515d2011-07-12 15:40:51 +0300672/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000673#ifdef TARGET_ARM
James Clarke8bf8e9d2017-09-15 20:33:13 +0100674static inline int regpairs_aligned(void *cpu_env, int num)
675{
Riku Voipio48e515d2011-07-12 15:40:51 +0300676 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
677}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200678#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
James Clarke8bf8e9d2017-09-15 20:33:13 +0100679static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000680#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
681/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
682 * of registers which translates to the same as ARM/MIPS, because we start with
683 * r3 as arg1 */
James Clarke8bf8e9d2017-09-15 20:33:13 +0100684static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
685#elif defined(TARGET_SH4)
686/* SH4 doesn't align register pairs, except for p{read,write}64 */
687static inline int regpairs_aligned(void *cpu_env, int num)
688{
689 switch (num) {
690 case TARGET_NR_pread64:
691 case TARGET_NR_pwrite64:
692 return 1;
693
694 default:
695 return 0;
696 }
697}
Riku Voipio48e515d2011-07-12 15:40:51 +0300698#else
James Clarke8bf8e9d2017-09-15 20:33:13 +0100699static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300700#endif
701
thsb92c47c2007-11-01 00:07:38 +0000702#define ERRNO_TABLE_SIZE 1200
703
704/* target_to_host_errno_table[] is initialized from
705 * host_to_target_errno_table[] in syscall_init(). */
706static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
707};
708
ths637947f2007-06-01 12:09:19 +0000709/*
thsfe8f0962007-07-12 10:59:21 +0000710 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000711 * minus the errnos that are not actually generic to all archs.
712 */
thsb92c47c2007-11-01 00:07:38 +0000713static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800714 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000715 [EIDRM] = TARGET_EIDRM,
716 [ECHRNG] = TARGET_ECHRNG,
717 [EL2NSYNC] = TARGET_EL2NSYNC,
718 [EL3HLT] = TARGET_EL3HLT,
719 [EL3RST] = TARGET_EL3RST,
720 [ELNRNG] = TARGET_ELNRNG,
721 [EUNATCH] = TARGET_EUNATCH,
722 [ENOCSI] = TARGET_ENOCSI,
723 [EL2HLT] = TARGET_EL2HLT,
724 [EDEADLK] = TARGET_EDEADLK,
725 [ENOLCK] = TARGET_ENOLCK,
726 [EBADE] = TARGET_EBADE,
727 [EBADR] = TARGET_EBADR,
728 [EXFULL] = TARGET_EXFULL,
729 [ENOANO] = TARGET_ENOANO,
730 [EBADRQC] = TARGET_EBADRQC,
731 [EBADSLT] = TARGET_EBADSLT,
732 [EBFONT] = TARGET_EBFONT,
733 [ENOSTR] = TARGET_ENOSTR,
734 [ENODATA] = TARGET_ENODATA,
735 [ETIME] = TARGET_ETIME,
736 [ENOSR] = TARGET_ENOSR,
737 [ENONET] = TARGET_ENONET,
738 [ENOPKG] = TARGET_ENOPKG,
739 [EREMOTE] = TARGET_EREMOTE,
740 [ENOLINK] = TARGET_ENOLINK,
741 [EADV] = TARGET_EADV,
742 [ESRMNT] = TARGET_ESRMNT,
743 [ECOMM] = TARGET_ECOMM,
744 [EPROTO] = TARGET_EPROTO,
745 [EDOTDOT] = TARGET_EDOTDOT,
746 [EMULTIHOP] = TARGET_EMULTIHOP,
747 [EBADMSG] = TARGET_EBADMSG,
748 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
749 [EOVERFLOW] = TARGET_EOVERFLOW,
750 [ENOTUNIQ] = TARGET_ENOTUNIQ,
751 [EBADFD] = TARGET_EBADFD,
752 [EREMCHG] = TARGET_EREMCHG,
753 [ELIBACC] = TARGET_ELIBACC,
754 [ELIBBAD] = TARGET_ELIBBAD,
755 [ELIBSCN] = TARGET_ELIBSCN,
756 [ELIBMAX] = TARGET_ELIBMAX,
757 [ELIBEXEC] = TARGET_ELIBEXEC,
758 [EILSEQ] = TARGET_EILSEQ,
759 [ENOSYS] = TARGET_ENOSYS,
760 [ELOOP] = TARGET_ELOOP,
761 [ERESTART] = TARGET_ERESTART,
762 [ESTRPIPE] = TARGET_ESTRPIPE,
763 [ENOTEMPTY] = TARGET_ENOTEMPTY,
764 [EUSERS] = TARGET_EUSERS,
765 [ENOTSOCK] = TARGET_ENOTSOCK,
766 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
767 [EMSGSIZE] = TARGET_EMSGSIZE,
768 [EPROTOTYPE] = TARGET_EPROTOTYPE,
769 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
770 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
771 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
772 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
773 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
774 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
775 [EADDRINUSE] = TARGET_EADDRINUSE,
776 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
777 [ENETDOWN] = TARGET_ENETDOWN,
778 [ENETUNREACH] = TARGET_ENETUNREACH,
779 [ENETRESET] = TARGET_ENETRESET,
780 [ECONNABORTED] = TARGET_ECONNABORTED,
781 [ECONNRESET] = TARGET_ECONNRESET,
782 [ENOBUFS] = TARGET_ENOBUFS,
783 [EISCONN] = TARGET_EISCONN,
784 [ENOTCONN] = TARGET_ENOTCONN,
785 [EUCLEAN] = TARGET_EUCLEAN,
786 [ENOTNAM] = TARGET_ENOTNAM,
787 [ENAVAIL] = TARGET_ENAVAIL,
788 [EISNAM] = TARGET_EISNAM,
789 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200790 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000791 [ESHUTDOWN] = TARGET_ESHUTDOWN,
792 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
793 [ETIMEDOUT] = TARGET_ETIMEDOUT,
794 [ECONNREFUSED] = TARGET_ECONNREFUSED,
795 [EHOSTDOWN] = TARGET_EHOSTDOWN,
796 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
797 [EALREADY] = TARGET_EALREADY,
798 [EINPROGRESS] = TARGET_EINPROGRESS,
799 [ESTALE] = TARGET_ESTALE,
800 [ECANCELED] = TARGET_ECANCELED,
801 [ENOMEDIUM] = TARGET_ENOMEDIUM,
802 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000803#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000804 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000805#endif
806#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000807 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000808#endif
809#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000810 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000811#endif
812#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000813 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000814#endif
815#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000816 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000817#endif
818#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000819 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000820#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200821#ifdef ENOMSG
822 [ENOMSG] = TARGET_ENOMSG,
823#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800824#ifdef ERKFILL
825 [ERFKILL] = TARGET_ERFKILL,
826#endif
827#ifdef EHWPOISON
828 [EHWPOISON] = TARGET_EHWPOISON,
829#endif
thsb92c47c2007-11-01 00:07:38 +0000830};
ths637947f2007-06-01 12:09:19 +0000831
832static inline int host_to_target_errno(int err)
833{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100834 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
835 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000836 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100837 }
ths637947f2007-06-01 12:09:19 +0000838 return err;
839}
840
thsb92c47c2007-11-01 00:07:38 +0000841static inline int target_to_host_errno(int err)
842{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100843 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
844 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000845 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100846 }
thsb92c47c2007-11-01 00:07:38 +0000847 return err;
848}
849
blueswir1992f48a2007-10-14 16:27:31 +0000850static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000851{
852 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000853 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000854 else
855 return ret;
856}
857
blueswir1992f48a2007-10-14 16:27:31 +0000858static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000859{
blueswir1992f48a2007-10-14 16:27:31 +0000860 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000861}
862
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100863const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000864{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100865 if (err == TARGET_ERESTARTSYS) {
866 return "To be restarted";
867 }
868 if (err == TARGET_QEMU_ESIGRETURN) {
869 return "Successful exit from sigreturn";
870 }
871
Alexander Graf962b2892011-11-21 12:04:07 +0100872 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
873 return NULL;
874 }
thsb92c47c2007-11-01 00:07:38 +0000875 return strerror(target_to_host_errno(err));
876}
877
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100878#define safe_syscall0(type, name) \
879static type safe_##name(void) \
880{ \
881 return safe_syscall(__NR_##name); \
882}
883
884#define safe_syscall1(type, name, type1, arg1) \
885static type safe_##name(type1 arg1) \
886{ \
887 return safe_syscall(__NR_##name, arg1); \
888}
889
890#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
891static type safe_##name(type1 arg1, type2 arg2) \
892{ \
893 return safe_syscall(__NR_##name, arg1, arg2); \
894}
895
896#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
897static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
898{ \
899 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
900}
901
902#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
903 type4, arg4) \
904static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
905{ \
906 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
907}
908
909#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
910 type4, arg4, type5, arg5) \
911static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
912 type5 arg5) \
913{ \
914 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
915}
916
917#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
918 type4, arg4, type5, arg5, type6, arg6) \
919static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
920 type5 arg5, type6 arg6) \
921{ \
922 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
923}
924
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100925safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
926safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100927safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
928 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100929safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
930 struct rusage *, rusage)
931safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
932 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100933safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100934safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
935 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100936safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
937 struct timespec *, tsp, const sigset_t *, sigmask,
938 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100939safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
940 int, maxevents, int, timeout, const sigset_t *, sigmask,
941 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100942safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
943 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100944safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100945safe_syscall2(int, kill, pid_t, pid, int, sig)
946safe_syscall2(int, tkill, int, tid, int, sig)
947safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100948safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
949safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200950safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
951 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200952safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
953 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100954safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
955 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100956safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
957 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
958safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
959 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
960safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
961safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100962safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100963safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
964 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100965safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
966 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100967safe_syscall2(int, nanosleep, const struct timespec *, req,
968 struct timespec *, rem)
969#ifdef TARGET_NR_clock_nanosleep
970safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
971 const struct timespec *, req, struct timespec *, rem)
972#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100973#ifdef __NR_msgsnd
974safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
975 int, flags)
976safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
977 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100978safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
979 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100980#else
981/* This host kernel architecture uses a single ipc syscall; fake up
982 * wrappers for the sub-operations to hide this implementation detail.
983 * Annoyingly we can't include linux/ipc.h to get the constant definitions
984 * for the call parameter because some structs in there conflict with the
985 * sys/ipc.h ones. So we just define them here, and rely on them being
986 * the same for all host architectures.
987 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100988#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100989#define Q_MSGSND 11
990#define Q_MSGRCV 12
991#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
992
993safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
994 void *, ptr, long, fifth)
995static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
996{
997 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
998}
999static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
1000{
1001 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
1002}
Peter Maydellffb7ee72016-06-06 19:58:12 +01001003static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
1004 const struct timespec *timeout)
1005{
1006 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
1007 (long)timeout);
1008}
Peter Maydell89f9fe42016-06-06 19:58:05 +01001009#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +01001010#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1011safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
1012 size_t, len, unsigned, prio, const struct timespec *, timeout)
1013safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
1014 size_t, len, unsigned *, prio, const struct timespec *, timeout)
1015#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +01001016/* We do ioctl like this rather than via safe_syscall3 to preserve the
1017 * "third argument might be integer or pointer or not present" behaviour of
1018 * the libc function.
1019 */
1020#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +01001021/* Similarly for fcntl. Note that callers must always:
1022 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1023 * use the flock64 struct rather than unsuffixed flock
1024 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1025 */
1026#ifdef __NR_fcntl64
1027#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1028#else
1029#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1030#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001031
Paul Burton8289d112014-06-22 11:25:33 +01001032static inline int host_to_target_sock_type(int host_type)
1033{
1034 int target_type;
1035
1036 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1037 case SOCK_DGRAM:
1038 target_type = TARGET_SOCK_DGRAM;
1039 break;
1040 case SOCK_STREAM:
1041 target_type = TARGET_SOCK_STREAM;
1042 break;
1043 default:
1044 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1045 break;
1046 }
1047
1048#if defined(SOCK_CLOEXEC)
1049 if (host_type & SOCK_CLOEXEC) {
1050 target_type |= TARGET_SOCK_CLOEXEC;
1051 }
1052#endif
1053
1054#if defined(SOCK_NONBLOCK)
1055 if (host_type & SOCK_NONBLOCK) {
1056 target_type |= TARGET_SOCK_NONBLOCK;
1057 }
1058#endif
1059
1060 return target_type;
1061}
1062
blueswir1992f48a2007-10-14 16:27:31 +00001063static abi_ulong target_brk;
1064static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001065static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001066
blueswir1992f48a2007-10-14 16:27:31 +00001067void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001068{
blueswir14c1de732007-07-07 20:45:44 +00001069 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001070 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001071}
1072
vincent4d1de872011-06-14 21:56:33 +00001073//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1074#define DEBUGF_BRK(message, args...)
1075
ths0da46a62007-10-20 20:23:07 +00001076/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001077abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001078{
blueswir1992f48a2007-10-14 16:27:31 +00001079 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001080 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001081
Paul Brook3a0c6c42012-02-09 19:04:27 +00001082 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001083
vincent4d1de872011-06-14 21:56:33 +00001084 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001085 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001086 return target_brk;
1087 }
1088 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001089 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1090 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001091 return target_brk;
1092 }
bellard31e31b82003-02-18 22:55:36 +00001093
vincent4d1de872011-06-14 21:56:33 +00001094 /* If the new brk is less than the highest page reserved to the
1095 * target heap allocation, set it and we're almost done... */
1096 if (new_brk <= brk_page) {
1097 /* Heap contents are initialized to zero, as for anonymous
1098 * mapped pages. */
1099 if (new_brk > target_brk) {
1100 memset(g2h(target_brk), 0, new_brk - target_brk);
1101 }
bellard31e31b82003-02-18 22:55:36 +00001102 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001103 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001104 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001105 }
1106
Peter Maydell00faf082011-04-18 16:34:24 +01001107 /* We need to allocate more memory after the brk... Note that
1108 * we don't use MAP_FIXED because that will map over the top of
1109 * any existing mapping (like the one with the host libc or qemu
1110 * itself); instead we treat "mapped but at wrong address" as
1111 * a failure and unmap again.
1112 */
vincent4d1de872011-06-14 21:56:33 +00001113 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001114 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001115 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001116 MAP_ANON|MAP_PRIVATE, 0, 0));
1117
1118 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001119 /* Heap contents are initialized to zero, as for anonymous
1120 * mapped pages. Technically the new pages are already
1121 * initialized to zero since they *are* anonymous mapped
1122 * pages, however we have to take care with the contents that
1123 * come from the remaining part of the previous page: it may
1124 * contains garbage data due to a previous heap usage (grown
1125 * then shrunken). */
1126 memset(g2h(target_brk), 0, brk_page - target_brk);
1127
Peter Maydell00faf082011-04-18 16:34:24 +01001128 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001129 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001130 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1131 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001132 return target_brk;
1133 } else if (mapped_addr != -1) {
1134 /* Mapped but at wrong address, meaning there wasn't actually
1135 * enough space for this brk.
1136 */
1137 target_munmap(mapped_addr, new_alloc_size);
1138 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001139 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001140 }
1141 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001142 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001143 }
balrog7ab240a2008-04-26 12:17:34 +00001144
Richard Henderson7dd46c02010-05-03 10:07:49 -07001145#if defined(TARGET_ALPHA)
1146 /* We (partially) emulate OSF/1 on Alpha, which requires we
1147 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001148 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001149#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001150 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001151 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001152}
1153
ths26edcf42007-12-09 02:25:24 +00001154static inline abi_long copy_from_user_fdset(fd_set *fds,
1155 abi_ulong target_fds_addr,
1156 int n)
bellard31e31b82003-02-18 22:55:36 +00001157{
ths26edcf42007-12-09 02:25:24 +00001158 int i, nw, j, k;
1159 abi_ulong b, *target_fds;
1160
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001161 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001162 if (!(target_fds = lock_user(VERIFY_READ,
1163 target_fds_addr,
1164 sizeof(abi_ulong) * nw,
1165 1)))
1166 return -TARGET_EFAULT;
1167
1168 FD_ZERO(fds);
1169 k = 0;
1170 for (i = 0; i < nw; i++) {
1171 /* grab the abi_ulong */
1172 __get_user(b, &target_fds[i]);
1173 for (j = 0; j < TARGET_ABI_BITS; j++) {
1174 /* check the bit inside the abi_ulong */
1175 if ((b >> j) & 1)
1176 FD_SET(k, fds);
1177 k++;
bellard31e31b82003-02-18 22:55:36 +00001178 }
bellard31e31b82003-02-18 22:55:36 +00001179 }
ths26edcf42007-12-09 02:25:24 +00001180
1181 unlock_user(target_fds, target_fds_addr, 0);
1182
1183 return 0;
bellard31e31b82003-02-18 22:55:36 +00001184}
1185
Mike Frysinger055e0902011-06-03 17:01:49 -04001186static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1187 abi_ulong target_fds_addr,
1188 int n)
1189{
1190 if (target_fds_addr) {
1191 if (copy_from_user_fdset(fds, target_fds_addr, n))
1192 return -TARGET_EFAULT;
1193 *fds_ptr = fds;
1194 } else {
1195 *fds_ptr = NULL;
1196 }
1197 return 0;
1198}
1199
ths26edcf42007-12-09 02:25:24 +00001200static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1201 const fd_set *fds,
1202 int n)
bellard31e31b82003-02-18 22:55:36 +00001203{
bellard31e31b82003-02-18 22:55:36 +00001204 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001205 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001206 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001207
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001208 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001209 if (!(target_fds = lock_user(VERIFY_WRITE,
1210 target_fds_addr,
1211 sizeof(abi_ulong) * nw,
1212 0)))
1213 return -TARGET_EFAULT;
1214
1215 k = 0;
1216 for (i = 0; i < nw; i++) {
1217 v = 0;
1218 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001219 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001220 k++;
bellard31e31b82003-02-18 22:55:36 +00001221 }
ths26edcf42007-12-09 02:25:24 +00001222 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001223 }
ths26edcf42007-12-09 02:25:24 +00001224
1225 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1226
1227 return 0;
bellard31e31b82003-02-18 22:55:36 +00001228}
1229
bellardc596ed12003-07-13 17:32:31 +00001230#if defined(__alpha__)
1231#define HOST_HZ 1024
1232#else
1233#define HOST_HZ 100
1234#endif
1235
blueswir1992f48a2007-10-14 16:27:31 +00001236static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001237{
1238#if HOST_HZ == TARGET_HZ
1239 return ticks;
1240#else
1241 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1242#endif
1243}
1244
bellard579a97f2007-11-11 14:26:47 +00001245static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1246 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001247{
pbrook53a59602006-03-25 19:31:22 +00001248 struct target_rusage *target_rusage;
1249
bellard579a97f2007-11-11 14:26:47 +00001250 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1251 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001252 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1253 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1254 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1255 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1256 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1257 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1258 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1259 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1260 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1261 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1262 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1263 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1264 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1265 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1266 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1267 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1268 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1269 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001270 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001271
1272 return 0;
bellardb4091862003-05-16 15:39:34 +00001273}
1274
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001275static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001276{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001277 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001278 rlim_t result;
1279
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001280 target_rlim_swap = tswapal(target_rlim);
1281 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1282 return RLIM_INFINITY;
1283
1284 result = target_rlim_swap;
1285 if (target_rlim_swap != (rlim_t)result)
1286 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001287
1288 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001289}
1290
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001291static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001292{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001293 abi_ulong target_rlim_swap;
1294 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001295
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001296 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001297 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001298 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001299 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001300 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001301
1302 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001303}
1304
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001305static inline int target_to_host_resource(int code)
1306{
1307 switch (code) {
1308 case TARGET_RLIMIT_AS:
1309 return RLIMIT_AS;
1310 case TARGET_RLIMIT_CORE:
1311 return RLIMIT_CORE;
1312 case TARGET_RLIMIT_CPU:
1313 return RLIMIT_CPU;
1314 case TARGET_RLIMIT_DATA:
1315 return RLIMIT_DATA;
1316 case TARGET_RLIMIT_FSIZE:
1317 return RLIMIT_FSIZE;
1318 case TARGET_RLIMIT_LOCKS:
1319 return RLIMIT_LOCKS;
1320 case TARGET_RLIMIT_MEMLOCK:
1321 return RLIMIT_MEMLOCK;
1322 case TARGET_RLIMIT_MSGQUEUE:
1323 return RLIMIT_MSGQUEUE;
1324 case TARGET_RLIMIT_NICE:
1325 return RLIMIT_NICE;
1326 case TARGET_RLIMIT_NOFILE:
1327 return RLIMIT_NOFILE;
1328 case TARGET_RLIMIT_NPROC:
1329 return RLIMIT_NPROC;
1330 case TARGET_RLIMIT_RSS:
1331 return RLIMIT_RSS;
1332 case TARGET_RLIMIT_RTPRIO:
1333 return RLIMIT_RTPRIO;
1334 case TARGET_RLIMIT_SIGPENDING:
1335 return RLIMIT_SIGPENDING;
1336 case TARGET_RLIMIT_STACK:
1337 return RLIMIT_STACK;
1338 default:
1339 return code;
1340 }
1341}
1342
ths788f5ec2007-12-09 02:37:05 +00001343static inline abi_long copy_from_user_timeval(struct timeval *tv,
1344 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001345{
pbrook53a59602006-03-25 19:31:22 +00001346 struct target_timeval *target_tv;
1347
ths788f5ec2007-12-09 02:37:05 +00001348 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001349 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001350
1351 __get_user(tv->tv_sec, &target_tv->tv_sec);
1352 __get_user(tv->tv_usec, &target_tv->tv_usec);
1353
1354 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001355
1356 return 0;
bellard31e31b82003-02-18 22:55:36 +00001357}
1358
ths788f5ec2007-12-09 02:37:05 +00001359static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1360 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001361{
pbrook53a59602006-03-25 19:31:22 +00001362 struct target_timeval *target_tv;
1363
ths788f5ec2007-12-09 02:37:05 +00001364 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001365 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001366
1367 __put_user(tv->tv_sec, &target_tv->tv_sec);
1368 __put_user(tv->tv_usec, &target_tv->tv_usec);
1369
1370 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001371
1372 return 0;
bellard31e31b82003-02-18 22:55:36 +00001373}
1374
Paul Burtonef4467e2014-06-22 11:25:40 +01001375static inline abi_long copy_from_user_timezone(struct timezone *tz,
1376 abi_ulong target_tz_addr)
1377{
1378 struct target_timezone *target_tz;
1379
1380 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1381 return -TARGET_EFAULT;
1382 }
1383
1384 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1385 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1386
1387 unlock_user_struct(target_tz, target_tz_addr, 0);
1388
1389 return 0;
1390}
1391
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001392#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1393#include <mqueue.h>
1394
aurel3224e10032009-04-15 16:11:43 +00001395static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1396 abi_ulong target_mq_attr_addr)
1397{
1398 struct target_mq_attr *target_mq_attr;
1399
1400 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1401 target_mq_attr_addr, 1))
1402 return -TARGET_EFAULT;
1403
1404 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1405 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1406 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1407 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1408
1409 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1410
1411 return 0;
1412}
1413
1414static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1415 const struct mq_attr *attr)
1416{
1417 struct target_mq_attr *target_mq_attr;
1418
1419 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1420 target_mq_attr_addr, 0))
1421 return -TARGET_EFAULT;
1422
1423 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1424 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1425 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1426 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1427
1428 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1429
1430 return 0;
1431}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001432#endif
bellard31e31b82003-02-18 22:55:36 +00001433
Mike Frysinger055e0902011-06-03 17:01:49 -04001434#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001435/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001436static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001437 abi_ulong rfd_addr, abi_ulong wfd_addr,
1438 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001439{
1440 fd_set rfds, wfds, efds;
1441 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001442 struct timeval tv;
1443 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001444 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001445
Mike Frysinger055e0902011-06-03 17:01:49 -04001446 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1447 if (ret) {
1448 return ret;
pbrook53a59602006-03-25 19:31:22 +00001449 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001450 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1451 if (ret) {
1452 return ret;
pbrook53a59602006-03-25 19:31:22 +00001453 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001454 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1455 if (ret) {
1456 return ret;
pbrook53a59602006-03-25 19:31:22 +00001457 }
ths3b46e622007-09-17 08:09:54 +00001458
ths26edcf42007-12-09 02:25:24 +00001459 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001460 if (copy_from_user_timeval(&tv, target_tv_addr))
1461 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001462 ts.tv_sec = tv.tv_sec;
1463 ts.tv_nsec = tv.tv_usec * 1000;
1464 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001465 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001466 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001467 }
ths26edcf42007-12-09 02:25:24 +00001468
Peter Maydell6df9d382016-05-12 18:47:51 +01001469 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1470 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001471
ths26edcf42007-12-09 02:25:24 +00001472 if (!is_error(ret)) {
1473 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1474 return -TARGET_EFAULT;
1475 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1476 return -TARGET_EFAULT;
1477 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1478 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001479
Peter Maydell6df9d382016-05-12 18:47:51 +01001480 if (target_tv_addr) {
1481 tv.tv_sec = ts.tv_sec;
1482 tv.tv_usec = ts.tv_nsec / 1000;
1483 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1484 return -TARGET_EFAULT;
1485 }
1486 }
bellard31e31b82003-02-18 22:55:36 +00001487 }
bellard579a97f2007-11-11 14:26:47 +00001488
bellard31e31b82003-02-18 22:55:36 +00001489 return ret;
1490}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001491
1492#if defined(TARGET_WANT_OLD_SYS_SELECT)
1493static abi_long do_old_select(abi_ulong arg1)
1494{
1495 struct target_sel_arg_struct *sel;
1496 abi_ulong inp, outp, exp, tvp;
1497 long nsel;
1498
1499 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1500 return -TARGET_EFAULT;
1501 }
1502
1503 nsel = tswapal(sel->n);
1504 inp = tswapal(sel->inp);
1505 outp = tswapal(sel->outp);
1506 exp = tswapal(sel->exp);
1507 tvp = tswapal(sel->tvp);
1508
1509 unlock_user_struct(sel, arg1, 0);
1510
1511 return do_select(nsel, inp, outp, exp, tvp);
1512}
1513#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001514#endif
bellard31e31b82003-02-18 22:55:36 +00001515
Riku Voipio099d6b02009-05-05 12:10:04 +03001516static abi_long do_pipe2(int host_pipe[], int flags)
1517{
1518#ifdef CONFIG_PIPE2
1519 return pipe2(host_pipe, flags);
1520#else
1521 return -ENOSYS;
1522#endif
1523}
1524
Richard Hendersonfb41a662010-05-03 10:07:52 -07001525static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1526 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001527{
1528 int host_pipe[2];
1529 abi_long ret;
1530 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1531
1532 if (is_error(ret))
1533 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001534
1535 /* Several targets have special calling conventions for the original
1536 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1537 if (!is_pipe2) {
1538#if defined(TARGET_ALPHA)
1539 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1540 return host_pipe[0];
1541#elif defined(TARGET_MIPS)
1542 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1543 return host_pipe[0];
1544#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001545 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001546 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001547#elif defined(TARGET_SPARC)
1548 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1549 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001550#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001551 }
1552
Riku Voipio099d6b02009-05-05 12:10:04 +03001553 if (put_user_s32(host_pipe[0], pipedes)
1554 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1555 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001556 return get_errno(ret);
1557}
1558
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001559static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1560 abi_ulong target_addr,
1561 socklen_t len)
1562{
1563 struct target_ip_mreqn *target_smreqn;
1564
1565 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1566 if (!target_smreqn)
1567 return -TARGET_EFAULT;
1568 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1569 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1570 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001571 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001572 unlock_user(target_smreqn, target_addr, 0);
1573
1574 return 0;
1575}
1576
Laurent Vivier7b36f782015-10-28 21:40:44 +01001577static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001578 abi_ulong target_addr,
1579 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001580{
aurel32607175e2009-04-15 16:11:59 +00001581 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1582 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001583 struct target_sockaddr *target_saddr;
1584
Laurent Vivier7b36f782015-10-28 21:40:44 +01001585 if (fd_trans_target_to_host_addr(fd)) {
1586 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1587 }
1588
bellard579a97f2007-11-11 14:26:47 +00001589 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1590 if (!target_saddr)
1591 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001592
1593 sa_family = tswap16(target_saddr->sa_family);
1594
1595 /* Oops. The caller might send a incomplete sun_path; sun_path
1596 * must be terminated by \0 (see the manual page), but
1597 * unfortunately it is quite common to specify sockaddr_un
1598 * length as "strlen(x->sun_path)" while it should be
1599 * "strlen(...) + 1". We'll fix that here if needed.
1600 * Linux kernel has a similar feature.
1601 */
1602
1603 if (sa_family == AF_UNIX) {
1604 if (len < unix_maxlen && len > 0) {
1605 char *cp = (char*)target_saddr;
1606
1607 if ( cp[len-1] && !cp[len] )
1608 len++;
1609 }
1610 if (len > unix_maxlen)
1611 len = unix_maxlen;
1612 }
1613
pbrook53a59602006-03-25 19:31:22 +00001614 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001615 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001616 if (sa_family == AF_NETLINK) {
1617 struct sockaddr_nl *nladdr;
1618
1619 nladdr = (struct sockaddr_nl *)addr;
1620 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1621 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1622 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001623 struct target_sockaddr_ll *lladdr;
1624
1625 lladdr = (struct target_sockaddr_ll *)addr;
1626 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1627 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1628 }
pbrook53a59602006-03-25 19:31:22 +00001629 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001630
1631 return 0;
bellard7854b052003-03-29 17:22:23 +00001632}
1633
bellard579a97f2007-11-11 14:26:47 +00001634static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1635 struct sockaddr *addr,
1636 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001637{
pbrook53a59602006-03-25 19:31:22 +00001638 struct target_sockaddr *target_saddr;
1639
Peter Maydella1e22192016-07-07 15:44:43 +01001640 if (len == 0) {
1641 return 0;
1642 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001643 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001644
bellard579a97f2007-11-11 14:26:47 +00001645 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1646 if (!target_saddr)
1647 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001648 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001649 if (len >= offsetof(struct target_sockaddr, sa_family) +
1650 sizeof(target_saddr->sa_family)) {
1651 target_saddr->sa_family = tswap16(addr->sa_family);
1652 }
1653 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001654 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1655 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1656 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001657 } else if (addr->sa_family == AF_PACKET) {
1658 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1659 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1660 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001661 } else if (addr->sa_family == AF_INET6 &&
1662 len >= sizeof(struct target_sockaddr_in6)) {
1663 struct target_sockaddr_in6 *target_in6 =
1664 (struct target_sockaddr_in6 *)target_saddr;
1665 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001666 }
pbrook53a59602006-03-25 19:31:22 +00001667 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001668
1669 return 0;
bellard7854b052003-03-29 17:22:23 +00001670}
1671
bellard5a4a8982007-11-11 17:39:18 +00001672static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1673 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001674{
1675 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001676 abi_long msg_controllen;
1677 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001678 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001679 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001680
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001681 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001682 if (msg_controllen < sizeof (struct target_cmsghdr))
1683 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001684 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001685 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001686 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001687 if (!target_cmsg)
1688 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001689
1690 while (cmsg && target_cmsg) {
1691 void *data = CMSG_DATA(cmsg);
1692 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1693
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001694 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001695 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001696
1697 space += CMSG_SPACE(len);
1698 if (space > msgh->msg_controllen) {
1699 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001700 /* This is a QEMU bug, since we allocated the payload
1701 * area ourselves (unlike overflow in host-to-target
1702 * conversion, which is just the guest giving us a buffer
1703 * that's too small). It can't happen for the payload types
1704 * we currently support; if it becomes an issue in future
1705 * we would need to improve our allocation strategy to
1706 * something more intelligent than "twice the size of the
1707 * target buffer we're reading from".
1708 */
bellard31febb72005-12-18 20:03:27 +00001709 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001710 break;
1711 }
1712
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001713 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1714 cmsg->cmsg_level = SOL_SOCKET;
1715 } else {
1716 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1717 }
bellard7854b052003-03-29 17:22:23 +00001718 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1719 cmsg->cmsg_len = CMSG_LEN(len);
1720
Alex Suykov30b8b682014-12-23 07:52:58 +02001721 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001722 int *fd = (int *)data;
1723 int *target_fd = (int *)target_data;
1724 int i, numfds = len / sizeof(int);
1725
Peter Maydell876e23c2015-05-26 19:46:32 +01001726 for (i = 0; i < numfds; i++) {
1727 __get_user(fd[i], target_fd + i);
1728 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001729 } else if (cmsg->cmsg_level == SOL_SOCKET
1730 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1731 struct ucred *cred = (struct ucred *)data;
1732 struct target_ucred *target_cred =
1733 (struct target_ucred *)target_data;
1734
Peter Maydell876e23c2015-05-26 19:46:32 +01001735 __get_user(cred->pid, &target_cred->pid);
1736 __get_user(cred->uid, &target_cred->uid);
1737 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001738 } else {
1739 gemu_log("Unsupported ancillary data: %d/%d\n",
1740 cmsg->cmsg_level, cmsg->cmsg_type);
1741 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001742 }
1743
1744 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001745 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1746 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001747 }
bellard5a4a8982007-11-11 17:39:18 +00001748 unlock_user(target_cmsg, target_cmsg_addr, 0);
1749 the_end:
bellard7854b052003-03-29 17:22:23 +00001750 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001751 return 0;
bellard7854b052003-03-29 17:22:23 +00001752}
1753
bellard5a4a8982007-11-11 17:39:18 +00001754static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1755 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001756{
1757 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001758 abi_long msg_controllen;
1759 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001760 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001761 socklen_t space = 0;
1762
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001763 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001764 if (msg_controllen < sizeof (struct target_cmsghdr))
1765 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001766 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001767 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001768 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001769 if (!target_cmsg)
1770 return -TARGET_EFAULT;
1771
bellard7854b052003-03-29 17:22:23 +00001772 while (cmsg && target_cmsg) {
1773 void *data = CMSG_DATA(cmsg);
1774 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1775
Peter Maydellad762b92017-12-15 13:52:56 +00001776 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001777 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001778
Peter Maydellc2aeb252015-05-26 19:46:31 +01001779 /* We never copy a half-header but may copy half-data;
1780 * this is Linux's behaviour in put_cmsg(). Note that
1781 * truncation here is a guest problem (which we report
1782 * to the guest via the CTRUNC bit), unlike truncation
1783 * in target_to_host_cmsg, which is a QEMU bug.
1784 */
Peter Maydell71749702017-12-15 13:52:55 +00001785 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001786 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001787 break;
1788 }
1789
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001790 if (cmsg->cmsg_level == SOL_SOCKET) {
1791 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1792 } else {
1793 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1794 }
bellard7854b052003-03-29 17:22:23 +00001795 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001796
Peter Maydellc2aeb252015-05-26 19:46:31 +01001797 /* Payload types which need a different size of payload on
1798 * the target must adjust tgt_len here.
1799 */
1800 switch (cmsg->cmsg_level) {
1801 case SOL_SOCKET:
1802 switch (cmsg->cmsg_type) {
1803 case SO_TIMESTAMP:
1804 tgt_len = sizeof(struct target_timeval);
1805 break;
1806 default:
1807 break;
1808 }
1809 default:
Peter Maydell71749702017-12-15 13:52:55 +00001810 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001811 break;
1812 }
1813
Peter Maydell71749702017-12-15 13:52:55 +00001814 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001815 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001816 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001817 }
1818
1819 /* We must now copy-and-convert len bytes of payload
1820 * into tgt_len bytes of destination space. Bear in mind
1821 * that in both source and destination we may be dealing
1822 * with a truncated value!
1823 */
Huw Davies52b65492014-04-17 14:02:47 +01001824 switch (cmsg->cmsg_level) {
1825 case SOL_SOCKET:
1826 switch (cmsg->cmsg_type) {
1827 case SCM_RIGHTS:
1828 {
1829 int *fd = (int *)data;
1830 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001831 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001832
Peter Maydell876e23c2015-05-26 19:46:32 +01001833 for (i = 0; i < numfds; i++) {
1834 __put_user(fd[i], target_fd + i);
1835 }
Huw Davies52b65492014-04-17 14:02:47 +01001836 break;
1837 }
1838 case SO_TIMESTAMP:
1839 {
1840 struct timeval *tv = (struct timeval *)data;
1841 struct target_timeval *target_tv =
1842 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001843
Peter Maydellc2aeb252015-05-26 19:46:31 +01001844 if (len != sizeof(struct timeval) ||
1845 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001846 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001847 }
Huw Davies52b65492014-04-17 14:02:47 +01001848
1849 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001850 __put_user(tv->tv_sec, &target_tv->tv_sec);
1851 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001852 break;
1853 }
Huw Davies4bc29752014-04-17 14:02:48 +01001854 case SCM_CREDENTIALS:
1855 {
1856 struct ucred *cred = (struct ucred *)data;
1857 struct target_ucred *target_cred =
1858 (struct target_ucred *)target_data;
1859
1860 __put_user(cred->pid, &target_cred->pid);
1861 __put_user(cred->uid, &target_cred->uid);
1862 __put_user(cred->gid, &target_cred->gid);
1863 break;
1864 }
Huw Davies52b65492014-04-17 14:02:47 +01001865 default:
1866 goto unimplemented;
1867 }
1868 break;
1869
Helge Delleree1ac3a2017-02-18 23:31:30 +01001870 case SOL_IP:
1871 switch (cmsg->cmsg_type) {
1872 case IP_TTL:
1873 {
1874 uint32_t *v = (uint32_t *)data;
1875 uint32_t *t_int = (uint32_t *)target_data;
1876
Peter Maydell71749702017-12-15 13:52:55 +00001877 if (len != sizeof(uint32_t) ||
1878 tgt_len != sizeof(uint32_t)) {
1879 goto unimplemented;
1880 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001881 __put_user(*v, t_int);
1882 break;
1883 }
1884 case IP_RECVERR:
1885 {
1886 struct errhdr_t {
1887 struct sock_extended_err ee;
1888 struct sockaddr_in offender;
1889 };
1890 struct errhdr_t *errh = (struct errhdr_t *)data;
1891 struct errhdr_t *target_errh =
1892 (struct errhdr_t *)target_data;
1893
Peter Maydell71749702017-12-15 13:52:55 +00001894 if (len != sizeof(struct errhdr_t) ||
1895 tgt_len != sizeof(struct errhdr_t)) {
1896 goto unimplemented;
1897 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001898 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1899 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1900 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1901 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1902 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1903 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1904 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1905 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1906 (void *) &errh->offender, sizeof(errh->offender));
1907 break;
1908 }
1909 default:
1910 goto unimplemented;
1911 }
1912 break;
1913
1914 case SOL_IPV6:
1915 switch (cmsg->cmsg_type) {
1916 case IPV6_HOPLIMIT:
1917 {
1918 uint32_t *v = (uint32_t *)data;
1919 uint32_t *t_int = (uint32_t *)target_data;
1920
Peter Maydell71749702017-12-15 13:52:55 +00001921 if (len != sizeof(uint32_t) ||
1922 tgt_len != sizeof(uint32_t)) {
1923 goto unimplemented;
1924 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001925 __put_user(*v, t_int);
1926 break;
1927 }
1928 case IPV6_RECVERR:
1929 {
1930 struct errhdr6_t {
1931 struct sock_extended_err ee;
1932 struct sockaddr_in6 offender;
1933 };
1934 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1935 struct errhdr6_t *target_errh =
1936 (struct errhdr6_t *)target_data;
1937
Peter Maydell71749702017-12-15 13:52:55 +00001938 if (len != sizeof(struct errhdr6_t) ||
1939 tgt_len != sizeof(struct errhdr6_t)) {
1940 goto unimplemented;
1941 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001942 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1943 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1944 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1945 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1946 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1947 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1948 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1949 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1950 (void *) &errh->offender, sizeof(errh->offender));
1951 break;
1952 }
1953 default:
1954 goto unimplemented;
1955 }
1956 break;
1957
Huw Davies52b65492014-04-17 14:02:47 +01001958 default:
1959 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001960 gemu_log("Unsupported ancillary data: %d/%d\n",
1961 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001962 memcpy(target_data, data, MIN(len, tgt_len));
1963 if (tgt_len > len) {
1964 memset(target_data + len, 0, tgt_len - len);
1965 }
bellard7854b052003-03-29 17:22:23 +00001966 }
1967
Peter Maydell71749702017-12-15 13:52:55 +00001968 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
1969 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001970 if (msg_controllen < tgt_space) {
1971 tgt_space = msg_controllen;
1972 }
1973 msg_controllen -= tgt_space;
1974 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001975 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001976 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1977 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001978 }
bellard5a4a8982007-11-11 17:39:18 +00001979 unlock_user(target_cmsg, target_cmsg_addr, space);
1980 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001981 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001982 return 0;
bellard7854b052003-03-29 17:22:23 +00001983}
1984
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001985static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1986{
1987 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1988 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1989 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1990 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1991 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1992}
1993
1994static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1995 size_t len,
1996 abi_long (*host_to_target_nlmsg)
1997 (struct nlmsghdr *))
1998{
1999 uint32_t nlmsg_len;
2000 abi_long ret;
2001
2002 while (len > sizeof(struct nlmsghdr)) {
2003
2004 nlmsg_len = nlh->nlmsg_len;
2005 if (nlmsg_len < sizeof(struct nlmsghdr) ||
2006 nlmsg_len > len) {
2007 break;
2008 }
2009
2010 switch (nlh->nlmsg_type) {
2011 case NLMSG_DONE:
2012 tswap_nlmsghdr(nlh);
2013 return 0;
2014 case NLMSG_NOOP:
2015 break;
2016 case NLMSG_ERROR:
2017 {
2018 struct nlmsgerr *e = NLMSG_DATA(nlh);
2019 e->error = tswap32(e->error);
2020 tswap_nlmsghdr(&e->msg);
2021 tswap_nlmsghdr(nlh);
2022 return 0;
2023 }
2024 default:
2025 ret = host_to_target_nlmsg(nlh);
2026 if (ret < 0) {
2027 tswap_nlmsghdr(nlh);
2028 return ret;
2029 }
2030 break;
2031 }
2032 tswap_nlmsghdr(nlh);
2033 len -= NLMSG_ALIGN(nlmsg_len);
2034 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
2035 }
2036 return 0;
2037}
2038
2039static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
2040 size_t len,
2041 abi_long (*target_to_host_nlmsg)
2042 (struct nlmsghdr *))
2043{
2044 int ret;
2045
2046 while (len > sizeof(struct nlmsghdr)) {
2047 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
2048 tswap32(nlh->nlmsg_len) > len) {
2049 break;
2050 }
2051 tswap_nlmsghdr(nlh);
2052 switch (nlh->nlmsg_type) {
2053 case NLMSG_DONE:
2054 return 0;
2055 case NLMSG_NOOP:
2056 break;
2057 case NLMSG_ERROR:
2058 {
2059 struct nlmsgerr *e = NLMSG_DATA(nlh);
2060 e->error = tswap32(e->error);
2061 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02002062 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002063 }
2064 default:
2065 ret = target_to_host_nlmsg(nlh);
2066 if (ret < 0) {
2067 return ret;
2068 }
2069 }
2070 len -= NLMSG_ALIGN(nlh->nlmsg_len);
2071 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
2072 }
2073 return 0;
2074}
2075
Laurent Vivier575b22b2016-06-02 22:14:15 +02002076#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02002077static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
2078 size_t len, void *context,
2079 abi_long (*host_to_target_nlattr)
2080 (struct nlattr *,
2081 void *context))
2082{
2083 unsigned short nla_len;
2084 abi_long ret;
2085
2086 while (len > sizeof(struct nlattr)) {
2087 nla_len = nlattr->nla_len;
2088 if (nla_len < sizeof(struct nlattr) ||
2089 nla_len > len) {
2090 break;
2091 }
2092 ret = host_to_target_nlattr(nlattr, context);
2093 nlattr->nla_len = tswap16(nlattr->nla_len);
2094 nlattr->nla_type = tswap16(nlattr->nla_type);
2095 if (ret < 0) {
2096 return ret;
2097 }
2098 len -= NLA_ALIGN(nla_len);
2099 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
2100 }
2101 return 0;
2102}
2103
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002104static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
2105 size_t len,
2106 abi_long (*host_to_target_rtattr)
2107 (struct rtattr *))
2108{
2109 unsigned short rta_len;
2110 abi_long ret;
2111
2112 while (len > sizeof(struct rtattr)) {
2113 rta_len = rtattr->rta_len;
2114 if (rta_len < sizeof(struct rtattr) ||
2115 rta_len > len) {
2116 break;
2117 }
2118 ret = host_to_target_rtattr(rtattr);
2119 rtattr->rta_len = tswap16(rtattr->rta_len);
2120 rtattr->rta_type = tswap16(rtattr->rta_type);
2121 if (ret < 0) {
2122 return ret;
2123 }
2124 len -= RTA_ALIGN(rta_len);
2125 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2126 }
2127 return 0;
2128}
2129
Laurent Vivierc5dff282016-06-27 18:54:30 +02002130#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2131
2132static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2133 void *context)
2134{
2135 uint16_t *u16;
2136 uint32_t *u32;
2137 uint64_t *u64;
2138
2139 switch (nlattr->nla_type) {
2140 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002141 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002142 break;
2143 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002144 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002145 break;
2146 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002147 case QEMU_IFLA_BR_VLAN_FILTERING:
2148 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2149 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2150 case QEMU_IFLA_BR_MCAST_ROUTER:
2151 case QEMU_IFLA_BR_MCAST_SNOOPING:
2152 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2153 case QEMU_IFLA_BR_MCAST_QUERIER:
2154 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2155 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2156 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002157 break;
2158 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002159 case QEMU_IFLA_BR_PRIORITY:
2160 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2161 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2162 case QEMU_IFLA_BR_ROOT_PORT:
2163 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002164 u16 = NLA_DATA(nlattr);
2165 *u16 = tswap16(*u16);
2166 break;
2167 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002168 case QEMU_IFLA_BR_FORWARD_DELAY:
2169 case QEMU_IFLA_BR_HELLO_TIME:
2170 case QEMU_IFLA_BR_MAX_AGE:
2171 case QEMU_IFLA_BR_AGEING_TIME:
2172 case QEMU_IFLA_BR_STP_STATE:
2173 case QEMU_IFLA_BR_ROOT_PATH_COST:
2174 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2175 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2176 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2177 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002178 u32 = NLA_DATA(nlattr);
2179 *u32 = tswap32(*u32);
2180 break;
2181 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002182 case QEMU_IFLA_BR_HELLO_TIMER:
2183 case QEMU_IFLA_BR_TCN_TIMER:
2184 case QEMU_IFLA_BR_GC_TIMER:
2185 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2186 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2187 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2188 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2189 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2190 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2191 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002192 u64 = NLA_DATA(nlattr);
2193 *u64 = tswap64(*u64);
2194 break;
2195 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002196 case QEMU_IFLA_BR_ROOT_ID:
2197 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002198 break;
2199 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002200 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002201 break;
2202 }
2203 return 0;
2204}
2205
2206static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2207 void *context)
2208{
2209 uint16_t *u16;
2210 uint32_t *u32;
2211 uint64_t *u64;
2212
2213 switch (nlattr->nla_type) {
2214 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002215 case QEMU_IFLA_BRPORT_STATE:
2216 case QEMU_IFLA_BRPORT_MODE:
2217 case QEMU_IFLA_BRPORT_GUARD:
2218 case QEMU_IFLA_BRPORT_PROTECT:
2219 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2220 case QEMU_IFLA_BRPORT_LEARNING:
2221 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2222 case QEMU_IFLA_BRPORT_PROXYARP:
2223 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2224 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2225 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2226 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2227 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002228 break;
2229 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002230 case QEMU_IFLA_BRPORT_PRIORITY:
2231 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2232 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2233 case QEMU_IFLA_BRPORT_ID:
2234 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002235 u16 = NLA_DATA(nlattr);
2236 *u16 = tswap16(*u16);
2237 break;
2238 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002239 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002240 u32 = NLA_DATA(nlattr);
2241 *u32 = tswap32(*u32);
2242 break;
2243 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002244 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2245 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2246 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002247 u64 = NLA_DATA(nlattr);
2248 *u64 = tswap64(*u64);
2249 break;
2250 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002251 case QEMU_IFLA_BRPORT_ROOT_ID:
2252 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002253 break;
2254 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002255 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002256 break;
2257 }
2258 return 0;
2259}
2260
2261struct linkinfo_context {
2262 int len;
2263 char *name;
2264 int slave_len;
2265 char *slave_name;
2266};
2267
2268static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2269 void *context)
2270{
2271 struct linkinfo_context *li_context = context;
2272
2273 switch (nlattr->nla_type) {
2274 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002275 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002276 li_context->name = NLA_DATA(nlattr);
2277 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2278 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002279 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002280 li_context->slave_name = NLA_DATA(nlattr);
2281 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2282 break;
2283 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002284 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002285 /* FIXME: only used by CAN */
2286 break;
2287 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002288 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002289 if (strncmp(li_context->name, "bridge",
2290 li_context->len) == 0) {
2291 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2292 nlattr->nla_len,
2293 NULL,
2294 host_to_target_data_bridge_nlattr);
2295 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002296 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002297 }
2298 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002299 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002300 if (strncmp(li_context->slave_name, "bridge",
2301 li_context->slave_len) == 0) {
2302 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2303 nlattr->nla_len,
2304 NULL,
2305 host_to_target_slave_data_bridge_nlattr);
2306 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002307 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002308 li_context->slave_name);
2309 }
2310 break;
2311 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002312 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002313 break;
2314 }
2315
2316 return 0;
2317}
2318
2319static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2320 void *context)
2321{
2322 uint32_t *u32;
2323 int i;
2324
2325 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002326 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002327 u32 = NLA_DATA(nlattr);
2328 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2329 i++) {
2330 u32[i] = tswap32(u32[i]);
2331 }
2332 break;
2333 default:
2334 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2335 }
2336 return 0;
2337}
2338
2339static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2340 void *context)
2341{
2342 uint32_t *u32;
2343 uint64_t *u64;
2344 struct ifla_cacheinfo *ci;
2345 int i;
2346
2347 switch (nlattr->nla_type) {
2348 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002349 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002350 break;
2351 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002352 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002353 break;
2354 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002355 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002356 u32 = NLA_DATA(nlattr);
2357 *u32 = tswap32(*u32);
2358 break;
2359 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002360 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002361 u32 = NLA_DATA(nlattr);
2362 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2363 i++) {
2364 u32[i] = tswap32(u32[i]);
2365 }
2366 break;
2367 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002368 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002369 ci = NLA_DATA(nlattr);
2370 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2371 ci->tstamp = tswap32(ci->tstamp);
2372 ci->reachable_time = tswap32(ci->reachable_time);
2373 ci->retrans_time = tswap32(ci->retrans_time);
2374 break;
2375 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002376 case QEMU_IFLA_INET6_STATS:
2377 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002378 u64 = NLA_DATA(nlattr);
2379 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2380 i++) {
2381 u64[i] = tswap64(u64[i]);
2382 }
2383 break;
2384 default:
2385 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2386 }
2387 return 0;
2388}
2389
2390static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2391 void *context)
2392{
2393 switch (nlattr->nla_type) {
2394 case AF_INET:
2395 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2396 NULL,
2397 host_to_target_data_inet_nlattr);
2398 case AF_INET6:
2399 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2400 NULL,
2401 host_to_target_data_inet6_nlattr);
2402 default:
2403 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2404 break;
2405 }
2406 return 0;
2407}
2408
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002409static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2410{
2411 uint32_t *u32;
2412 struct rtnl_link_stats *st;
2413 struct rtnl_link_stats64 *st64;
2414 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002415 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002416
2417 switch (rtattr->rta_type) {
2418 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002419 case QEMU_IFLA_ADDRESS:
2420 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002421 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002422 case QEMU_IFLA_IFNAME:
2423 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002424 break;
2425 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002426 case QEMU_IFLA_OPERSTATE:
2427 case QEMU_IFLA_LINKMODE:
2428 case QEMU_IFLA_CARRIER:
2429 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002430 break;
2431 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002432 case QEMU_IFLA_MTU:
2433 case QEMU_IFLA_LINK:
2434 case QEMU_IFLA_WEIGHT:
2435 case QEMU_IFLA_TXQLEN:
2436 case QEMU_IFLA_CARRIER_CHANGES:
2437 case QEMU_IFLA_NUM_RX_QUEUES:
2438 case QEMU_IFLA_NUM_TX_QUEUES:
2439 case QEMU_IFLA_PROMISCUITY:
2440 case QEMU_IFLA_EXT_MASK:
2441 case QEMU_IFLA_LINK_NETNSID:
2442 case QEMU_IFLA_GROUP:
2443 case QEMU_IFLA_MASTER:
2444 case QEMU_IFLA_NUM_VF:
Laurent Viviera1488b82016-10-27 03:00:49 +02002445 case QEMU_IFLA_GSO_MAX_SEGS:
2446 case QEMU_IFLA_GSO_MAX_SIZE:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002447 u32 = RTA_DATA(rtattr);
2448 *u32 = tswap32(*u32);
2449 break;
2450 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002451 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002452 st = RTA_DATA(rtattr);
2453 st->rx_packets = tswap32(st->rx_packets);
2454 st->tx_packets = tswap32(st->tx_packets);
2455 st->rx_bytes = tswap32(st->rx_bytes);
2456 st->tx_bytes = tswap32(st->tx_bytes);
2457 st->rx_errors = tswap32(st->rx_errors);
2458 st->tx_errors = tswap32(st->tx_errors);
2459 st->rx_dropped = tswap32(st->rx_dropped);
2460 st->tx_dropped = tswap32(st->tx_dropped);
2461 st->multicast = tswap32(st->multicast);
2462 st->collisions = tswap32(st->collisions);
2463
2464 /* detailed rx_errors: */
2465 st->rx_length_errors = tswap32(st->rx_length_errors);
2466 st->rx_over_errors = tswap32(st->rx_over_errors);
2467 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2468 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2469 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2470 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2471
2472 /* detailed tx_errors */
2473 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2474 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2475 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2476 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2477 st->tx_window_errors = tswap32(st->tx_window_errors);
2478
2479 /* for cslip etc */
2480 st->rx_compressed = tswap32(st->rx_compressed);
2481 st->tx_compressed = tswap32(st->tx_compressed);
2482 break;
2483 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002484 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002485 st64 = RTA_DATA(rtattr);
2486 st64->rx_packets = tswap64(st64->rx_packets);
2487 st64->tx_packets = tswap64(st64->tx_packets);
2488 st64->rx_bytes = tswap64(st64->rx_bytes);
2489 st64->tx_bytes = tswap64(st64->tx_bytes);
2490 st64->rx_errors = tswap64(st64->rx_errors);
2491 st64->tx_errors = tswap64(st64->tx_errors);
2492 st64->rx_dropped = tswap64(st64->rx_dropped);
2493 st64->tx_dropped = tswap64(st64->tx_dropped);
2494 st64->multicast = tswap64(st64->multicast);
2495 st64->collisions = tswap64(st64->collisions);
2496
2497 /* detailed rx_errors: */
2498 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2499 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2500 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2501 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2502 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2503 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2504
2505 /* detailed tx_errors */
2506 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2507 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2508 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2509 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2510 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2511
2512 /* for cslip etc */
2513 st64->rx_compressed = tswap64(st64->rx_compressed);
2514 st64->tx_compressed = tswap64(st64->tx_compressed);
2515 break;
2516 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002517 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002518 map = RTA_DATA(rtattr);
2519 map->mem_start = tswap64(map->mem_start);
2520 map->mem_end = tswap64(map->mem_end);
2521 map->base_addr = tswap64(map->base_addr);
2522 map->irq = tswap16(map->irq);
2523 break;
2524 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002525 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002526 memset(&li_context, 0, sizeof(li_context));
2527 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2528 &li_context,
2529 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002530 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002531 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2532 NULL,
2533 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002534 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002535 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002536 break;
2537 }
2538 return 0;
2539}
2540
2541static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2542{
2543 uint32_t *u32;
2544 struct ifa_cacheinfo *ci;
2545
2546 switch (rtattr->rta_type) {
2547 /* binary: depends on family type */
2548 case IFA_ADDRESS:
2549 case IFA_LOCAL:
2550 break;
2551 /* string */
2552 case IFA_LABEL:
2553 break;
2554 /* u32 */
2555 case IFA_FLAGS:
2556 case IFA_BROADCAST:
2557 u32 = RTA_DATA(rtattr);
2558 *u32 = tswap32(*u32);
2559 break;
2560 /* struct ifa_cacheinfo */
2561 case IFA_CACHEINFO:
2562 ci = RTA_DATA(rtattr);
2563 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2564 ci->ifa_valid = tswap32(ci->ifa_valid);
2565 ci->cstamp = tswap32(ci->cstamp);
2566 ci->tstamp = tswap32(ci->tstamp);
2567 break;
2568 default:
2569 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2570 break;
2571 }
2572 return 0;
2573}
2574
2575static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2576{
2577 uint32_t *u32;
2578 switch (rtattr->rta_type) {
2579 /* binary: depends on family type */
2580 case RTA_GATEWAY:
2581 case RTA_DST:
2582 case RTA_PREFSRC:
2583 break;
2584 /* u32 */
2585 case RTA_PRIORITY:
2586 case RTA_TABLE:
2587 case RTA_OIF:
2588 u32 = RTA_DATA(rtattr);
2589 *u32 = tswap32(*u32);
2590 break;
2591 default:
2592 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2593 break;
2594 }
2595 return 0;
2596}
2597
2598static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2599 uint32_t rtattr_len)
2600{
2601 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2602 host_to_target_data_link_rtattr);
2603}
2604
2605static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2606 uint32_t rtattr_len)
2607{
2608 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2609 host_to_target_data_addr_rtattr);
2610}
2611
2612static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2613 uint32_t rtattr_len)
2614{
2615 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2616 host_to_target_data_route_rtattr);
2617}
2618
2619static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2620{
2621 uint32_t nlmsg_len;
2622 struct ifinfomsg *ifi;
2623 struct ifaddrmsg *ifa;
2624 struct rtmsg *rtm;
2625
2626 nlmsg_len = nlh->nlmsg_len;
2627 switch (nlh->nlmsg_type) {
2628 case RTM_NEWLINK:
2629 case RTM_DELLINK:
2630 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002631 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2632 ifi = NLMSG_DATA(nlh);
2633 ifi->ifi_type = tswap16(ifi->ifi_type);
2634 ifi->ifi_index = tswap32(ifi->ifi_index);
2635 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2636 ifi->ifi_change = tswap32(ifi->ifi_change);
2637 host_to_target_link_rtattr(IFLA_RTA(ifi),
2638 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2639 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002640 break;
2641 case RTM_NEWADDR:
2642 case RTM_DELADDR:
2643 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002644 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2645 ifa = NLMSG_DATA(nlh);
2646 ifa->ifa_index = tswap32(ifa->ifa_index);
2647 host_to_target_addr_rtattr(IFA_RTA(ifa),
2648 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2649 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002650 break;
2651 case RTM_NEWROUTE:
2652 case RTM_DELROUTE:
2653 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002654 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2655 rtm = NLMSG_DATA(nlh);
2656 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2657 host_to_target_route_rtattr(RTM_RTA(rtm),
2658 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2659 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002660 break;
2661 default:
2662 return -TARGET_EINVAL;
2663 }
2664 return 0;
2665}
2666
2667static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2668 size_t len)
2669{
2670 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2671}
2672
2673static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2674 size_t len,
2675 abi_long (*target_to_host_rtattr)
2676 (struct rtattr *))
2677{
2678 abi_long ret;
2679
2680 while (len >= sizeof(struct rtattr)) {
2681 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2682 tswap16(rtattr->rta_len) > len) {
2683 break;
2684 }
2685 rtattr->rta_len = tswap16(rtattr->rta_len);
2686 rtattr->rta_type = tswap16(rtattr->rta_type);
2687 ret = target_to_host_rtattr(rtattr);
2688 if (ret < 0) {
2689 return ret;
2690 }
2691 len -= RTA_ALIGN(rtattr->rta_len);
2692 rtattr = (struct rtattr *)(((char *)rtattr) +
2693 RTA_ALIGN(rtattr->rta_len));
2694 }
2695 return 0;
2696}
2697
2698static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2699{
2700 switch (rtattr->rta_type) {
2701 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002702 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002703 break;
2704 }
2705 return 0;
2706}
2707
2708static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2709{
2710 switch (rtattr->rta_type) {
2711 /* binary: depends on family type */
2712 case IFA_LOCAL:
2713 case IFA_ADDRESS:
2714 break;
2715 default:
2716 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2717 break;
2718 }
2719 return 0;
2720}
2721
2722static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2723{
2724 uint32_t *u32;
2725 switch (rtattr->rta_type) {
2726 /* binary: depends on family type */
2727 case RTA_DST:
2728 case RTA_SRC:
2729 case RTA_GATEWAY:
2730 break;
2731 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002732 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002733 case RTA_OIF:
2734 u32 = RTA_DATA(rtattr);
2735 *u32 = tswap32(*u32);
2736 break;
2737 default:
2738 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2739 break;
2740 }
2741 return 0;
2742}
2743
2744static void target_to_host_link_rtattr(struct rtattr *rtattr,
2745 uint32_t rtattr_len)
2746{
2747 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2748 target_to_host_data_link_rtattr);
2749}
2750
2751static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2752 uint32_t rtattr_len)
2753{
2754 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2755 target_to_host_data_addr_rtattr);
2756}
2757
2758static void target_to_host_route_rtattr(struct rtattr *rtattr,
2759 uint32_t rtattr_len)
2760{
2761 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2762 target_to_host_data_route_rtattr);
2763}
2764
2765static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2766{
2767 struct ifinfomsg *ifi;
2768 struct ifaddrmsg *ifa;
2769 struct rtmsg *rtm;
2770
2771 switch (nlh->nlmsg_type) {
2772 case RTM_GETLINK:
2773 break;
2774 case RTM_NEWLINK:
2775 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002776 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2777 ifi = NLMSG_DATA(nlh);
2778 ifi->ifi_type = tswap16(ifi->ifi_type);
2779 ifi->ifi_index = tswap32(ifi->ifi_index);
2780 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2781 ifi->ifi_change = tswap32(ifi->ifi_change);
2782 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2783 NLMSG_LENGTH(sizeof(*ifi)));
2784 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002785 break;
2786 case RTM_GETADDR:
2787 case RTM_NEWADDR:
2788 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002789 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2790 ifa = NLMSG_DATA(nlh);
2791 ifa->ifa_index = tswap32(ifa->ifa_index);
2792 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2793 NLMSG_LENGTH(sizeof(*ifa)));
2794 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002795 break;
2796 case RTM_GETROUTE:
2797 break;
2798 case RTM_NEWROUTE:
2799 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002800 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2801 rtm = NLMSG_DATA(nlh);
2802 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2803 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2804 NLMSG_LENGTH(sizeof(*rtm)));
2805 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002806 break;
2807 default:
2808 return -TARGET_EOPNOTSUPP;
2809 }
2810 return 0;
2811}
2812
2813static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2814{
2815 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2816}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002817#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002818
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002819static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2820{
2821 switch (nlh->nlmsg_type) {
2822 default:
2823 gemu_log("Unknown host audit message type %d\n",
2824 nlh->nlmsg_type);
2825 return -TARGET_EINVAL;
2826 }
2827 return 0;
2828}
2829
2830static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2831 size_t len)
2832{
2833 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2834}
2835
2836static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2837{
2838 switch (nlh->nlmsg_type) {
2839 case AUDIT_USER:
2840 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2841 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2842 break;
2843 default:
2844 gemu_log("Unknown target audit message type %d\n",
2845 nlh->nlmsg_type);
2846 return -TARGET_EINVAL;
2847 }
2848
2849 return 0;
2850}
2851
2852static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2853{
2854 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2855}
2856
ths0da46a62007-10-20 20:23:07 +00002857/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002858static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002859 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002860{
blueswir1992f48a2007-10-14 16:27:31 +00002861 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002862 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002863 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002864 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002865
bellard8853f862004-02-22 14:57:26 +00002866 switch(level) {
2867 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002868 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002869 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002870 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002871
bellard2f619692007-11-16 10:46:05 +00002872 if (get_user_u32(val, optval_addr))
2873 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002874 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2875 break;
2876 case SOL_IP:
2877 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002878 case IP_TOS:
2879 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002880 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002881 case IP_ROUTER_ALERT:
2882 case IP_RECVOPTS:
2883 case IP_RETOPTS:
2884 case IP_PKTINFO:
2885 case IP_MTU_DISCOVER:
2886 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002887 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002888 case IP_RECVTOS:
2889#ifdef IP_FREEBIND
2890 case IP_FREEBIND:
2891#endif
2892 case IP_MULTICAST_TTL:
2893 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002894 val = 0;
2895 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002896 if (get_user_u32(val, optval_addr))
2897 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002898 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002899 if (get_user_u8(val, optval_addr))
2900 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002901 }
2902 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2903 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002904 case IP_ADD_MEMBERSHIP:
2905 case IP_DROP_MEMBERSHIP:
2906 if (optlen < sizeof (struct target_ip_mreq) ||
2907 optlen > sizeof (struct target_ip_mreqn))
2908 return -TARGET_EINVAL;
2909
2910 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2911 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2912 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2913 break;
2914
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002915 case IP_BLOCK_SOURCE:
2916 case IP_UNBLOCK_SOURCE:
2917 case IP_ADD_SOURCE_MEMBERSHIP:
2918 case IP_DROP_SOURCE_MEMBERSHIP:
2919 if (optlen != sizeof (struct target_ip_mreq_source))
2920 return -TARGET_EINVAL;
2921
2922 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2923 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2924 unlock_user (ip_mreq_source, optval_addr, 0);
2925 break;
2926
bellard8853f862004-02-22 14:57:26 +00002927 default:
2928 goto unimplemented;
2929 }
2930 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002931 case SOL_IPV6:
2932 switch (optname) {
2933 case IPV6_MTU_DISCOVER:
2934 case IPV6_MTU:
2935 case IPV6_V6ONLY:
2936 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002937 case IPV6_UNICAST_HOPS:
2938 case IPV6_RECVERR:
2939 case IPV6_RECVHOPLIMIT:
2940 case IPV6_2292HOPLIMIT:
2941 case IPV6_CHECKSUM:
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002942 val = 0;
2943 if (optlen < sizeof(uint32_t)) {
2944 return -TARGET_EINVAL;
2945 }
2946 if (get_user_u32(val, optval_addr)) {
2947 return -TARGET_EFAULT;
2948 }
2949 ret = get_errno(setsockopt(sockfd, level, optname,
2950 &val, sizeof(val)));
2951 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002952 case IPV6_PKTINFO:
2953 {
2954 struct in6_pktinfo pki;
2955
2956 if (optlen < sizeof(pki)) {
2957 return -TARGET_EINVAL;
2958 }
2959
2960 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2961 return -TARGET_EFAULT;
2962 }
2963
2964 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2965
2966 ret = get_errno(setsockopt(sockfd, level, optname,
2967 &pki, sizeof(pki)));
2968 break;
2969 }
2970 default:
2971 goto unimplemented;
2972 }
2973 break;
2974 case SOL_ICMPV6:
2975 switch (optname) {
2976 case ICMPV6_FILTER:
2977 {
2978 struct icmp6_filter icmp6f;
2979
2980 if (optlen > sizeof(icmp6f)) {
2981 optlen = sizeof(icmp6f);
2982 }
2983
2984 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
2985 return -TARGET_EFAULT;
2986 }
2987
2988 for (val = 0; val < 8; val++) {
2989 icmp6f.data[val] = tswap32(icmp6f.data[val]);
2990 }
2991
2992 ret = get_errno(setsockopt(sockfd, level, optname,
2993 &icmp6f, optlen));
2994 break;
2995 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002996 default:
2997 goto unimplemented;
2998 }
2999 break;
Jing Huang920394d2012-07-24 13:59:23 +00003000 case SOL_RAW:
3001 switch (optname) {
3002 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003003 case IPV6_CHECKSUM:
3004 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00003005 if (optlen < sizeof(uint32_t)) {
3006 return -TARGET_EINVAL;
3007 }
3008
3009 if (get_user_u32(val, optval_addr)) {
3010 return -TARGET_EFAULT;
3011 }
3012 ret = get_errno(setsockopt(sockfd, level, optname,
3013 &val, sizeof(val)));
3014 break;
3015
3016 default:
3017 goto unimplemented;
3018 }
3019 break;
bellard3532fa72006-06-24 15:06:03 +00003020 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00003021 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00003022 case TARGET_SO_RCVTIMEO:
3023 {
3024 struct timeval tv;
3025
3026 optname = SO_RCVTIMEO;
3027
3028set_timeout:
3029 if (optlen != sizeof(struct target_timeval)) {
3030 return -TARGET_EINVAL;
3031 }
3032
3033 if (copy_from_user_timeval(&tv, optval_addr)) {
3034 return -TARGET_EFAULT;
3035 }
3036
3037 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3038 &tv, sizeof(tv)));
3039 return ret;
3040 }
3041 case TARGET_SO_SNDTIMEO:
3042 optname = SO_SNDTIMEO;
3043 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02003044 case TARGET_SO_ATTACH_FILTER:
3045 {
3046 struct target_sock_fprog *tfprog;
3047 struct target_sock_filter *tfilter;
3048 struct sock_fprog fprog;
3049 struct sock_filter *filter;
3050 int i;
3051
3052 if (optlen != sizeof(*tfprog)) {
3053 return -TARGET_EINVAL;
3054 }
3055 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
3056 return -TARGET_EFAULT;
3057 }
3058 if (!lock_user_struct(VERIFY_READ, tfilter,
3059 tswapal(tfprog->filter), 0)) {
3060 unlock_user_struct(tfprog, optval_addr, 1);
3061 return -TARGET_EFAULT;
3062 }
3063
3064 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303065 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003066 if (filter == NULL) {
3067 unlock_user_struct(tfilter, tfprog->filter, 1);
3068 unlock_user_struct(tfprog, optval_addr, 1);
3069 return -TARGET_ENOMEM;
3070 }
3071 for (i = 0; i < fprog.len; i++) {
3072 filter[i].code = tswap16(tfilter[i].code);
3073 filter[i].jt = tfilter[i].jt;
3074 filter[i].jf = tfilter[i].jf;
3075 filter[i].k = tswap32(tfilter[i].k);
3076 }
3077 fprog.filter = filter;
3078
3079 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
3080 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303081 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003082
3083 unlock_user_struct(tfilter, tfprog->filter, 1);
3084 unlock_user_struct(tfprog, optval_addr, 1);
3085 return ret;
3086 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003087 case TARGET_SO_BINDTODEVICE:
3088 {
3089 char *dev_ifname, *addr_ifname;
3090
3091 if (optlen > IFNAMSIZ - 1) {
3092 optlen = IFNAMSIZ - 1;
3093 }
3094 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3095 if (!dev_ifname) {
3096 return -TARGET_EFAULT;
3097 }
3098 optname = SO_BINDTODEVICE;
3099 addr_ifname = alloca(IFNAMSIZ);
3100 memcpy(addr_ifname, dev_ifname, optlen);
3101 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08003102 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3103 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003104 unlock_user (dev_ifname, optval_addr, 0);
3105 return ret;
3106 }
bellard8853f862004-02-22 14:57:26 +00003107 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00003108 case TARGET_SO_DEBUG:
3109 optname = SO_DEBUG;
3110 break;
3111 case TARGET_SO_REUSEADDR:
3112 optname = SO_REUSEADDR;
3113 break;
3114 case TARGET_SO_TYPE:
3115 optname = SO_TYPE;
3116 break;
3117 case TARGET_SO_ERROR:
3118 optname = SO_ERROR;
3119 break;
3120 case TARGET_SO_DONTROUTE:
3121 optname = SO_DONTROUTE;
3122 break;
3123 case TARGET_SO_BROADCAST:
3124 optname = SO_BROADCAST;
3125 break;
3126 case TARGET_SO_SNDBUF:
3127 optname = SO_SNDBUF;
3128 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003129 case TARGET_SO_SNDBUFFORCE:
3130 optname = SO_SNDBUFFORCE;
3131 break;
bellard3532fa72006-06-24 15:06:03 +00003132 case TARGET_SO_RCVBUF:
3133 optname = SO_RCVBUF;
3134 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003135 case TARGET_SO_RCVBUFFORCE:
3136 optname = SO_RCVBUFFORCE;
3137 break;
bellard3532fa72006-06-24 15:06:03 +00003138 case TARGET_SO_KEEPALIVE:
3139 optname = SO_KEEPALIVE;
3140 break;
3141 case TARGET_SO_OOBINLINE:
3142 optname = SO_OOBINLINE;
3143 break;
3144 case TARGET_SO_NO_CHECK:
3145 optname = SO_NO_CHECK;
3146 break;
3147 case TARGET_SO_PRIORITY:
3148 optname = SO_PRIORITY;
3149 break;
bellard5e83e8e2005-03-01 22:32:06 +00003150#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00003151 case TARGET_SO_BSDCOMPAT:
3152 optname = SO_BSDCOMPAT;
3153 break;
bellard5e83e8e2005-03-01 22:32:06 +00003154#endif
bellard3532fa72006-06-24 15:06:03 +00003155 case TARGET_SO_PASSCRED:
3156 optname = SO_PASSCRED;
3157 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01003158 case TARGET_SO_PASSSEC:
3159 optname = SO_PASSSEC;
3160 break;
bellard3532fa72006-06-24 15:06:03 +00003161 case TARGET_SO_TIMESTAMP:
3162 optname = SO_TIMESTAMP;
3163 break;
3164 case TARGET_SO_RCVLOWAT:
3165 optname = SO_RCVLOWAT;
3166 break;
bellard8853f862004-02-22 14:57:26 +00003167 default:
3168 goto unimplemented;
3169 }
bellard3532fa72006-06-24 15:06:03 +00003170 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003171 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003172
bellard2f619692007-11-16 10:46:05 +00003173 if (get_user_u32(val, optval_addr))
3174 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003175 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003176 break;
bellard7854b052003-03-29 17:22:23 +00003177 default:
bellard8853f862004-02-22 14:57:26 +00003178 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003179 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003180 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003181 }
bellard8853f862004-02-22 14:57:26 +00003182 return ret;
bellard7854b052003-03-29 17:22:23 +00003183}
3184
ths0da46a62007-10-20 20:23:07 +00003185/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003186static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003187 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003188{
blueswir1992f48a2007-10-14 16:27:31 +00003189 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003190 int len, val;
3191 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003192
3193 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003194 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003195 level = SOL_SOCKET;
3196 switch (optname) {
3197 /* These don't just return a single integer */
3198 case TARGET_SO_LINGER:
3199 case TARGET_SO_RCVTIMEO:
3200 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003201 case TARGET_SO_PEERNAME:
3202 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003203 case TARGET_SO_PEERCRED: {
3204 struct ucred cr;
3205 socklen_t crlen;
3206 struct target_ucred *tcr;
3207
3208 if (get_user_u32(len, optlen)) {
3209 return -TARGET_EFAULT;
3210 }
3211 if (len < 0) {
3212 return -TARGET_EINVAL;
3213 }
3214
3215 crlen = sizeof(cr);
3216 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3217 &cr, &crlen));
3218 if (ret < 0) {
3219 return ret;
3220 }
3221 if (len > crlen) {
3222 len = crlen;
3223 }
3224 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3225 return -TARGET_EFAULT;
3226 }
3227 __put_user(cr.pid, &tcr->pid);
3228 __put_user(cr.uid, &tcr->uid);
3229 __put_user(cr.gid, &tcr->gid);
3230 unlock_user_struct(tcr, optval_addr, 1);
3231 if (put_user_u32(len, optlen)) {
3232 return -TARGET_EFAULT;
3233 }
3234 break;
3235 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003236 /* Options with 'int' argument. */
3237 case TARGET_SO_DEBUG:
3238 optname = SO_DEBUG;
3239 goto int_case;
3240 case TARGET_SO_REUSEADDR:
3241 optname = SO_REUSEADDR;
3242 goto int_case;
3243 case TARGET_SO_TYPE:
3244 optname = SO_TYPE;
3245 goto int_case;
3246 case TARGET_SO_ERROR:
3247 optname = SO_ERROR;
3248 goto int_case;
3249 case TARGET_SO_DONTROUTE:
3250 optname = SO_DONTROUTE;
3251 goto int_case;
3252 case TARGET_SO_BROADCAST:
3253 optname = SO_BROADCAST;
3254 goto int_case;
3255 case TARGET_SO_SNDBUF:
3256 optname = SO_SNDBUF;
3257 goto int_case;
3258 case TARGET_SO_RCVBUF:
3259 optname = SO_RCVBUF;
3260 goto int_case;
3261 case TARGET_SO_KEEPALIVE:
3262 optname = SO_KEEPALIVE;
3263 goto int_case;
3264 case TARGET_SO_OOBINLINE:
3265 optname = SO_OOBINLINE;
3266 goto int_case;
3267 case TARGET_SO_NO_CHECK:
3268 optname = SO_NO_CHECK;
3269 goto int_case;
3270 case TARGET_SO_PRIORITY:
3271 optname = SO_PRIORITY;
3272 goto int_case;
3273#ifdef SO_BSDCOMPAT
3274 case TARGET_SO_BSDCOMPAT:
3275 optname = SO_BSDCOMPAT;
3276 goto int_case;
3277#endif
3278 case TARGET_SO_PASSCRED:
3279 optname = SO_PASSCRED;
3280 goto int_case;
3281 case TARGET_SO_TIMESTAMP:
3282 optname = SO_TIMESTAMP;
3283 goto int_case;
3284 case TARGET_SO_RCVLOWAT:
3285 optname = SO_RCVLOWAT;
3286 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003287 case TARGET_SO_ACCEPTCONN:
3288 optname = SO_ACCEPTCONN;
3289 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003290 default:
bellard2efbe912005-07-23 15:10:20 +00003291 goto int_case;
3292 }
3293 break;
3294 case SOL_TCP:
3295 /* TCP options all take an 'int' value. */
3296 int_case:
bellard2f619692007-11-16 10:46:05 +00003297 if (get_user_u32(len, optlen))
3298 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003299 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003300 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003301 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003302 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3303 if (ret < 0)
3304 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003305 if (optname == SO_TYPE) {
3306 val = host_to_target_sock_type(val);
3307 }
bellard2efbe912005-07-23 15:10:20 +00003308 if (len > lv)
3309 len = lv;
bellard2f619692007-11-16 10:46:05 +00003310 if (len == 4) {
3311 if (put_user_u32(val, optval_addr))
3312 return -TARGET_EFAULT;
3313 } else {
3314 if (put_user_u8(val, optval_addr))
3315 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003316 }
bellard2f619692007-11-16 10:46:05 +00003317 if (put_user_u32(len, optlen))
3318 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003319 break;
3320 case SOL_IP:
3321 switch(optname) {
3322 case IP_TOS:
3323 case IP_TTL:
3324 case IP_HDRINCL:
3325 case IP_ROUTER_ALERT:
3326 case IP_RECVOPTS:
3327 case IP_RETOPTS:
3328 case IP_PKTINFO:
3329 case IP_MTU_DISCOVER:
3330 case IP_RECVERR:
3331 case IP_RECVTOS:
3332#ifdef IP_FREEBIND
3333 case IP_FREEBIND:
3334#endif
3335 case IP_MULTICAST_TTL:
3336 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003337 if (get_user_u32(len, optlen))
3338 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003339 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003340 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003341 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003342 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3343 if (ret < 0)
3344 return ret;
bellard2efbe912005-07-23 15:10:20 +00003345 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003346 len = 1;
bellard2f619692007-11-16 10:46:05 +00003347 if (put_user_u32(len, optlen)
3348 || put_user_u8(val, optval_addr))
3349 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003350 } else {
bellard2efbe912005-07-23 15:10:20 +00003351 if (len > sizeof(int))
3352 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003353 if (put_user_u32(len, optlen)
3354 || put_user_u32(val, optval_addr))
3355 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003356 }
bellard8853f862004-02-22 14:57:26 +00003357 break;
bellard2efbe912005-07-23 15:10:20 +00003358 default:
thsc02f4992007-12-18 02:39:59 +00003359 ret = -TARGET_ENOPROTOOPT;
3360 break;
bellard8853f862004-02-22 14:57:26 +00003361 }
3362 break;
3363 default:
3364 unimplemented:
3365 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3366 level, optname);
thsc02f4992007-12-18 02:39:59 +00003367 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003368 break;
3369 }
3370 return ret;
bellard7854b052003-03-29 17:22:23 +00003371}
3372
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003373static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003374 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003375{
3376 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003377 struct iovec *vec;
3378 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003379 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003380 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003381 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003382
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003383 if (count == 0) {
3384 errno = 0;
3385 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003386 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003387 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003388 errno = EINVAL;
3389 return NULL;
3390 }
3391
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303392 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003393 if (vec == NULL) {
3394 errno = ENOMEM;
3395 return NULL;
3396 }
3397
3398 target_vec = lock_user(VERIFY_READ, target_addr,
3399 count * sizeof(struct target_iovec), 1);
3400 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003401 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003402 goto fail2;
3403 }
3404
3405 /* ??? If host page size > target page size, this will result in a
3406 value larger than what we can actually support. */
3407 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3408 total_len = 0;
3409
3410 for (i = 0; i < count; i++) {
3411 abi_ulong base = tswapal(target_vec[i].iov_base);
3412 abi_long len = tswapal(target_vec[i].iov_len);
3413
3414 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003415 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003416 goto fail;
3417 } else if (len == 0) {
3418 /* Zero length pointer is ignored. */
3419 vec[i].iov_base = 0;
3420 } else {
3421 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003422 /* If the first buffer pointer is bad, this is a fault. But
3423 * subsequent bad buffers will result in a partial write; this
3424 * is realized by filling the vector with null pointers and
3425 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003426 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003427 if (i == 0) {
3428 err = EFAULT;
3429 goto fail;
3430 } else {
3431 bad_address = true;
3432 }
3433 }
3434 if (bad_address) {
3435 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003436 }
3437 if (len > max_len - total_len) {
3438 len = max_len - total_len;
3439 }
3440 }
3441 vec[i].iov_len = len;
3442 total_len += len;
3443 }
3444
3445 unlock_user(target_vec, target_addr, 0);
3446 return vec;
3447
3448 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003449 while (--i >= 0) {
3450 if (tswapal(target_vec[i].iov_len) > 0) {
3451 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3452 }
3453 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003454 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003455 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303456 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003457 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003458 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003459}
3460
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003461static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003462 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003463{
3464 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003465 int i;
3466
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003467 target_vec = lock_user(VERIFY_READ, target_addr,
3468 count * sizeof(struct target_iovec), 1);
3469 if (target_vec) {
3470 for (i = 0; i < count; i++) {
3471 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003472 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003473 if (len < 0) {
3474 break;
3475 }
balrogd732dcb2008-10-28 10:21:03 +00003476 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3477 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003478 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003479 }
bellard579a97f2007-11-11 14:26:47 +00003480
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303481 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003482}
3483
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003484static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003485{
3486 int host_type = 0;
3487 int target_type = *type;
3488
3489 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3490 case TARGET_SOCK_DGRAM:
3491 host_type = SOCK_DGRAM;
3492 break;
3493 case TARGET_SOCK_STREAM:
3494 host_type = SOCK_STREAM;
3495 break;
3496 default:
3497 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3498 break;
3499 }
3500 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003501#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003502 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003503#else
3504 return -TARGET_EINVAL;
3505#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003506 }
3507 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003508#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003509 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003510#elif !defined(O_NONBLOCK)
3511 return -TARGET_EINVAL;
3512#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003513 }
3514 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003515 return 0;
3516}
3517
3518/* Try to emulate socket type flags after socket creation. */
3519static int sock_flags_fixup(int fd, int target_type)
3520{
3521#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3522 if (target_type & TARGET_SOCK_NONBLOCK) {
3523 int flags = fcntl(fd, F_GETFL);
3524 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3525 close(fd);
3526 return -TARGET_EINVAL;
3527 }
3528 }
3529#endif
3530 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003531}
3532
Laurent Vivier0cf22722015-10-28 21:40:45 +01003533static abi_long packet_target_to_host_sockaddr(void *host_addr,
3534 abi_ulong target_addr,
3535 socklen_t len)
3536{
3537 struct sockaddr *addr = host_addr;
3538 struct target_sockaddr *target_saddr;
3539
3540 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3541 if (!target_saddr) {
3542 return -TARGET_EFAULT;
3543 }
3544
3545 memcpy(addr, target_saddr, len);
3546 addr->sa_family = tswap16(target_saddr->sa_family);
3547 /* spkt_protocol is big-endian */
3548
3549 unlock_user(target_saddr, target_addr, 0);
3550 return 0;
3551}
3552
3553static TargetFdTrans target_packet_trans = {
3554 .target_to_host_addr = packet_target_to_host_sockaddr,
3555};
3556
Laurent Vivier575b22b2016-06-02 22:14:15 +02003557#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003558static abi_long netlink_route_target_to_host(void *buf, size_t len)
3559{
Laurent Vivieref759f62016-06-21 19:51:13 +02003560 abi_long ret;
3561
3562 ret = target_to_host_nlmsg_route(buf, len);
3563 if (ret < 0) {
3564 return ret;
3565 }
3566
3567 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003568}
3569
3570static abi_long netlink_route_host_to_target(void *buf, size_t len)
3571{
Laurent Vivieref759f62016-06-21 19:51:13 +02003572 abi_long ret;
3573
3574 ret = host_to_target_nlmsg_route(buf, len);
3575 if (ret < 0) {
3576 return ret;
3577 }
3578
3579 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003580}
3581
3582static TargetFdTrans target_netlink_route_trans = {
3583 .target_to_host_data = netlink_route_target_to_host,
3584 .host_to_target_data = netlink_route_host_to_target,
3585};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003586#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003587
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003588static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3589{
Laurent Vivieref759f62016-06-21 19:51:13 +02003590 abi_long ret;
3591
3592 ret = target_to_host_nlmsg_audit(buf, len);
3593 if (ret < 0) {
3594 return ret;
3595 }
3596
3597 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003598}
3599
3600static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3601{
Laurent Vivieref759f62016-06-21 19:51:13 +02003602 abi_long ret;
3603
3604 ret = host_to_target_nlmsg_audit(buf, len);
3605 if (ret < 0) {
3606 return ret;
3607 }
3608
3609 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003610}
3611
3612static TargetFdTrans target_netlink_audit_trans = {
3613 .target_to_host_data = netlink_audit_target_to_host,
3614 .host_to_target_data = netlink_audit_host_to_target,
3615};
3616
ths0da46a62007-10-20 20:23:07 +00003617/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003618static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003619{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003620 int target_type = type;
3621 int ret;
3622
3623 ret = target_to_host_sock_type(&type);
3624 if (ret) {
3625 return ret;
3626 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003627
Laurent Vivier575b22b2016-06-02 22:14:15 +02003628 if (domain == PF_NETLINK && !(
3629#ifdef CONFIG_RTNETLINK
3630 protocol == NETLINK_ROUTE ||
3631#endif
3632 protocol == NETLINK_KOBJECT_UEVENT ||
3633 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003634 return -EPFNOSUPPORT;
3635 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003636
3637 if (domain == AF_PACKET ||
3638 (domain == AF_INET && type == SOCK_PACKET)) {
3639 protocol = tswap16(protocol);
3640 }
3641
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003642 ret = get_errno(socket(domain, type, protocol));
3643 if (ret >= 0) {
3644 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003645 if (type == SOCK_PACKET) {
3646 /* Manage an obsolete case :
3647 * if socket type is SOCK_PACKET, bind by name
3648 */
3649 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003650 } else if (domain == PF_NETLINK) {
3651 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003652#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003653 case NETLINK_ROUTE:
3654 fd_trans_register(ret, &target_netlink_route_trans);
3655 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003656#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003657 case NETLINK_KOBJECT_UEVENT:
3658 /* nothing to do: messages are strings */
3659 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003660 case NETLINK_AUDIT:
3661 fd_trans_register(ret, &target_netlink_audit_trans);
3662 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003663 default:
3664 g_assert_not_reached();
3665 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003666 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003667 }
3668 return ret;
bellard3532fa72006-06-24 15:06:03 +00003669}
3670
ths0da46a62007-10-20 20:23:07 +00003671/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003672static abi_long do_bind(int sockfd, abi_ulong target_addr,
3673 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003674{
aurel328f7aeaf2009-01-30 19:47:57 +00003675 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003676 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003677
Blue Swirl38724252010-09-18 05:53:14 +00003678 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003679 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003680 }
aurel328f7aeaf2009-01-30 19:47:57 +00003681
aurel32607175e2009-04-15 16:11:59 +00003682 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003683
Laurent Vivier7b36f782015-10-28 21:40:44 +01003684 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003685 if (ret)
3686 return ret;
3687
bellard3532fa72006-06-24 15:06:03 +00003688 return get_errno(bind(sockfd, addr, addrlen));
3689}
3690
ths0da46a62007-10-20 20:23:07 +00003691/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003692static abi_long do_connect(int sockfd, abi_ulong target_addr,
3693 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003694{
aurel328f7aeaf2009-01-30 19:47:57 +00003695 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003696 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003697
Blue Swirl38724252010-09-18 05:53:14 +00003698 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003699 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003700 }
aurel328f7aeaf2009-01-30 19:47:57 +00003701
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003702 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003703
Laurent Vivier7b36f782015-10-28 21:40:44 +01003704 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003705 if (ret)
3706 return ret;
3707
Peter Maydell2a3c7612016-06-06 19:58:03 +01003708 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003709}
3710
Alexander Graff19e00d2014-03-02 19:36:42 +00003711/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3712static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3713 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003714{
balrog6de645c2008-10-28 10:26:29 +00003715 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003716 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003717 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003718 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003719 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003720
bellard3532fa72006-06-24 15:06:03 +00003721 if (msgp->msg_name) {
3722 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003723 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003724 ret = target_to_host_sockaddr(fd, msg.msg_name,
3725 tswapal(msgp->msg_name),
3726 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003727 if (ret == -TARGET_EFAULT) {
3728 /* For connected sockets msg_name and msg_namelen must
3729 * be ignored, so returning EFAULT immediately is wrong.
3730 * Instead, pass a bad msg_name to the host kernel, and
3731 * let it decide whether to return EFAULT or not.
3732 */
3733 msg.msg_name = (void *)-1;
3734 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003735 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003736 }
bellard3532fa72006-06-24 15:06:03 +00003737 } else {
3738 msg.msg_name = NULL;
3739 msg.msg_namelen = 0;
3740 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003741 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003742 msg.msg_control = alloca(msg.msg_controllen);
3743 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003744
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003745 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003746 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003747
3748 if (count > IOV_MAX) {
3749 /* sendrcvmsg returns a different errno for this condition than
3750 * readv/writev, so we must catch it here before lock_iovec() does.
3751 */
3752 ret = -TARGET_EMSGSIZE;
3753 goto out2;
3754 }
3755
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003756 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3757 target_vec, count, send);
3758 if (vec == NULL) {
3759 ret = -host_to_target_errno(errno);
3760 goto out2;
3761 }
bellard3532fa72006-06-24 15:06:03 +00003762 msg.msg_iovlen = count;
3763 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003764
bellard3532fa72006-06-24 15:06:03 +00003765 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003766 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003767 void *host_msg;
3768
3769 host_msg = g_malloc(msg.msg_iov->iov_len);
3770 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3771 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003772 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003773 if (ret >= 0) {
3774 msg.msg_iov->iov_base = host_msg;
3775 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3776 }
3777 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003778 } else {
3779 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003780 if (ret == 0) {
3781 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3782 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003783 }
bellard3532fa72006-06-24 15:06:03 +00003784 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003785 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003786 if (!is_error(ret)) {
3787 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003788 if (fd_trans_host_to_target_data(fd)) {
3789 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003790 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003791 } else {
3792 ret = host_to_target_cmsg(msgp, &msg);
3793 }
Jing Huangca619062012-07-24 13:58:02 +00003794 if (!is_error(ret)) {
3795 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003796 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003797 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3798 msg.msg_name, msg.msg_namelen);
3799 if (ret) {
3800 goto out;
3801 }
3802 }
3803
balrog6de645c2008-10-28 10:26:29 +00003804 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003805 }
balrog6de645c2008-10-28 10:26:29 +00003806 }
bellard3532fa72006-06-24 15:06:03 +00003807 }
Jing Huangca619062012-07-24 13:58:02 +00003808
3809out:
bellard3532fa72006-06-24 15:06:03 +00003810 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003811out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003812 return ret;
3813}
3814
3815static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3816 int flags, int send)
3817{
3818 abi_long ret;
3819 struct target_msghdr *msgp;
3820
3821 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3822 msgp,
3823 target_msg,
3824 send ? 1 : 0)) {
3825 return -TARGET_EFAULT;
3826 }
3827 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003828 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003829 return ret;
3830}
3831
Alexander Graff19e00d2014-03-02 19:36:42 +00003832/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3833 * so it might not have this *mmsg-specific flag either.
3834 */
3835#ifndef MSG_WAITFORONE
3836#define MSG_WAITFORONE 0x10000
3837#endif
3838
3839static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3840 unsigned int vlen, unsigned int flags,
3841 int send)
3842{
3843 struct target_mmsghdr *mmsgp;
3844 abi_long ret = 0;
3845 int i;
3846
3847 if (vlen > UIO_MAXIOV) {
3848 vlen = UIO_MAXIOV;
3849 }
3850
3851 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3852 if (!mmsgp) {
3853 return -TARGET_EFAULT;
3854 }
3855
3856 for (i = 0; i < vlen; i++) {
3857 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3858 if (is_error(ret)) {
3859 break;
3860 }
3861 mmsgp[i].msg_len = tswap32(ret);
3862 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3863 if (flags & MSG_WAITFORONE) {
3864 flags |= MSG_DONTWAIT;
3865 }
3866 }
3867
3868 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3869
3870 /* Return number of datagrams sent if we sent any at all;
3871 * otherwise return the error.
3872 */
3873 if (i) {
3874 return i;
3875 }
3876 return ret;
3877}
Alexander Graff19e00d2014-03-02 19:36:42 +00003878
Peter Maydella94b4982013-02-08 04:35:04 +00003879/* do_accept4() Must return target values and target errnos. */
3880static abi_long do_accept4(int fd, abi_ulong target_addr,
3881 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003882{
bellard2f619692007-11-16 10:46:05 +00003883 socklen_t addrlen;
3884 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003885 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003886 int host_flags;
3887
3888 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003889
Peter Maydella94b4982013-02-08 04:35:04 +00003890 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003891 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003892 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003893
3894 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003895 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003896 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003897
Blue Swirl38724252010-09-18 05:53:14 +00003898 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003899 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003900 }
aurel328f7aeaf2009-01-30 19:47:57 +00003901
Arnaud Patard917507b2009-06-19 10:44:45 +03003902 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3903 return -TARGET_EINVAL;
3904
bellard2f619692007-11-16 10:46:05 +00003905 addr = alloca(addrlen);
3906
Peter Maydellff6dc132016-06-06 19:58:13 +01003907 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003908 if (!is_error(ret)) {
3909 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003910 if (put_user_u32(addrlen, target_addrlen_addr))
3911 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003912 }
3913 return ret;
3914}
3915
ths0da46a62007-10-20 20:23:07 +00003916/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003917static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003918 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003919{
bellard2f619692007-11-16 10:46:05 +00003920 socklen_t addrlen;
3921 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003922 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003923
bellard2f619692007-11-16 10:46:05 +00003924 if (get_user_u32(addrlen, target_addrlen_addr))
3925 return -TARGET_EFAULT;
3926
Blue Swirl38724252010-09-18 05:53:14 +00003927 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003928 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003929 }
aurel328f7aeaf2009-01-30 19:47:57 +00003930
Arnaud Patard917507b2009-06-19 10:44:45 +03003931 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3932 return -TARGET_EFAULT;
3933
bellard2f619692007-11-16 10:46:05 +00003934 addr = alloca(addrlen);
3935
pbrook1be9e1d2006-11-19 15:26:04 +00003936 ret = get_errno(getpeername(fd, addr, &addrlen));
3937 if (!is_error(ret)) {
3938 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003939 if (put_user_u32(addrlen, target_addrlen_addr))
3940 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003941 }
3942 return ret;
3943}
3944
ths0da46a62007-10-20 20:23:07 +00003945/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003946static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003947 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003948{
bellard2f619692007-11-16 10:46:05 +00003949 socklen_t addrlen;
3950 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003951 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003952
bellard2f619692007-11-16 10:46:05 +00003953 if (get_user_u32(addrlen, target_addrlen_addr))
3954 return -TARGET_EFAULT;
3955
Blue Swirl38724252010-09-18 05:53:14 +00003956 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003957 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003958 }
aurel328f7aeaf2009-01-30 19:47:57 +00003959
Arnaud Patard917507b2009-06-19 10:44:45 +03003960 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3961 return -TARGET_EFAULT;
3962
bellard2f619692007-11-16 10:46:05 +00003963 addr = alloca(addrlen);
3964
pbrook1be9e1d2006-11-19 15:26:04 +00003965 ret = get_errno(getsockname(fd, addr, &addrlen));
3966 if (!is_error(ret)) {
3967 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003968 if (put_user_u32(addrlen, target_addrlen_addr))
3969 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003970 }
3971 return ret;
3972}
3973
ths0da46a62007-10-20 20:23:07 +00003974/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003975static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003976 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003977{
3978 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003979 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003980
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003981 target_to_host_sock_type(&type);
3982
pbrook1be9e1d2006-11-19 15:26:04 +00003983 ret = get_errno(socketpair(domain, type, protocol, tab));
3984 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003985 if (put_user_s32(tab[0], target_tab_addr)
3986 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3987 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003988 }
3989 return ret;
3990}
3991
ths0da46a62007-10-20 20:23:07 +00003992/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003993static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3994 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003995{
3996 void *addr;
3997 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003998 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003999 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004000
Blue Swirl38724252010-09-18 05:53:14 +00004001 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004002 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004003 }
aurel328f7aeaf2009-01-30 19:47:57 +00004004
bellard579a97f2007-11-11 14:26:47 +00004005 host_msg = lock_user(VERIFY_READ, msg, len, 1);
4006 if (!host_msg)
4007 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004008 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004009 copy_msg = host_msg;
4010 host_msg = g_malloc(len);
4011 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004012 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
4013 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004014 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004015 }
4016 }
pbrook1be9e1d2006-11-19 15:26:04 +00004017 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02004018 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01004019 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03004020 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004021 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03004022 }
Peter Maydell66687532016-06-06 19:58:04 +01004023 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004024 } else {
Peter Maydell66687532016-06-06 19:58:04 +01004025 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004026 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02004027fail:
4028 if (copy_msg) {
4029 g_free(host_msg);
4030 host_msg = copy_msg;
4031 }
pbrook1be9e1d2006-11-19 15:26:04 +00004032 unlock_user(host_msg, msg, 0);
4033 return ret;
4034}
4035
ths0da46a62007-10-20 20:23:07 +00004036/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004037static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4038 abi_ulong target_addr,
4039 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004040{
4041 socklen_t addrlen;
4042 void *addr;
4043 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004044 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004045
bellard579a97f2007-11-11 14:26:47 +00004046 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4047 if (!host_msg)
4048 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004049 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004050 if (get_user_u32(addrlen, target_addrlen)) {
4051 ret = -TARGET_EFAULT;
4052 goto fail;
4053 }
Blue Swirl38724252010-09-18 05:53:14 +00004054 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004055 ret = -TARGET_EINVAL;
4056 goto fail;
4057 }
pbrook1be9e1d2006-11-19 15:26:04 +00004058 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004059 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4060 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004061 } else {
4062 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004063 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004064 }
4065 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004066 if (fd_trans_host_to_target_data(fd)) {
4067 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4068 }
pbrook1be9e1d2006-11-19 15:26:04 +00004069 if (target_addr) {
4070 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004071 if (put_user_u32(addrlen, target_addrlen)) {
4072 ret = -TARGET_EFAULT;
4073 goto fail;
4074 }
pbrook1be9e1d2006-11-19 15:26:04 +00004075 }
4076 unlock_user(host_msg, msg, len);
4077 } else {
bellard2f619692007-11-16 10:46:05 +00004078fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004079 unlock_user(host_msg, msg, 0);
4080 }
4081 return ret;
4082}
4083
j_mayer32407102007-09-26 23:01:49 +00004084#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004085/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004086static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004087{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004088 static const unsigned nargs[] = { /* number of arguments per operation */
4089 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4090 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4091 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4092 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4093 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4094 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4095 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4096 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4097 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4098 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4099 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4100 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4101 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4102 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4103 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4104 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4105 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4106 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4107 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4108 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004109 };
4110 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004111 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004112
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004113 /* check the range of the first argument num */
4114 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4115 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4116 return -TARGET_EINVAL;
4117 }
4118 /* ensure we have space for args */
4119 if (nargs[num] > ARRAY_SIZE(a)) {
4120 return -TARGET_EINVAL;
4121 }
4122 /* collect the arguments in a[] according to nargs[] */
4123 for (i = 0; i < nargs[num]; ++i) {
4124 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4125 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004126 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004127 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004128 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004129 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004130 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004131 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004132 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004133 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004134 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004135 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004136 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004137 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004138 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004139 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004140 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004141 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004142 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004143 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004144 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004145 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004146 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004147 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004148 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004149 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004150 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004151 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004152 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004153 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004154 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004155 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004156 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004157 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004158 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004159 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004160 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4161 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4162 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4163 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4164 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4165 return do_accept4(a[0], a[1], a[2], a[3]);
4166 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4167 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4168 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4169 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004170 default:
4171 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004172 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004173 }
bellard31e31b82003-02-18 22:55:36 +00004174}
j_mayer32407102007-09-26 23:01:49 +00004175#endif
bellard31e31b82003-02-18 22:55:36 +00004176
bellard8853f862004-02-22 14:57:26 +00004177#define N_SHM_REGIONS 32
4178
4179static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004180 abi_ulong start;
4181 abi_ulong size;
4182 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004183} shm_regions[N_SHM_REGIONS];
4184
Peter Maydell005eb2a2016-07-15 16:50:47 +01004185#ifndef TARGET_SEMID64_DS
4186/* asm-generic version of this struct */
4187struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004188{
4189 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004190 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004191#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004192 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004193#endif
blueswir1992f48a2007-10-14 16:27:31 +00004194 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004195#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004196 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004197#endif
blueswir1992f48a2007-10-14 16:27:31 +00004198 abi_ulong sem_nsems;
4199 abi_ulong __unused3;
4200 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004201};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004202#endif
ths3eb6b042007-06-03 14:26:27 +00004203
bellard579a97f2007-11-11 14:26:47 +00004204static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4205 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004206{
4207 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004208 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004209
bellard579a97f2007-11-11 14:26:47 +00004210 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4211 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004212 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004213 host_ip->__key = tswap32(target_ip->__key);
4214 host_ip->uid = tswap32(target_ip->uid);
4215 host_ip->gid = tswap32(target_ip->gid);
4216 host_ip->cuid = tswap32(target_ip->cuid);
4217 host_ip->cgid = tswap32(target_ip->cgid);
4218#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4219 host_ip->mode = tswap32(target_ip->mode);
4220#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004221 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004222#endif
4223#if defined(TARGET_PPC)
4224 host_ip->__seq = tswap32(target_ip->__seq);
4225#else
4226 host_ip->__seq = tswap16(target_ip->__seq);
4227#endif
ths3eb6b042007-06-03 14:26:27 +00004228 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004229 return 0;
ths3eb6b042007-06-03 14:26:27 +00004230}
4231
bellard579a97f2007-11-11 14:26:47 +00004232static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4233 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004234{
4235 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004236 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004237
bellard579a97f2007-11-11 14:26:47 +00004238 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4239 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004240 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004241 target_ip->__key = tswap32(host_ip->__key);
4242 target_ip->uid = tswap32(host_ip->uid);
4243 target_ip->gid = tswap32(host_ip->gid);
4244 target_ip->cuid = tswap32(host_ip->cuid);
4245 target_ip->cgid = tswap32(host_ip->cgid);
4246#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4247 target_ip->mode = tswap32(host_ip->mode);
4248#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004249 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004250#endif
4251#if defined(TARGET_PPC)
4252 target_ip->__seq = tswap32(host_ip->__seq);
4253#else
4254 target_ip->__seq = tswap16(host_ip->__seq);
4255#endif
ths3eb6b042007-06-03 14:26:27 +00004256 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004257 return 0;
ths3eb6b042007-06-03 14:26:27 +00004258}
4259
bellard579a97f2007-11-11 14:26:47 +00004260static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4261 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004262{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004263 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004264
bellard579a97f2007-11-11 14:26:47 +00004265 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4266 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004267 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4268 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004269 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4270 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4271 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004272 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004273 return 0;
ths3eb6b042007-06-03 14:26:27 +00004274}
4275
bellard579a97f2007-11-11 14:26:47 +00004276static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4277 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004278{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004279 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004280
bellard579a97f2007-11-11 14:26:47 +00004281 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4282 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004283 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004284 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004285 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4286 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4287 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004288 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004289 return 0;
ths3eb6b042007-06-03 14:26:27 +00004290}
4291
aurel32e5289082009-04-18 16:16:12 +00004292struct target_seminfo {
4293 int semmap;
4294 int semmni;
4295 int semmns;
4296 int semmnu;
4297 int semmsl;
4298 int semopm;
4299 int semume;
4300 int semusz;
4301 int semvmx;
4302 int semaem;
4303};
4304
4305static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4306 struct seminfo *host_seminfo)
4307{
4308 struct target_seminfo *target_seminfo;
4309 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4310 return -TARGET_EFAULT;
4311 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4312 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4313 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4314 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4315 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4316 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4317 __put_user(host_seminfo->semume, &target_seminfo->semume);
4318 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4319 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4320 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4321 unlock_user_struct(target_seminfo, target_addr, 1);
4322 return 0;
4323}
4324
thsfa294812007-02-02 22:05:00 +00004325union semun {
4326 int val;
ths3eb6b042007-06-03 14:26:27 +00004327 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004328 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004329 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004330};
4331
ths3eb6b042007-06-03 14:26:27 +00004332union target_semun {
4333 int val;
aurel32e5289082009-04-18 16:16:12 +00004334 abi_ulong buf;
4335 abi_ulong array;
4336 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004337};
4338
aurel32e5289082009-04-18 16:16:12 +00004339static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4340 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004341{
aurel32e5289082009-04-18 16:16:12 +00004342 int nsems;
4343 unsigned short *array;
4344 union semun semun;
4345 struct semid_ds semid_ds;
4346 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004347
aurel32e5289082009-04-18 16:16:12 +00004348 semun.buf = &semid_ds;
4349
4350 ret = semctl(semid, 0, IPC_STAT, semun);
4351 if (ret == -1)
4352 return get_errno(ret);
4353
4354 nsems = semid_ds.sem_nsems;
4355
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304356 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004357 if (!*host_array) {
4358 return -TARGET_ENOMEM;
4359 }
aurel32e5289082009-04-18 16:16:12 +00004360 array = lock_user(VERIFY_READ, target_addr,
4361 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004362 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304363 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004364 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004365 }
aurel32e5289082009-04-18 16:16:12 +00004366
4367 for(i=0; i<nsems; i++) {
4368 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004369 }
aurel32e5289082009-04-18 16:16:12 +00004370 unlock_user(array, target_addr, 0);
4371
bellard579a97f2007-11-11 14:26:47 +00004372 return 0;
ths3eb6b042007-06-03 14:26:27 +00004373}
4374
aurel32e5289082009-04-18 16:16:12 +00004375static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4376 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004377{
aurel32e5289082009-04-18 16:16:12 +00004378 int nsems;
4379 unsigned short *array;
4380 union semun semun;
4381 struct semid_ds semid_ds;
4382 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004383
aurel32e5289082009-04-18 16:16:12 +00004384 semun.buf = &semid_ds;
4385
4386 ret = semctl(semid, 0, IPC_STAT, semun);
4387 if (ret == -1)
4388 return get_errno(ret);
4389
4390 nsems = semid_ds.sem_nsems;
4391
4392 array = lock_user(VERIFY_WRITE, target_addr,
4393 nsems*sizeof(unsigned short), 0);
4394 if (!array)
4395 return -TARGET_EFAULT;
4396
4397 for(i=0; i<nsems; i++) {
4398 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004399 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304400 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004401 unlock_user(array, target_addr, 1);
4402
bellard579a97f2007-11-11 14:26:47 +00004403 return 0;
ths3eb6b042007-06-03 14:26:27 +00004404}
4405
aurel32e5289082009-04-18 16:16:12 +00004406static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004407 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004408{
Stefan Weild1c002b2015-02-08 15:40:58 +01004409 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004410 union semun arg;
4411 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304412 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004413 struct seminfo seminfo;
4414 abi_long ret = -TARGET_EINVAL;
4415 abi_long err;
4416 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004417
4418 switch( cmd ) {
4419 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004420 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004421 /* In 64 bit cross-endian situations, we will erroneously pick up
4422 * the wrong half of the union for the "val" element. To rectify
4423 * this, the entire 8-byte structure is byteswapped, followed by
4424 * a swap of the 4 byte val field. In other cases, the data is
4425 * already in proper host byte order. */
4426 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4427 target_su.buf = tswapal(target_su.buf);
4428 arg.val = tswap32(target_su.val);
4429 } else {
4430 arg.val = target_su.val;
4431 }
aurel32e5289082009-04-18 16:16:12 +00004432 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004433 break;
4434 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004435 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004436 err = target_to_host_semarray(semid, &array, target_su.array);
4437 if (err)
4438 return err;
4439 arg.array = array;
4440 ret = get_errno(semctl(semid, semnum, cmd, arg));
4441 err = host_to_target_semarray(semid, target_su.array, &array);
4442 if (err)
4443 return err;
ths3eb6b042007-06-03 14:26:27 +00004444 break;
4445 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004446 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004447 case SEM_STAT:
4448 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4449 if (err)
4450 return err;
4451 arg.buf = &dsarg;
4452 ret = get_errno(semctl(semid, semnum, cmd, arg));
4453 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4454 if (err)
4455 return err;
ths3eb6b042007-06-03 14:26:27 +00004456 break;
aurel32e5289082009-04-18 16:16:12 +00004457 case IPC_INFO:
4458 case SEM_INFO:
4459 arg.__buf = &seminfo;
4460 ret = get_errno(semctl(semid, semnum, cmd, arg));
4461 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4462 if (err)
4463 return err;
4464 break;
4465 case IPC_RMID:
4466 case GETPID:
4467 case GETNCNT:
4468 case GETZCNT:
4469 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4470 break;
ths3eb6b042007-06-03 14:26:27 +00004471 }
4472
4473 return ret;
4474}
4475
aurel32e5289082009-04-18 16:16:12 +00004476struct target_sembuf {
4477 unsigned short sem_num;
4478 short sem_op;
4479 short sem_flg;
4480};
4481
4482static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4483 abi_ulong target_addr,
4484 unsigned nsops)
4485{
4486 struct target_sembuf *target_sembuf;
4487 int i;
4488
4489 target_sembuf = lock_user(VERIFY_READ, target_addr,
4490 nsops*sizeof(struct target_sembuf), 1);
4491 if (!target_sembuf)
4492 return -TARGET_EFAULT;
4493
4494 for(i=0; i<nsops; i++) {
4495 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4496 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4497 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4498 }
4499
4500 unlock_user(target_sembuf, target_addr, 0);
4501
4502 return 0;
4503}
4504
4505static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4506{
4507 struct sembuf sops[nsops];
4508
4509 if (target_to_host_sembuf(sops, ptr, nsops))
4510 return -TARGET_EFAULT;
4511
Peter Maydellffb7ee72016-06-06 19:58:12 +01004512 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004513}
4514
ths1bc012f2007-06-03 14:27:49 +00004515struct target_msqid_ds
4516{
aurel321c54ff92008-10-13 21:08:44 +00004517 struct target_ipc_perm msg_perm;
4518 abi_ulong msg_stime;
4519#if TARGET_ABI_BITS == 32
4520 abi_ulong __unused1;
4521#endif
4522 abi_ulong msg_rtime;
4523#if TARGET_ABI_BITS == 32
4524 abi_ulong __unused2;
4525#endif
4526 abi_ulong msg_ctime;
4527#if TARGET_ABI_BITS == 32
4528 abi_ulong __unused3;
4529#endif
4530 abi_ulong __msg_cbytes;
4531 abi_ulong msg_qnum;
4532 abi_ulong msg_qbytes;
4533 abi_ulong msg_lspid;
4534 abi_ulong msg_lrpid;
4535 abi_ulong __unused4;
4536 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004537};
4538
bellard579a97f2007-11-11 14:26:47 +00004539static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4540 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004541{
4542 struct target_msqid_ds *target_md;
4543
bellard579a97f2007-11-11 14:26:47 +00004544 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4545 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004546 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4547 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004548 host_md->msg_stime = tswapal(target_md->msg_stime);
4549 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4550 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4551 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4552 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4553 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4554 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4555 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004556 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004557 return 0;
ths1bc012f2007-06-03 14:27:49 +00004558}
4559
bellard579a97f2007-11-11 14:26:47 +00004560static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4561 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004562{
4563 struct target_msqid_ds *target_md;
4564
bellard579a97f2007-11-11 14:26:47 +00004565 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4566 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004567 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4568 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004569 target_md->msg_stime = tswapal(host_md->msg_stime);
4570 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4571 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4572 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4573 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4574 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4575 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4576 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004577 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004578 return 0;
ths1bc012f2007-06-03 14:27:49 +00004579}
4580
aurel321c54ff92008-10-13 21:08:44 +00004581struct target_msginfo {
4582 int msgpool;
4583 int msgmap;
4584 int msgmax;
4585 int msgmnb;
4586 int msgmni;
4587 int msgssz;
4588 int msgtql;
4589 unsigned short int msgseg;
4590};
4591
4592static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4593 struct msginfo *host_msginfo)
4594{
4595 struct target_msginfo *target_msginfo;
4596 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4597 return -TARGET_EFAULT;
4598 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4599 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4600 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4601 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4602 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4603 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4604 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4605 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4606 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004607 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004608}
4609
4610static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004611{
4612 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004613 struct msginfo msginfo;
4614 abi_long ret = -TARGET_EINVAL;
4615
4616 cmd &= 0xff;
4617
4618 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004619 case IPC_STAT:
4620 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004621 case MSG_STAT:
4622 if (target_to_host_msqid_ds(&dsarg,ptr))
4623 return -TARGET_EFAULT;
4624 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4625 if (host_to_target_msqid_ds(ptr,&dsarg))
4626 return -TARGET_EFAULT;
4627 break;
4628 case IPC_RMID:
4629 ret = get_errno(msgctl(msgid, cmd, NULL));
4630 break;
4631 case IPC_INFO:
4632 case MSG_INFO:
4633 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4634 if (host_to_target_msginfo(ptr, &msginfo))
4635 return -TARGET_EFAULT;
4636 break;
ths1bc012f2007-06-03 14:27:49 +00004637 }
aurel321c54ff92008-10-13 21:08:44 +00004638
ths1bc012f2007-06-03 14:27:49 +00004639 return ret;
4640}
4641
4642struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004643 abi_long mtype;
4644 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004645};
4646
blueswir1992f48a2007-10-14 16:27:31 +00004647static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004648 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004649{
4650 struct target_msgbuf *target_mb;
4651 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004652 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004653
Tom Mustaedcc5f92014-08-12 13:53:37 -05004654 if (msgsz < 0) {
4655 return -TARGET_EINVAL;
4656 }
4657
bellard579a97f2007-11-11 14:26:47 +00004658 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4659 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304660 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004661 if (!host_mb) {
4662 unlock_user_struct(target_mb, msgp, 0);
4663 return -TARGET_ENOMEM;
4664 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004665 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004666 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004667 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304668 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004669 unlock_user_struct(target_mb, msgp, 0);
4670
4671 return ret;
4672}
4673
blueswir1992f48a2007-10-14 16:27:31 +00004674static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004675 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004676 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004677{
4678 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004679 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004680 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004681 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004682
Peter Maydell99874f62016-05-20 19:00:56 +01004683 if (msgsz < 0) {
4684 return -TARGET_EINVAL;
4685 }
4686
bellard579a97f2007-11-11 14:26:47 +00004687 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4688 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004689
Peter Maydell415d8472016-05-20 19:00:57 +01004690 host_mb = g_try_malloc(msgsz + sizeof(long));
4691 if (!host_mb) {
4692 ret = -TARGET_ENOMEM;
4693 goto end;
4694 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004695 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004696
bellard579a97f2007-11-11 14:26:47 +00004697 if (ret > 0) {
4698 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4699 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4700 if (!target_mtext) {
4701 ret = -TARGET_EFAULT;
4702 goto end;
4703 }
aurel321c54ff92008-10-13 21:08:44 +00004704 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004705 unlock_user(target_mtext, target_mtext_addr, ret);
4706 }
aurel321c54ff92008-10-13 21:08:44 +00004707
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004708 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004709
bellard579a97f2007-11-11 14:26:47 +00004710end:
4711 if (target_mb)
4712 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004713 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004714 return ret;
4715}
4716
Riku Voipio88a8c982009-04-03 10:42:00 +03004717static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4718 abi_ulong target_addr)
4719{
4720 struct target_shmid_ds *target_sd;
4721
4722 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4723 return -TARGET_EFAULT;
4724 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4725 return -TARGET_EFAULT;
4726 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4727 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4728 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4729 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4730 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4731 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4732 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4733 unlock_user_struct(target_sd, target_addr, 0);
4734 return 0;
4735}
4736
4737static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4738 struct shmid_ds *host_sd)
4739{
4740 struct target_shmid_ds *target_sd;
4741
4742 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4743 return -TARGET_EFAULT;
4744 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4745 return -TARGET_EFAULT;
4746 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4747 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4748 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4749 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4750 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4751 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4752 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4753 unlock_user_struct(target_sd, target_addr, 1);
4754 return 0;
4755}
4756
4757struct target_shminfo {
4758 abi_ulong shmmax;
4759 abi_ulong shmmin;
4760 abi_ulong shmmni;
4761 abi_ulong shmseg;
4762 abi_ulong shmall;
4763};
4764
4765static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4766 struct shminfo *host_shminfo)
4767{
4768 struct target_shminfo *target_shminfo;
4769 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4770 return -TARGET_EFAULT;
4771 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4772 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4773 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4774 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4775 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4776 unlock_user_struct(target_shminfo, target_addr, 1);
4777 return 0;
4778}
4779
4780struct target_shm_info {
4781 int used_ids;
4782 abi_ulong shm_tot;
4783 abi_ulong shm_rss;
4784 abi_ulong shm_swp;
4785 abi_ulong swap_attempts;
4786 abi_ulong swap_successes;
4787};
4788
4789static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4790 struct shm_info *host_shm_info)
4791{
4792 struct target_shm_info *target_shm_info;
4793 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4794 return -TARGET_EFAULT;
4795 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4796 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4797 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4798 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4799 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4800 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4801 unlock_user_struct(target_shm_info, target_addr, 1);
4802 return 0;
4803}
4804
4805static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4806{
4807 struct shmid_ds dsarg;
4808 struct shminfo shminfo;
4809 struct shm_info shm_info;
4810 abi_long ret = -TARGET_EINVAL;
4811
4812 cmd &= 0xff;
4813
4814 switch(cmd) {
4815 case IPC_STAT:
4816 case IPC_SET:
4817 case SHM_STAT:
4818 if (target_to_host_shmid_ds(&dsarg, buf))
4819 return -TARGET_EFAULT;
4820 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4821 if (host_to_target_shmid_ds(buf, &dsarg))
4822 return -TARGET_EFAULT;
4823 break;
4824 case IPC_INFO:
4825 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4826 if (host_to_target_shminfo(buf, &shminfo))
4827 return -TARGET_EFAULT;
4828 break;
4829 case SHM_INFO:
4830 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4831 if (host_to_target_shm_info(buf, &shm_info))
4832 return -TARGET_EFAULT;
4833 break;
4834 case IPC_RMID:
4835 case SHM_LOCK:
4836 case SHM_UNLOCK:
4837 ret = get_errno(shmctl(shmid, cmd, NULL));
4838 break;
4839 }
4840
4841 return ret;
4842}
4843
Peter Maydellee8e7612016-07-11 16:48:11 +01004844#ifndef TARGET_FORCE_SHMLBA
4845/* For most architectures, SHMLBA is the same as the page size;
4846 * some architectures have larger values, in which case they should
4847 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4848 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4849 * and defining its own value for SHMLBA.
4850 *
4851 * The kernel also permits SHMLBA to be set by the architecture to a
4852 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4853 * this means that addresses are rounded to the large size if
4854 * SHM_RND is set but addresses not aligned to that size are not rejected
4855 * as long as they are at least page-aligned. Since the only architecture
4856 * which uses this is ia64 this code doesn't provide for that oddity.
4857 */
4858static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4859{
4860 return TARGET_PAGE_SIZE;
4861}
4862#endif
4863
4864static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4865 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004866{
4867 abi_long raddr;
4868 void *host_raddr;
4869 struct shmid_ds shm_info;
4870 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004871 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004872
4873 /* find out the length of the shared memory segment */
4874 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4875 if (is_error(ret)) {
4876 /* can't get length, bail out */
4877 return ret;
4878 }
4879
Peter Maydellee8e7612016-07-11 16:48:11 +01004880 shmlba = target_shmlba(cpu_env);
4881
4882 if (shmaddr & (shmlba - 1)) {
4883 if (shmflg & SHM_RND) {
4884 shmaddr &= ~(shmlba - 1);
4885 } else {
4886 return -TARGET_EINVAL;
4887 }
4888 }
4889
Riku Voipio88a8c982009-04-03 10:42:00 +03004890 mmap_lock();
4891
4892 if (shmaddr)
4893 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4894 else {
4895 abi_ulong mmap_start;
4896
4897 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4898
4899 if (mmap_start == -1) {
4900 errno = ENOMEM;
4901 host_raddr = (void *)-1;
4902 } else
4903 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4904 }
4905
4906 if (host_raddr == (void *)-1) {
4907 mmap_unlock();
4908 return get_errno((long)host_raddr);
4909 }
4910 raddr=h2g((unsigned long)host_raddr);
4911
4912 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4913 PAGE_VALID | PAGE_READ |
4914 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4915
4916 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004917 if (!shm_regions[i].in_use) {
4918 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004919 shm_regions[i].start = raddr;
4920 shm_regions[i].size = shm_info.shm_segsz;
4921 break;
4922 }
4923 }
4924
4925 mmap_unlock();
4926 return raddr;
4927
4928}
4929
4930static inline abi_long do_shmdt(abi_ulong shmaddr)
4931{
4932 int i;
4933
4934 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004935 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4936 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004937 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004938 break;
4939 }
4940 }
4941
4942 return get_errno(shmdt(g2h(shmaddr)));
4943}
4944
aurel321c54ff92008-10-13 21:08:44 +00004945#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004946/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004947/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004948static abi_long do_ipc(CPUArchState *cpu_env,
4949 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004950 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004951 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004952{
4953 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004954 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004955
4956 version = call >> 16;
4957 call &= 0xffff;
4958
4959 switch (call) {
thsfa294812007-02-02 22:05:00 +00004960 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004961 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004962 break;
4963
4964 case IPCOP_semget:
4965 ret = get_errno(semget(first, second, third));
4966 break;
4967
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004968 case IPCOP_semctl: {
4969 /* The semun argument to semctl is passed by value, so dereference the
4970 * ptr argument. */
4971 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004972 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004973 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004974 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004975 }
thsd96372e2007-02-02 22:05:44 +00004976
aurel321c54ff92008-10-13 21:08:44 +00004977 case IPCOP_msgget:
4978 ret = get_errno(msgget(first, second));
4979 break;
thsd96372e2007-02-02 22:05:44 +00004980
aurel321c54ff92008-10-13 21:08:44 +00004981 case IPCOP_msgsnd:
4982 ret = do_msgsnd(first, ptr, second, third);
4983 break;
thsd96372e2007-02-02 22:05:44 +00004984
aurel321c54ff92008-10-13 21:08:44 +00004985 case IPCOP_msgctl:
4986 ret = do_msgctl(first, second, ptr);
4987 break;
thsd96372e2007-02-02 22:05:44 +00004988
aurel321c54ff92008-10-13 21:08:44 +00004989 case IPCOP_msgrcv:
4990 switch (version) {
4991 case 0:
4992 {
4993 struct target_ipc_kludge {
4994 abi_long msgp;
4995 abi_long msgtyp;
4996 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004997
aurel321c54ff92008-10-13 21:08:44 +00004998 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4999 ret = -TARGET_EFAULT;
5000 break;
ths1bc012f2007-06-03 14:27:49 +00005001 }
aurel321c54ff92008-10-13 21:08:44 +00005002
Laurent Vivier79dd77d2012-12-20 11:00:11 +00005003 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00005004
5005 unlock_user_struct(tmp, ptr, 0);
5006 break;
5007 }
5008 default:
5009 ret = do_msgrcv(first, ptr, second, fifth, third);
5010 }
5011 break;
thsd96372e2007-02-02 22:05:44 +00005012
bellard8853f862004-02-22 14:57:26 +00005013 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03005014 switch (version) {
5015 default:
bellard5a4a8982007-11-11 17:39:18 +00005016 {
5017 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01005018 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03005019 if (is_error(raddr))
5020 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00005021 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00005022 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03005023 break;
5024 }
5025 case 1:
5026 ret = -TARGET_EINVAL;
5027 break;
bellard5a4a8982007-11-11 17:39:18 +00005028 }
bellard8853f862004-02-22 14:57:26 +00005029 break;
5030 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03005031 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00005032 break;
5033
5034 case IPCOP_shmget:
5035 /* IPC_* flag values are the same on all linux platforms */
5036 ret = get_errno(shmget(first, second, third));
5037 break;
5038
5039 /* IPC_* and SHM_* command values are the same on all linux platforms */
5040 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005041 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005042 break;
5043 default:
j_mayer32407102007-09-26 23:01:49 +00005044 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005045 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005046 break;
5047 }
5048 return ret;
5049}
j_mayer32407102007-09-26 23:01:49 +00005050#endif
bellard8853f862004-02-22 14:57:26 +00005051
bellard31e31b82003-02-18 22:55:36 +00005052/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005053
Blue Swirl001faf32009-05-13 17:53:17 +00005054#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005055#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5056enum {
5057#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005058STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005059};
5060#undef STRUCT
5061#undef STRUCT_SPECIAL
5062
Blue Swirl001faf32009-05-13 17:53:17 +00005063#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005064#define STRUCT_SPECIAL(name)
5065#include "syscall_types.h"
5066#undef STRUCT
5067#undef STRUCT_SPECIAL
5068
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005069typedef struct IOCTLEntry IOCTLEntry;
5070
5071typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005072 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005073
5074struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005075 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005076 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005077 const char *name;
5078 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005079 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005080 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005081};
bellard31e31b82003-02-18 22:55:36 +00005082
5083#define IOC_R 0x0001
5084#define IOC_W 0x0002
5085#define IOC_RW (IOC_R | IOC_W)
5086
5087#define MAX_STRUCT_SIZE 4096
5088
Peter Maydelldace20d2011-01-10 13:11:24 +00005089#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005090/* So fiemap access checks don't overflow on 32 bit systems.
5091 * This is very slightly smaller than the limit imposed by
5092 * the underlying kernel.
5093 */
5094#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5095 / sizeof(struct fiemap_extent))
5096
5097static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005098 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005099{
5100 /* The parameter for this ioctl is a struct fiemap followed
5101 * by an array of struct fiemap_extent whose size is set
5102 * in fiemap->fm_extent_count. The array is filled in by the
5103 * ioctl.
5104 */
5105 int target_size_in, target_size_out;
5106 struct fiemap *fm;
5107 const argtype *arg_type = ie->arg_type;
5108 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5109 void *argptr, *p;
5110 abi_long ret;
5111 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5112 uint32_t outbufsz;
5113 int free_fm = 0;
5114
5115 assert(arg_type[0] == TYPE_PTR);
5116 assert(ie->access == IOC_RW);
5117 arg_type++;
5118 target_size_in = thunk_type_size(arg_type, 0);
5119 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5120 if (!argptr) {
5121 return -TARGET_EFAULT;
5122 }
5123 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5124 unlock_user(argptr, arg, 0);
5125 fm = (struct fiemap *)buf_temp;
5126 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5127 return -TARGET_EINVAL;
5128 }
5129
5130 outbufsz = sizeof (*fm) +
5131 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5132
5133 if (outbufsz > MAX_STRUCT_SIZE) {
5134 /* We can't fit all the extents into the fixed size buffer.
5135 * Allocate one that is large enough and use it instead.
5136 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305137 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005138 if (!fm) {
5139 return -TARGET_ENOMEM;
5140 }
5141 memcpy(fm, buf_temp, sizeof(struct fiemap));
5142 free_fm = 1;
5143 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005144 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005145 if (!is_error(ret)) {
5146 target_size_out = target_size_in;
5147 /* An extent_count of 0 means we were only counting the extents
5148 * so there are no structs to copy
5149 */
5150 if (fm->fm_extent_count != 0) {
5151 target_size_out += fm->fm_mapped_extents * extent_size;
5152 }
5153 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5154 if (!argptr) {
5155 ret = -TARGET_EFAULT;
5156 } else {
5157 /* Convert the struct fiemap */
5158 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5159 if (fm->fm_extent_count != 0) {
5160 p = argptr + target_size_in;
5161 /* ...and then all the struct fiemap_extents */
5162 for (i = 0; i < fm->fm_mapped_extents; i++) {
5163 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5164 THUNK_TARGET);
5165 p += extent_size;
5166 }
5167 }
5168 unlock_user(argptr, arg, target_size_out);
5169 }
5170 }
5171 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305172 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005173 }
5174 return ret;
5175}
Peter Maydelldace20d2011-01-10 13:11:24 +00005176#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005177
Laurent Vivier059c2f22011-03-30 00:12:12 +02005178static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005179 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005180{
5181 const argtype *arg_type = ie->arg_type;
5182 int target_size;
5183 void *argptr;
5184 int ret;
5185 struct ifconf *host_ifconf;
5186 uint32_t outbufsz;
5187 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5188 int target_ifreq_size;
5189 int nb_ifreq;
5190 int free_buf = 0;
5191 int i;
5192 int target_ifc_len;
5193 abi_long target_ifc_buf;
5194 int host_ifc_len;
5195 char *host_ifc_buf;
5196
5197 assert(arg_type[0] == TYPE_PTR);
5198 assert(ie->access == IOC_RW);
5199
5200 arg_type++;
5201 target_size = thunk_type_size(arg_type, 0);
5202
5203 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5204 if (!argptr)
5205 return -TARGET_EFAULT;
5206 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5207 unlock_user(argptr, arg, 0);
5208
5209 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5210 target_ifc_len = host_ifconf->ifc_len;
5211 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5212
5213 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5214 nb_ifreq = target_ifc_len / target_ifreq_size;
5215 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5216
5217 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5218 if (outbufsz > MAX_STRUCT_SIZE) {
5219 /* We can't fit all the extents into the fixed size buffer.
5220 * Allocate one that is large enough and use it instead.
5221 */
5222 host_ifconf = malloc(outbufsz);
5223 if (!host_ifconf) {
5224 return -TARGET_ENOMEM;
5225 }
5226 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5227 free_buf = 1;
5228 }
5229 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5230
5231 host_ifconf->ifc_len = host_ifc_len;
5232 host_ifconf->ifc_buf = host_ifc_buf;
5233
Peter Maydell49ca6f32016-06-06 19:58:14 +01005234 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005235 if (!is_error(ret)) {
5236 /* convert host ifc_len to target ifc_len */
5237
5238 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5239 target_ifc_len = nb_ifreq * target_ifreq_size;
5240 host_ifconf->ifc_len = target_ifc_len;
5241
5242 /* restore target ifc_buf */
5243
5244 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5245
5246 /* copy struct ifconf to target user */
5247
5248 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5249 if (!argptr)
5250 return -TARGET_EFAULT;
5251 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5252 unlock_user(argptr, arg, target_size);
5253
5254 /* copy ifreq[] to target user */
5255
5256 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5257 for (i = 0; i < nb_ifreq ; i++) {
5258 thunk_convert(argptr + i * target_ifreq_size,
5259 host_ifc_buf + i * sizeof(struct ifreq),
5260 ifreq_arg_type, THUNK_TARGET);
5261 }
5262 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5263 }
5264
5265 if (free_buf) {
5266 free(host_ifconf);
5267 }
5268
5269 return ret;
5270}
5271
Alexander Graf56e904e2012-01-31 18:42:06 +01005272static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005273 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005274{
5275 void *argptr;
5276 struct dm_ioctl *host_dm;
5277 abi_long guest_data;
5278 uint32_t guest_data_size;
5279 int target_size;
5280 const argtype *arg_type = ie->arg_type;
5281 abi_long ret;
5282 void *big_buf = NULL;
5283 char *host_data;
5284
5285 arg_type++;
5286 target_size = thunk_type_size(arg_type, 0);
5287 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5288 if (!argptr) {
5289 ret = -TARGET_EFAULT;
5290 goto out;
5291 }
5292 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5293 unlock_user(argptr, arg, 0);
5294
5295 /* buf_temp is too small, so fetch things into a bigger buffer */
5296 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5297 memcpy(big_buf, buf_temp, target_size);
5298 buf_temp = big_buf;
5299 host_dm = big_buf;
5300
5301 guest_data = arg + host_dm->data_start;
5302 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005303 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005304 goto out;
5305 }
5306 guest_data_size = host_dm->data_size - host_dm->data_start;
5307 host_data = (char*)host_dm + host_dm->data_start;
5308
5309 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005310 if (!argptr) {
5311 ret = -TARGET_EFAULT;
5312 goto out;
5313 }
5314
Alexander Graf56e904e2012-01-31 18:42:06 +01005315 switch (ie->host_cmd) {
5316 case DM_REMOVE_ALL:
5317 case DM_LIST_DEVICES:
5318 case DM_DEV_CREATE:
5319 case DM_DEV_REMOVE:
5320 case DM_DEV_SUSPEND:
5321 case DM_DEV_STATUS:
5322 case DM_DEV_WAIT:
5323 case DM_TABLE_STATUS:
5324 case DM_TABLE_CLEAR:
5325 case DM_TABLE_DEPS:
5326 case DM_LIST_VERSIONS:
5327 /* no input data */
5328 break;
5329 case DM_DEV_RENAME:
5330 case DM_DEV_SET_GEOMETRY:
5331 /* data contains only strings */
5332 memcpy(host_data, argptr, guest_data_size);
5333 break;
5334 case DM_TARGET_MSG:
5335 memcpy(host_data, argptr, guest_data_size);
5336 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5337 break;
5338 case DM_TABLE_LOAD:
5339 {
5340 void *gspec = argptr;
5341 void *cur_data = host_data;
5342 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5343 int spec_size = thunk_type_size(arg_type, 0);
5344 int i;
5345
5346 for (i = 0; i < host_dm->target_count; i++) {
5347 struct dm_target_spec *spec = cur_data;
5348 uint32_t next;
5349 int slen;
5350
5351 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5352 slen = strlen((char*)gspec + spec_size) + 1;
5353 next = spec->next;
5354 spec->next = sizeof(*spec) + slen;
5355 strcpy((char*)&spec[1], gspec + spec_size);
5356 gspec += next;
5357 cur_data += spec->next;
5358 }
5359 break;
5360 }
5361 default:
5362 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005363 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005364 goto out;
5365 }
5366 unlock_user(argptr, guest_data, 0);
5367
Peter Maydell49ca6f32016-06-06 19:58:14 +01005368 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005369 if (!is_error(ret)) {
5370 guest_data = arg + host_dm->data_start;
5371 guest_data_size = host_dm->data_size - host_dm->data_start;
5372 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5373 switch (ie->host_cmd) {
5374 case DM_REMOVE_ALL:
5375 case DM_DEV_CREATE:
5376 case DM_DEV_REMOVE:
5377 case DM_DEV_RENAME:
5378 case DM_DEV_SUSPEND:
5379 case DM_DEV_STATUS:
5380 case DM_TABLE_LOAD:
5381 case DM_TABLE_CLEAR:
5382 case DM_TARGET_MSG:
5383 case DM_DEV_SET_GEOMETRY:
5384 /* no return data */
5385 break;
5386 case DM_LIST_DEVICES:
5387 {
5388 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5389 uint32_t remaining_data = guest_data_size;
5390 void *cur_data = argptr;
5391 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5392 int nl_size = 12; /* can't use thunk_size due to alignment */
5393
5394 while (1) {
5395 uint32_t next = nl->next;
5396 if (next) {
5397 nl->next = nl_size + (strlen(nl->name) + 1);
5398 }
5399 if (remaining_data < nl->next) {
5400 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5401 break;
5402 }
5403 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5404 strcpy(cur_data + nl_size, nl->name);
5405 cur_data += nl->next;
5406 remaining_data -= nl->next;
5407 if (!next) {
5408 break;
5409 }
5410 nl = (void*)nl + next;
5411 }
5412 break;
5413 }
5414 case DM_DEV_WAIT:
5415 case DM_TABLE_STATUS:
5416 {
5417 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5418 void *cur_data = argptr;
5419 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5420 int spec_size = thunk_type_size(arg_type, 0);
5421 int i;
5422
5423 for (i = 0; i < host_dm->target_count; i++) {
5424 uint32_t next = spec->next;
5425 int slen = strlen((char*)&spec[1]) + 1;
5426 spec->next = (cur_data - argptr) + spec_size + slen;
5427 if (guest_data_size < spec->next) {
5428 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5429 break;
5430 }
5431 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5432 strcpy(cur_data + spec_size, (char*)&spec[1]);
5433 cur_data = argptr + spec->next;
5434 spec = (void*)host_dm + host_dm->data_start + next;
5435 }
5436 break;
5437 }
5438 case DM_TABLE_DEPS:
5439 {
5440 void *hdata = (void*)host_dm + host_dm->data_start;
5441 int count = *(uint32_t*)hdata;
5442 uint64_t *hdev = hdata + 8;
5443 uint64_t *gdev = argptr + 8;
5444 int i;
5445
5446 *(uint32_t*)argptr = tswap32(count);
5447 for (i = 0; i < count; i++) {
5448 *gdev = tswap64(*hdev);
5449 gdev++;
5450 hdev++;
5451 }
5452 break;
5453 }
5454 case DM_LIST_VERSIONS:
5455 {
5456 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5457 uint32_t remaining_data = guest_data_size;
5458 void *cur_data = argptr;
5459 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5460 int vers_size = thunk_type_size(arg_type, 0);
5461
5462 while (1) {
5463 uint32_t next = vers->next;
5464 if (next) {
5465 vers->next = vers_size + (strlen(vers->name) + 1);
5466 }
5467 if (remaining_data < vers->next) {
5468 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5469 break;
5470 }
5471 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5472 strcpy(cur_data + vers_size, vers->name);
5473 cur_data += vers->next;
5474 remaining_data -= vers->next;
5475 if (!next) {
5476 break;
5477 }
5478 vers = (void*)vers + next;
5479 }
5480 break;
5481 }
5482 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005483 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005484 ret = -TARGET_EINVAL;
5485 goto out;
5486 }
5487 unlock_user(argptr, guest_data, guest_data_size);
5488
5489 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5490 if (!argptr) {
5491 ret = -TARGET_EFAULT;
5492 goto out;
5493 }
5494 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5495 unlock_user(argptr, arg, target_size);
5496 }
5497out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005498 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005499 return ret;
5500}
5501
Alexander Grafa59b5e32014-08-22 13:15:50 +02005502static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005503 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005504{
5505 void *argptr;
5506 int target_size;
5507 const argtype *arg_type = ie->arg_type;
5508 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5509 abi_long ret;
5510
5511 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5512 struct blkpg_partition host_part;
5513
5514 /* Read and convert blkpg */
5515 arg_type++;
5516 target_size = thunk_type_size(arg_type, 0);
5517 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5518 if (!argptr) {
5519 ret = -TARGET_EFAULT;
5520 goto out;
5521 }
5522 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5523 unlock_user(argptr, arg, 0);
5524
5525 switch (host_blkpg->op) {
5526 case BLKPG_ADD_PARTITION:
5527 case BLKPG_DEL_PARTITION:
5528 /* payload is struct blkpg_partition */
5529 break;
5530 default:
5531 /* Unknown opcode */
5532 ret = -TARGET_EINVAL;
5533 goto out;
5534 }
5535
5536 /* Read and convert blkpg->data */
5537 arg = (abi_long)(uintptr_t)host_blkpg->data;
5538 target_size = thunk_type_size(part_arg_type, 0);
5539 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5540 if (!argptr) {
5541 ret = -TARGET_EFAULT;
5542 goto out;
5543 }
5544 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5545 unlock_user(argptr, arg, 0);
5546
5547 /* Swizzle the data pointer to our local copy and call! */
5548 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005549 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005550
5551out:
5552 return ret;
5553}
5554
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005555static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005556 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005557{
5558 const argtype *arg_type = ie->arg_type;
5559 const StructEntry *se;
5560 const argtype *field_types;
5561 const int *dst_offsets, *src_offsets;
5562 int target_size;
5563 void *argptr;
5564 abi_ulong *target_rt_dev_ptr;
5565 unsigned long *host_rt_dev_ptr;
5566 abi_long ret;
5567 int i;
5568
5569 assert(ie->access == IOC_W);
5570 assert(*arg_type == TYPE_PTR);
5571 arg_type++;
5572 assert(*arg_type == TYPE_STRUCT);
5573 target_size = thunk_type_size(arg_type, 0);
5574 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5575 if (!argptr) {
5576 return -TARGET_EFAULT;
5577 }
5578 arg_type++;
5579 assert(*arg_type == (int)STRUCT_rtentry);
5580 se = struct_entries + *arg_type++;
5581 assert(se->convert[0] == NULL);
5582 /* convert struct here to be able to catch rt_dev string */
5583 field_types = se->field_types;
5584 dst_offsets = se->field_offsets[THUNK_HOST];
5585 src_offsets = se->field_offsets[THUNK_TARGET];
5586 for (i = 0; i < se->nb_fields; i++) {
5587 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5588 assert(*field_types == TYPE_PTRVOID);
5589 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5590 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5591 if (*target_rt_dev_ptr != 0) {
5592 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5593 tswapal(*target_rt_dev_ptr));
5594 if (!*host_rt_dev_ptr) {
5595 unlock_user(argptr, arg, 0);
5596 return -TARGET_EFAULT;
5597 }
5598 } else {
5599 *host_rt_dev_ptr = 0;
5600 }
5601 field_types++;
5602 continue;
5603 }
5604 field_types = thunk_convert(buf_temp + dst_offsets[i],
5605 argptr + src_offsets[i],
5606 field_types, THUNK_HOST);
5607 }
5608 unlock_user(argptr, arg, 0);
5609
Peter Maydell49ca6f32016-06-06 19:58:14 +01005610 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005611 if (*host_rt_dev_ptr != 0) {
5612 unlock_user((void *)*host_rt_dev_ptr,
5613 *target_rt_dev_ptr, 0);
5614 }
5615 return ret;
5616}
5617
Paul Burtonca56f5b2014-06-22 11:25:47 +01005618static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005619 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005620{
5621 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005622 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005623}
5624
blueswir19f106a72008-10-05 10:52:52 +00005625static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005626#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005627 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5628#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5629 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005630#define IOCTL_IGNORE(cmd) \
5631 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005632#include "ioctls.h"
5633 { 0, 0, },
5634};
5635
pbrook53a59602006-03-25 19:31:22 +00005636/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005637/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005638static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005639{
5640 const IOCTLEntry *ie;
5641 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005642 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005643 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005644 int target_size;
5645 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005646
5647 ie = ioctl_entries;
5648 for(;;) {
5649 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005650 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005651 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005652 }
5653 if (ie->target_cmd == cmd)
5654 break;
5655 ie++;
5656 }
5657 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005658#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005659 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005660#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005661 if (ie->do_ioctl) {
5662 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005663 } else if (!ie->host_cmd) {
5664 /* Some architectures define BSD ioctls in their headers
5665 that are not implemented in Linux. */
5666 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005667 }
5668
bellard31e31b82003-02-18 22:55:36 +00005669 switch(arg_type[0]) {
5670 case TYPE_NULL:
5671 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005672 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005673 break;
5674 case TYPE_PTRVOID:
5675 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005676 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005677 break;
5678 case TYPE_PTR:
5679 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005680 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005681 switch(ie->access) {
5682 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005683 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005684 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005685 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5686 if (!argptr)
5687 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005688 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5689 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005690 }
5691 break;
5692 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005693 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5694 if (!argptr)
5695 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005696 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5697 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005698 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005699 break;
5700 default:
5701 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005702 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5703 if (!argptr)
5704 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005705 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5706 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005707 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005708 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005709 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5710 if (!argptr)
5711 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005712 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5713 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005714 }
5715 break;
5716 }
5717 break;
5718 default:
j_mayer32407102007-09-26 23:01:49 +00005719 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5720 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005721 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005722 break;
5723 }
5724 return ret;
5725}
5726
blueswir1b39bc502008-10-05 10:51:10 +00005727static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005728 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5729 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5730 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5731 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5732 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5733 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5734 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5735 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5736 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5737 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5738 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5739 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5740 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5741 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5742 { 0, 0, 0, 0 }
5743};
5744
blueswir1b39bc502008-10-05 10:51:10 +00005745static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005746 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5747 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5748 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5749 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5750 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5751 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5752 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5753 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5754 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5755 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5756 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5757 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5758 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5759 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5760 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5761 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5762 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5763 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5764 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5765 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5766 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5767 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5768 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5769 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5770 { 0, 0, 0, 0 }
5771};
5772
blueswir1b39bc502008-10-05 10:51:10 +00005773static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005774 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5775 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5776 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5777 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5778 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5779 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5780 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5781 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5782 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5783 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5784 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5785 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5786 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5787 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5788 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5789 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5790 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5791 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5792 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5793 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5794 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5795 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5796 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5797 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5798 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5799 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5800 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5801 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5802 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5803 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5804 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5805 { 0, 0, 0, 0 }
5806};
5807
blueswir1b39bc502008-10-05 10:51:10 +00005808static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005809 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5810 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5811 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5812 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5813 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5814 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5815 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5816 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5817 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5818 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5819 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5820 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5821 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5822 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5823 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5824 { 0, 0, 0, 0 }
5825};
5826
5827static void target_to_host_termios (void *dst, const void *src)
5828{
5829 struct host_termios *host = dst;
5830 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005831
ths5fafdf22007-09-16 21:08:06 +00005832 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005833 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005834 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005835 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005836 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005837 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005838 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005839 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5840 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005841
Arnaud Patard44607122009-04-21 17:39:08 +03005842 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005843 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5844 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005845 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005846 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005847 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005848 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005849 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005850 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005851 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005852 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5853 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005854 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5855 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5856 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5857 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5858 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005859 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005860}
ths3b46e622007-09-17 08:09:54 +00005861
bellard31e31b82003-02-18 22:55:36 +00005862static void host_to_target_termios (void *dst, const void *src)
5863{
5864 struct target_termios *target = dst;
5865 const struct host_termios *host = src;
5866
ths5fafdf22007-09-16 21:08:06 +00005867 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005868 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005869 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005870 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005871 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005872 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005873 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005874 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5875 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005876
Arnaud Patard44607122009-04-21 17:39:08 +03005877 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005878 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5879 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5880 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5881 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5882 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5883 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5884 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5885 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5886 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5887 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5888 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5889 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5890 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5891 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5892 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5893 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5894 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5895}
5896
blueswir18e853dc2008-10-05 10:49:32 +00005897static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005898 .convert = { host_to_target_termios, target_to_host_termios },
5899 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5900 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5901};
5902
bellard5286db72003-06-05 00:57:30 +00005903static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005904 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5905 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5906 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5907 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5908 MAP_ANONYMOUS, MAP_ANONYMOUS },
5909 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5910 MAP_GROWSDOWN, MAP_GROWSDOWN },
5911 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5912 MAP_DENYWRITE, MAP_DENYWRITE },
5913 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5914 MAP_EXECUTABLE, MAP_EXECUTABLE },
5915 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
5916 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
5917 MAP_NORESERVE, MAP_NORESERVE },
5918 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
5919 /* MAP_STACK had been ignored by the kernel for quite some time.
5920 Recognize it for the target insofar as we do not want to pass
5921 it through to the host. */
5922 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
5923 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00005924};
5925
bellard2ab83ea2003-06-15 19:56:46 +00005926#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005927
5928/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005929static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005930
bellard03acab62007-11-11 14:57:14 +00005931static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005932{
5933 int size;
pbrook53a59602006-03-25 19:31:22 +00005934 void *p;
bellard6dbad632003-03-16 18:05:05 +00005935
5936 if (!ldt_table)
5937 return 0;
5938 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5939 if (size > bytecount)
5940 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005941 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5942 if (!p)
bellard03acab62007-11-11 14:57:14 +00005943 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005944 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005945 memcpy(p, ldt_table, size);
5946 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005947 return size;
5948}
5949
5950/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005951static abi_long write_ldt(CPUX86State *env,
5952 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005953{
5954 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005955 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005956 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005957 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005958 uint32_t *lp, entry_1, entry_2;
5959
5960 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005961 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005962 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005963 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005964 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005965 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005966 ldt_info.limit = tswap32(target_ldt_info->limit);
5967 ldt_info.flags = tswap32(target_ldt_info->flags);
5968 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005969
bellard6dbad632003-03-16 18:05:05 +00005970 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005971 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005972 seg_32bit = ldt_info.flags & 1;
5973 contents = (ldt_info.flags >> 1) & 3;
5974 read_exec_only = (ldt_info.flags >> 3) & 1;
5975 limit_in_pages = (ldt_info.flags >> 4) & 1;
5976 seg_not_present = (ldt_info.flags >> 5) & 1;
5977 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005978#ifdef TARGET_ABI32
5979 lm = 0;
5980#else
5981 lm = (ldt_info.flags >> 7) & 1;
5982#endif
bellard6dbad632003-03-16 18:05:05 +00005983 if (contents == 3) {
5984 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005985 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005986 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005987 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005988 }
5989 /* allocate the LDT */
5990 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005991 env->ldt.base = target_mmap(0,
5992 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5993 PROT_READ|PROT_WRITE,
5994 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5995 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005996 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005997 memset(g2h(env->ldt.base), 0,
5998 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005999 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006000 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006001 }
6002
6003 /* NOTE: same code as Linux kernel */
6004 /* Allow LDTs to be cleared by the user. */
6005 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6006 if (oldmode ||
6007 (contents == 0 &&
6008 read_exec_only == 1 &&
6009 seg_32bit == 0 &&
6010 limit_in_pages == 0 &&
6011 seg_not_present == 1 &&
6012 useable == 0 )) {
6013 entry_1 = 0;
6014 entry_2 = 0;
6015 goto install;
6016 }
6017 }
ths3b46e622007-09-17 08:09:54 +00006018
bellard6dbad632003-03-16 18:05:05 +00006019 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6020 (ldt_info.limit & 0x0ffff);
6021 entry_2 = (ldt_info.base_addr & 0xff000000) |
6022 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6023 (ldt_info.limit & 0xf0000) |
6024 ((read_exec_only ^ 1) << 9) |
6025 (contents << 10) |
6026 ((seg_not_present ^ 1) << 15) |
6027 (seg_32bit << 22) |
6028 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006029 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006030 0x7000;
6031 if (!oldmode)
6032 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006033
bellard6dbad632003-03-16 18:05:05 +00006034 /* Install the new entry ... */
6035install:
6036 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6037 lp[0] = tswap32(entry_1);
6038 lp[1] = tswap32(entry_2);
6039 return 0;
6040}
6041
6042/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006043static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6044 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006045{
bellard03acab62007-11-11 14:57:14 +00006046 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006047
bellard6dbad632003-03-16 18:05:05 +00006048 switch (func) {
6049 case 0:
6050 ret = read_ldt(ptr, bytecount);
6051 break;
6052 case 1:
6053 ret = write_ldt(env, ptr, bytecount, 1);
6054 break;
6055 case 0x11:
6056 ret = write_ldt(env, ptr, bytecount, 0);
6057 break;
bellard03acab62007-11-11 14:57:14 +00006058 default:
6059 ret = -TARGET_ENOSYS;
6060 break;
bellard6dbad632003-03-16 18:05:05 +00006061 }
6062 return ret;
6063}
bellard1b6b0292003-03-22 17:31:38 +00006064
blueswir14583f582008-08-24 10:35:55 +00006065#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006066abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006067{
6068 uint64_t *gdt_table = g2h(env->gdt.base);
6069 struct target_modify_ldt_ldt_s ldt_info;
6070 struct target_modify_ldt_ldt_s *target_ldt_info;
6071 int seg_32bit, contents, read_exec_only, limit_in_pages;
6072 int seg_not_present, useable, lm;
6073 uint32_t *lp, entry_1, entry_2;
6074 int i;
6075
6076 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6077 if (!target_ldt_info)
6078 return -TARGET_EFAULT;
6079 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006080 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006081 ldt_info.limit = tswap32(target_ldt_info->limit);
6082 ldt_info.flags = tswap32(target_ldt_info->flags);
6083 if (ldt_info.entry_number == -1) {
6084 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6085 if (gdt_table[i] == 0) {
6086 ldt_info.entry_number = i;
6087 target_ldt_info->entry_number = tswap32(i);
6088 break;
6089 }
6090 }
6091 }
6092 unlock_user_struct(target_ldt_info, ptr, 1);
6093
6094 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6095 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6096 return -TARGET_EINVAL;
6097 seg_32bit = ldt_info.flags & 1;
6098 contents = (ldt_info.flags >> 1) & 3;
6099 read_exec_only = (ldt_info.flags >> 3) & 1;
6100 limit_in_pages = (ldt_info.flags >> 4) & 1;
6101 seg_not_present = (ldt_info.flags >> 5) & 1;
6102 useable = (ldt_info.flags >> 6) & 1;
6103#ifdef TARGET_ABI32
6104 lm = 0;
6105#else
6106 lm = (ldt_info.flags >> 7) & 1;
6107#endif
6108
6109 if (contents == 3) {
6110 if (seg_not_present == 0)
6111 return -TARGET_EINVAL;
6112 }
6113
6114 /* NOTE: same code as Linux kernel */
6115 /* Allow LDTs to be cleared by the user. */
6116 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6117 if ((contents == 0 &&
6118 read_exec_only == 1 &&
6119 seg_32bit == 0 &&
6120 limit_in_pages == 0 &&
6121 seg_not_present == 1 &&
6122 useable == 0 )) {
6123 entry_1 = 0;
6124 entry_2 = 0;
6125 goto install;
6126 }
6127 }
6128
6129 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6130 (ldt_info.limit & 0x0ffff);
6131 entry_2 = (ldt_info.base_addr & 0xff000000) |
6132 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6133 (ldt_info.limit & 0xf0000) |
6134 ((read_exec_only ^ 1) << 9) |
6135 (contents << 10) |
6136 ((seg_not_present ^ 1) << 15) |
6137 (seg_32bit << 22) |
6138 (limit_in_pages << 23) |
6139 (useable << 20) |
6140 (lm << 21) |
6141 0x7000;
6142
6143 /* Install the new entry ... */
6144install:
6145 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6146 lp[0] = tswap32(entry_1);
6147 lp[1] = tswap32(entry_2);
6148 return 0;
6149}
6150
blueswir18fcd3692008-08-17 20:26:25 +00006151static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006152{
6153 struct target_modify_ldt_ldt_s *target_ldt_info;
6154 uint64_t *gdt_table = g2h(env->gdt.base);
6155 uint32_t base_addr, limit, flags;
6156 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6157 int seg_not_present, useable, lm;
6158 uint32_t *lp, entry_1, entry_2;
6159
6160 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6161 if (!target_ldt_info)
6162 return -TARGET_EFAULT;
6163 idx = tswap32(target_ldt_info->entry_number);
6164 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6165 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6166 unlock_user_struct(target_ldt_info, ptr, 1);
6167 return -TARGET_EINVAL;
6168 }
6169 lp = (uint32_t *)(gdt_table + idx);
6170 entry_1 = tswap32(lp[0]);
6171 entry_2 = tswap32(lp[1]);
6172
6173 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6174 contents = (entry_2 >> 10) & 3;
6175 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6176 seg_32bit = (entry_2 >> 22) & 1;
6177 limit_in_pages = (entry_2 >> 23) & 1;
6178 useable = (entry_2 >> 20) & 1;
6179#ifdef TARGET_ABI32
6180 lm = 0;
6181#else
6182 lm = (entry_2 >> 21) & 1;
6183#endif
6184 flags = (seg_32bit << 0) | (contents << 1) |
6185 (read_exec_only << 3) | (limit_in_pages << 4) |
6186 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6187 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6188 base_addr = (entry_1 >> 16) |
6189 (entry_2 & 0xff000000) |
6190 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006191 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006192 target_ldt_info->limit = tswap32(limit);
6193 target_ldt_info->flags = tswap32(flags);
6194 unlock_user_struct(target_ldt_info, ptr, 1);
6195 return 0;
6196}
blueswir14583f582008-08-24 10:35:55 +00006197#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006198
bellardd2fd1af2007-11-14 18:08:56 +00006199#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006200abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006201{
Juan Quintela1add8692011-06-16 17:37:09 +01006202 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006203 abi_ulong val;
6204 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006205
bellardd2fd1af2007-11-14 18:08:56 +00006206 switch(code) {
6207 case TARGET_ARCH_SET_GS:
6208 case TARGET_ARCH_SET_FS:
6209 if (code == TARGET_ARCH_SET_GS)
6210 idx = R_GS;
6211 else
6212 idx = R_FS;
6213 cpu_x86_load_seg(env, idx, 0);
6214 env->segs[idx].base = addr;
6215 break;
6216 case TARGET_ARCH_GET_GS:
6217 case TARGET_ARCH_GET_FS:
6218 if (code == TARGET_ARCH_GET_GS)
6219 idx = R_GS;
6220 else
6221 idx = R_FS;
6222 val = env->segs[idx].base;
6223 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006224 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006225 break;
6226 default:
6227 ret = -TARGET_EINVAL;
6228 break;
6229 }
Juan Quintela1add8692011-06-16 17:37:09 +01006230 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006231}
6232#endif
6233
bellard2ab83ea2003-06-15 19:56:46 +00006234#endif /* defined(TARGET_I386) */
6235
Riku Voipio05098a92011-03-04 15:27:29 +02006236#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006237
pbrookd865bab2008-06-07 22:12:17 +00006238
6239static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6240typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006241 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006242 pthread_mutex_t mutex;
6243 pthread_cond_t cond;
6244 pthread_t thread;
6245 uint32_t tid;
6246 abi_ulong child_tidptr;
6247 abi_ulong parent_tidptr;
6248 sigset_t sigmask;
6249} new_thread_info;
6250
6251static void *clone_func(void *arg)
6252{
6253 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006254 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006255 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006256 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006257
Emilio G. Cota70903762015-08-23 20:23:41 -04006258 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006259 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006260 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006261 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006262 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006263 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006264 info->tid = gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006265 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006266 if (info->child_tidptr)
6267 put_user_u32(info->tid, info->child_tidptr);
6268 if (info->parent_tidptr)
6269 put_user_u32(info->tid, info->parent_tidptr);
6270 /* Enable signals. */
6271 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6272 /* Signal to the parent that we're ready. */
6273 pthread_mutex_lock(&info->mutex);
6274 pthread_cond_broadcast(&info->cond);
6275 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006276 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006277 pthread_mutex_lock(&clone_lock);
6278 pthread_mutex_unlock(&clone_lock);
6279 cpu_loop(env);
6280 /* never exits */
6281 return NULL;
6282}
bellard1b6b0292003-03-22 17:31:38 +00006283
ths0da46a62007-10-20 20:23:07 +00006284/* do_fork() Must return host values and target errnos (unlike most
6285 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006286static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006287 abi_ulong parent_tidptr, target_ulong newtls,
6288 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006289{
Andreas Färber0429a972013-08-26 18:14:44 +02006290 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006291 int ret;
bellard5cd43932003-03-29 16:54:36 +00006292 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006293 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006294 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006295 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006296
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006297 flags &= ~CLONE_IGNORED_FLAGS;
6298
balrog436d1242008-09-21 02:39:45 +00006299 /* Emulate vfork() with fork() */
6300 if (flags & CLONE_VFORK)
6301 flags &= ~(CLONE_VFORK | CLONE_VM);
6302
bellard1b6b0292003-03-22 17:31:38 +00006303 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006304 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006305 new_thread_info info;
6306 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006307
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006308 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6309 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6310 return -TARGET_EINVAL;
6311 }
6312
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006313 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006314 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00006315 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006316 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006317 /* Init regs that differ from the parent. */
6318 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006319 new_cpu = ENV_GET_CPU(new_env);
6320 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006321 ts->bprm = parent_ts->bprm;
6322 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006323 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006324
Peter Maydell7cfbd382016-08-02 18:41:26 +01006325 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006326 ts->child_tidptr = child_tidptr;
6327 }
6328
Peter Maydell7cfbd382016-08-02 18:41:26 +01006329 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006330 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006331 }
pbrookd865bab2008-06-07 22:12:17 +00006332
6333 /* Grab a mutex so that thread setup appears atomic. */
6334 pthread_mutex_lock(&clone_lock);
6335
6336 memset(&info, 0, sizeof(info));
6337 pthread_mutex_init(&info.mutex, NULL);
6338 pthread_mutex_lock(&info.mutex);
6339 pthread_cond_init(&info.cond, NULL);
6340 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006341 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006342 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006343 }
6344 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006345 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006346 }
pbrookd865bab2008-06-07 22:12:17 +00006347
6348 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006349 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6350 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006351 /* It is not safe to deliver signals until the child has finished
6352 initializing, so temporarily block all signals. */
6353 sigfillset(&sigmask);
6354 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6355
Alex Bennéeb67cb682016-10-05 11:13:04 -07006356 /* If this is our first additional thread, we need to ensure we
6357 * generate code for parallel execution and flush old translations.
6358 */
6359 if (!parallel_cpus) {
6360 parallel_cpus = true;
6361 tb_flush(cpu);
6362 }
6363
pbrookd865bab2008-06-07 22:12:17 +00006364 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006365 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006366
6367 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6368 pthread_attr_destroy(&attr);
6369 if (ret == 0) {
6370 /* Wait for the child to initialize. */
6371 pthread_cond_wait(&info.cond, &info.mutex);
6372 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006373 } else {
6374 ret = -1;
6375 }
6376 pthread_mutex_unlock(&info.mutex);
6377 pthread_cond_destroy(&info.cond);
6378 pthread_mutex_destroy(&info.mutex);
6379 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006380 } else {
6381 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006382 if (flags & CLONE_INVALID_FORK_FLAGS) {
6383 return -TARGET_EINVAL;
6384 }
6385
6386 /* We can't support custom termination signals */
6387 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006388 return -TARGET_EINVAL;
6389 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006390
6391 if (block_signals()) {
6392 return -TARGET_ERESTARTSYS;
6393 }
6394
pbrookd865bab2008-06-07 22:12:17 +00006395 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006396 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006397 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006398 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00006399 cpu_clone_regs(env, newsp);
6400 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006401 /* There is a race condition here. The parent process could
6402 theoretically read the TID in the child process before the child
6403 tid is set. This would require using either ptrace
6404 (not implemented) or having *_tidptr to point at a shared memory
6405 mapping. We can't repeat the spinlock hack used above because
6406 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006407 if (flags & CLONE_CHILD_SETTID)
6408 put_user_u32(gettid(), child_tidptr);
6409 if (flags & CLONE_PARENT_SETTID)
6410 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006411 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006412 if (flags & CLONE_SETTLS)
6413 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006414 if (flags & CLONE_CHILD_CLEARTID)
6415 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006416 } else {
6417 fork_end(0);
6418 }
bellard1b6b0292003-03-22 17:31:38 +00006419 }
6420 return ret;
6421}
6422
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006423/* warning : doesn't handle linux specific flags... */
6424static int target_to_host_fcntl_cmd(int cmd)
6425{
6426 switch(cmd) {
6427 case TARGET_F_DUPFD:
6428 case TARGET_F_GETFD:
6429 case TARGET_F_SETFD:
6430 case TARGET_F_GETFL:
6431 case TARGET_F_SETFL:
6432 return cmd;
6433 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006434 return F_GETLK64;
6435 case TARGET_F_SETLK:
6436 return F_SETLK64;
6437 case TARGET_F_SETLKW:
6438 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006439 case TARGET_F_GETOWN:
6440 return F_GETOWN;
6441 case TARGET_F_SETOWN:
6442 return F_SETOWN;
6443 case TARGET_F_GETSIG:
6444 return F_GETSIG;
6445 case TARGET_F_SETSIG:
6446 return F_SETSIG;
6447#if TARGET_ABI_BITS == 32
6448 case TARGET_F_GETLK64:
6449 return F_GETLK64;
6450 case TARGET_F_SETLK64:
6451 return F_SETLK64;
6452 case TARGET_F_SETLKW64:
6453 return F_SETLKW64;
6454#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006455 case TARGET_F_SETLEASE:
6456 return F_SETLEASE;
6457 case TARGET_F_GETLEASE:
6458 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006459#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006460 case TARGET_F_DUPFD_CLOEXEC:
6461 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006462#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006463 case TARGET_F_NOTIFY:
6464 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006465#ifdef F_GETOWN_EX
6466 case TARGET_F_GETOWN_EX:
6467 return F_GETOWN_EX;
6468#endif
6469#ifdef F_SETOWN_EX
6470 case TARGET_F_SETOWN_EX:
6471 return F_SETOWN_EX;
6472#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006473#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006474 case TARGET_F_SETPIPE_SZ:
6475 return F_SETPIPE_SZ;
6476 case TARGET_F_GETPIPE_SZ:
6477 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006478#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006479 default:
6480 return -TARGET_EINVAL;
6481 }
6482 return -TARGET_EINVAL;
6483}
6484
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006485#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6486static const bitmask_transtbl flock_tbl[] = {
6487 TRANSTBL_CONVERT(F_RDLCK),
6488 TRANSTBL_CONVERT(F_WRLCK),
6489 TRANSTBL_CONVERT(F_UNLCK),
6490 TRANSTBL_CONVERT(F_EXLCK),
6491 TRANSTBL_CONVERT(F_SHLCK),
6492 { 0, 0, 0, 0 }
6493};
6494
Peter Maydell213d3e92016-06-13 11:22:05 +01006495static inline abi_long copy_from_user_flock(struct flock64 *fl,
6496 abi_ulong target_flock_addr)
6497{
6498 struct target_flock *target_fl;
6499 short l_type;
6500
6501 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6502 return -TARGET_EFAULT;
6503 }
6504
6505 __get_user(l_type, &target_fl->l_type);
6506 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6507 __get_user(fl->l_whence, &target_fl->l_whence);
6508 __get_user(fl->l_start, &target_fl->l_start);
6509 __get_user(fl->l_len, &target_fl->l_len);
6510 __get_user(fl->l_pid, &target_fl->l_pid);
6511 unlock_user_struct(target_fl, target_flock_addr, 0);
6512 return 0;
6513}
6514
6515static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6516 const struct flock64 *fl)
6517{
6518 struct target_flock *target_fl;
6519 short l_type;
6520
6521 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6522 return -TARGET_EFAULT;
6523 }
6524
6525 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6526 __put_user(l_type, &target_fl->l_type);
6527 __put_user(fl->l_whence, &target_fl->l_whence);
6528 __put_user(fl->l_start, &target_fl->l_start);
6529 __put_user(fl->l_len, &target_fl->l_len);
6530 __put_user(fl->l_pid, &target_fl->l_pid);
6531 unlock_user_struct(target_fl, target_flock_addr, 1);
6532 return 0;
6533}
6534
6535typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6536typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6537
6538#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6539static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6540 abi_ulong target_flock_addr)
6541{
6542 struct target_eabi_flock64 *target_fl;
6543 short l_type;
6544
6545 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6546 return -TARGET_EFAULT;
6547 }
6548
6549 __get_user(l_type, &target_fl->l_type);
6550 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6551 __get_user(fl->l_whence, &target_fl->l_whence);
6552 __get_user(fl->l_start, &target_fl->l_start);
6553 __get_user(fl->l_len, &target_fl->l_len);
6554 __get_user(fl->l_pid, &target_fl->l_pid);
6555 unlock_user_struct(target_fl, target_flock_addr, 0);
6556 return 0;
6557}
6558
6559static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6560 const struct flock64 *fl)
6561{
6562 struct target_eabi_flock64 *target_fl;
6563 short l_type;
6564
6565 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6566 return -TARGET_EFAULT;
6567 }
6568
6569 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6570 __put_user(l_type, &target_fl->l_type);
6571 __put_user(fl->l_whence, &target_fl->l_whence);
6572 __put_user(fl->l_start, &target_fl->l_start);
6573 __put_user(fl->l_len, &target_fl->l_len);
6574 __put_user(fl->l_pid, &target_fl->l_pid);
6575 unlock_user_struct(target_fl, target_flock_addr, 1);
6576 return 0;
6577}
6578#endif
6579
6580static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6581 abi_ulong target_flock_addr)
6582{
6583 struct target_flock64 *target_fl;
6584 short l_type;
6585
6586 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6587 return -TARGET_EFAULT;
6588 }
6589
6590 __get_user(l_type, &target_fl->l_type);
6591 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6592 __get_user(fl->l_whence, &target_fl->l_whence);
6593 __get_user(fl->l_start, &target_fl->l_start);
6594 __get_user(fl->l_len, &target_fl->l_len);
6595 __get_user(fl->l_pid, &target_fl->l_pid);
6596 unlock_user_struct(target_fl, target_flock_addr, 0);
6597 return 0;
6598}
6599
6600static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6601 const struct flock64 *fl)
6602{
6603 struct target_flock64 *target_fl;
6604 short l_type;
6605
6606 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6607 return -TARGET_EFAULT;
6608 }
6609
6610 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6611 __put_user(l_type, &target_fl->l_type);
6612 __put_user(fl->l_whence, &target_fl->l_whence);
6613 __put_user(fl->l_start, &target_fl->l_start);
6614 __put_user(fl->l_len, &target_fl->l_len);
6615 __put_user(fl->l_pid, &target_fl->l_pid);
6616 unlock_user_struct(target_fl, target_flock_addr, 1);
6617 return 0;
6618}
6619
blueswir1992f48a2007-10-14 16:27:31 +00006620static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006621{
ths43f238d2007-01-05 20:55:49 +00006622 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006623#ifdef F_GETOWN_EX
6624 struct f_owner_ex fox;
6625 struct target_f_owner_ex *target_fox;
6626#endif
blueswir1992f48a2007-10-14 16:27:31 +00006627 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006628 int host_cmd = target_to_host_fcntl_cmd(cmd);
6629
6630 if (host_cmd == -TARGET_EINVAL)
6631 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006632
bellard7775e9e2003-05-14 22:46:48 +00006633 switch(cmd) {
6634 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006635 ret = copy_from_user_flock(&fl64, arg);
6636 if (ret) {
6637 return ret;
6638 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006639 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006640 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006641 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006642 }
6643 break;
ths3b46e622007-09-17 08:09:54 +00006644
bellard7775e9e2003-05-14 22:46:48 +00006645 case TARGET_F_SETLK:
6646 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006647 ret = copy_from_user_flock(&fl64, arg);
6648 if (ret) {
6649 return ret;
6650 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006651 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006652 break;
ths3b46e622007-09-17 08:09:54 +00006653
bellard7775e9e2003-05-14 22:46:48 +00006654 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006655 ret = copy_from_user_flock64(&fl64, arg);
6656 if (ret) {
6657 return ret;
6658 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006659 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006660 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006661 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006662 }
bellard9ee1fa22007-11-11 15:11:19 +00006663 break;
bellard7775e9e2003-05-14 22:46:48 +00006664 case TARGET_F_SETLK64:
6665 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006666 ret = copy_from_user_flock64(&fl64, arg);
6667 if (ret) {
6668 return ret;
6669 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006670 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006671 break;
6672
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006673 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006674 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006675 if (ret >= 0) {
6676 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6677 }
bellardffa65c32004-01-04 23:57:22 +00006678 break;
6679
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006680 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006681 ret = get_errno(safe_fcntl(fd, host_cmd,
6682 target_to_host_bitmask(arg,
6683 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006684 break;
6685
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006686#ifdef F_GETOWN_EX
6687 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006688 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006689 if (ret >= 0) {
6690 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6691 return -TARGET_EFAULT;
6692 target_fox->type = tswap32(fox.type);
6693 target_fox->pid = tswap32(fox.pid);
6694 unlock_user_struct(target_fox, arg, 1);
6695 }
6696 break;
6697#endif
6698
6699#ifdef F_SETOWN_EX
6700 case TARGET_F_SETOWN_EX:
6701 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6702 return -TARGET_EFAULT;
6703 fox.type = tswap32(target_fox->type);
6704 fox.pid = tswap32(target_fox->pid);
6705 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006706 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006707 break;
6708#endif
6709
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006710 case TARGET_F_SETOWN:
6711 case TARGET_F_GETOWN:
6712 case TARGET_F_SETSIG:
6713 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006714 case TARGET_F_SETLEASE:
6715 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006716 case TARGET_F_SETPIPE_SZ:
6717 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006718 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006719 break;
6720
bellard7775e9e2003-05-14 22:46:48 +00006721 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006722 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006723 break;
6724 }
6725 return ret;
6726}
6727
bellard67867302003-11-23 17:05:30 +00006728#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006729
bellard67867302003-11-23 17:05:30 +00006730static inline int high2lowuid(int uid)
6731{
6732 if (uid > 65535)
6733 return 65534;
6734 else
6735 return uid;
6736}
6737
6738static inline int high2lowgid(int gid)
6739{
6740 if (gid > 65535)
6741 return 65534;
6742 else
6743 return gid;
6744}
6745
6746static inline int low2highuid(int uid)
6747{
6748 if ((int16_t)uid == -1)
6749 return -1;
6750 else
6751 return uid;
6752}
6753
6754static inline int low2highgid(int gid)
6755{
6756 if ((int16_t)gid == -1)
6757 return -1;
6758 else
6759 return gid;
6760}
Riku Voipio0c866a72011-04-18 15:23:06 +03006761static inline int tswapid(int id)
6762{
6763 return tswap16(id);
6764}
Peter Maydell76ca3102014-03-02 19:36:41 +00006765
6766#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6767
Riku Voipio0c866a72011-04-18 15:23:06 +03006768#else /* !USE_UID16 */
6769static inline int high2lowuid(int uid)
6770{
6771 return uid;
6772}
6773static inline int high2lowgid(int gid)
6774{
6775 return gid;
6776}
6777static inline int low2highuid(int uid)
6778{
6779 return uid;
6780}
6781static inline int low2highgid(int gid)
6782{
6783 return gid;
6784}
6785static inline int tswapid(int id)
6786{
6787 return tswap32(id);
6788}
Peter Maydell76ca3102014-03-02 19:36:41 +00006789
6790#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6791
bellard67867302003-11-23 17:05:30 +00006792#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006793
Peter Maydellfd6f7792016-03-01 16:33:02 +00006794/* We must do direct syscalls for setting UID/GID, because we want to
6795 * implement the Linux system call semantics of "change only for this thread",
6796 * not the libc/POSIX semantics of "change for all threads in process".
6797 * (See http://ewontfix.com/17/ for more details.)
6798 * We use the 32-bit version of the syscalls if present; if it is not
6799 * then either the host architecture supports 32-bit UIDs natively with
6800 * the standard syscall, or the 16-bit UID is the best we can do.
6801 */
6802#ifdef __NR_setuid32
6803#define __NR_sys_setuid __NR_setuid32
6804#else
6805#define __NR_sys_setuid __NR_setuid
6806#endif
6807#ifdef __NR_setgid32
6808#define __NR_sys_setgid __NR_setgid32
6809#else
6810#define __NR_sys_setgid __NR_setgid
6811#endif
6812#ifdef __NR_setresuid32
6813#define __NR_sys_setresuid __NR_setresuid32
6814#else
6815#define __NR_sys_setresuid __NR_setresuid
6816#endif
6817#ifdef __NR_setresgid32
6818#define __NR_sys_setresgid __NR_setresgid32
6819#else
6820#define __NR_sys_setresgid __NR_setresgid
6821#endif
6822
6823_syscall1(int, sys_setuid, uid_t, uid)
6824_syscall1(int, sys_setgid, gid_t, gid)
6825_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6826_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6827
bellard31e31b82003-02-18 22:55:36 +00006828void syscall_init(void)
6829{
bellard2ab83ea2003-06-15 19:56:46 +00006830 IOCTLEntry *ie;
6831 const argtype *arg_type;
6832 int size;
thsb92c47c2007-11-01 00:07:38 +00006833 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006834
Alexander Graf8be656b2015-05-06 23:47:32 +02006835 thunk_init(STRUCT_MAX);
6836
Blue Swirl001faf32009-05-13 17:53:17 +00006837#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006838#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006839#include "syscall_types.h"
6840#undef STRUCT
6841#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006842
Peter Maydelldd6e9572012-07-23 08:07:22 +00006843 /* Build target_to_host_errno_table[] table from
6844 * host_to_target_errno_table[]. */
6845 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6846 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6847 }
6848
bellard2ab83ea2003-06-15 19:56:46 +00006849 /* we patch the ioctl size if necessary. We rely on the fact that
6850 no ioctl has all the bits at '1' in the size field */
6851 ie = ioctl_entries;
6852 while (ie->target_cmd != 0) {
6853 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6854 TARGET_IOC_SIZEMASK) {
6855 arg_type = ie->arg_type;
6856 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006857 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006858 ie->target_cmd);
6859 exit(1);
6860 }
6861 arg_type++;
6862 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006863 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006864 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6865 (size << TARGET_IOC_SIZESHIFT);
6866 }
thsb92c47c2007-11-01 00:07:38 +00006867
bellard2ab83ea2003-06-15 19:56:46 +00006868 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006869#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6870 (defined(__x86_64__) && defined(TARGET_X86_64))
6871 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6872 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6873 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006874 }
6875#endif
6876 ie++;
6877 }
bellard31e31b82003-02-18 22:55:36 +00006878}
bellardc573ff62004-01-04 15:51:36 +00006879
blueswir1992f48a2007-10-14 16:27:31 +00006880#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006881static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6882{
thsaf325d32008-06-10 15:29:15 +00006883#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006884 return ((uint64_t)word0 << 32) | word1;
6885#else
6886 return ((uint64_t)word1 << 32) | word0;
6887#endif
6888}
blueswir1992f48a2007-10-14 16:27:31 +00006889#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006890static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6891{
6892 return word0;
6893}
blueswir1992f48a2007-10-14 16:27:31 +00006894#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006895
6896#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006897static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6898 abi_long arg2,
6899 abi_long arg3,
6900 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006901{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006902 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006903 arg2 = arg3;
6904 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006905 }
pbrookce4defa2006-02-09 16:49:55 +00006906 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6907}
6908#endif
6909
6910#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006911static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6912 abi_long arg2,
6913 abi_long arg3,
6914 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006915{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006916 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006917 arg2 = arg3;
6918 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006919 }
pbrookce4defa2006-02-09 16:49:55 +00006920 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6921}
6922#endif
6923
bellard579a97f2007-11-11 14:26:47 +00006924static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6925 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006926{
6927 struct target_timespec *target_ts;
6928
bellard579a97f2007-11-11 14:26:47 +00006929 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6930 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006931 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6932 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006933 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006934 return 0;
pbrook53a59602006-03-25 19:31:22 +00006935}
6936
bellard579a97f2007-11-11 14:26:47 +00006937static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6938 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006939{
6940 struct target_timespec *target_ts;
6941
bellard579a97f2007-11-11 14:26:47 +00006942 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6943 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006944 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6945 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006946 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006947 return 0;
pbrook53a59602006-03-25 19:31:22 +00006948}
6949
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006950static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6951 abi_ulong target_addr)
6952{
6953 struct target_itimerspec *target_itspec;
6954
6955 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6956 return -TARGET_EFAULT;
6957 }
6958
6959 host_itspec->it_interval.tv_sec =
6960 tswapal(target_itspec->it_interval.tv_sec);
6961 host_itspec->it_interval.tv_nsec =
6962 tswapal(target_itspec->it_interval.tv_nsec);
6963 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6964 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6965
6966 unlock_user_struct(target_itspec, target_addr, 1);
6967 return 0;
6968}
6969
6970static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6971 struct itimerspec *host_its)
6972{
6973 struct target_itimerspec *target_itspec;
6974
6975 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6976 return -TARGET_EFAULT;
6977 }
6978
6979 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6980 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6981
6982 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6983 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6984
6985 unlock_user_struct(target_itspec, target_addr, 0);
6986 return 0;
6987}
6988
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02006989static inline abi_long target_to_host_timex(struct timex *host_tx,
6990 abi_long target_addr)
6991{
6992 struct target_timex *target_tx;
6993
6994 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
6995 return -TARGET_EFAULT;
6996 }
6997
6998 __get_user(host_tx->modes, &target_tx->modes);
6999 __get_user(host_tx->offset, &target_tx->offset);
7000 __get_user(host_tx->freq, &target_tx->freq);
7001 __get_user(host_tx->maxerror, &target_tx->maxerror);
7002 __get_user(host_tx->esterror, &target_tx->esterror);
7003 __get_user(host_tx->status, &target_tx->status);
7004 __get_user(host_tx->constant, &target_tx->constant);
7005 __get_user(host_tx->precision, &target_tx->precision);
7006 __get_user(host_tx->tolerance, &target_tx->tolerance);
7007 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7008 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7009 __get_user(host_tx->tick, &target_tx->tick);
7010 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7011 __get_user(host_tx->jitter, &target_tx->jitter);
7012 __get_user(host_tx->shift, &target_tx->shift);
7013 __get_user(host_tx->stabil, &target_tx->stabil);
7014 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7015 __get_user(host_tx->calcnt, &target_tx->calcnt);
7016 __get_user(host_tx->errcnt, &target_tx->errcnt);
7017 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7018 __get_user(host_tx->tai, &target_tx->tai);
7019
7020 unlock_user_struct(target_tx, target_addr, 0);
7021 return 0;
7022}
7023
7024static inline abi_long host_to_target_timex(abi_long target_addr,
7025 struct timex *host_tx)
7026{
7027 struct target_timex *target_tx;
7028
7029 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7030 return -TARGET_EFAULT;
7031 }
7032
7033 __put_user(host_tx->modes, &target_tx->modes);
7034 __put_user(host_tx->offset, &target_tx->offset);
7035 __put_user(host_tx->freq, &target_tx->freq);
7036 __put_user(host_tx->maxerror, &target_tx->maxerror);
7037 __put_user(host_tx->esterror, &target_tx->esterror);
7038 __put_user(host_tx->status, &target_tx->status);
7039 __put_user(host_tx->constant, &target_tx->constant);
7040 __put_user(host_tx->precision, &target_tx->precision);
7041 __put_user(host_tx->tolerance, &target_tx->tolerance);
7042 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7043 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7044 __put_user(host_tx->tick, &target_tx->tick);
7045 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7046 __put_user(host_tx->jitter, &target_tx->jitter);
7047 __put_user(host_tx->shift, &target_tx->shift);
7048 __put_user(host_tx->stabil, &target_tx->stabil);
7049 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7050 __put_user(host_tx->calcnt, &target_tx->calcnt);
7051 __put_user(host_tx->errcnt, &target_tx->errcnt);
7052 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7053 __put_user(host_tx->tai, &target_tx->tai);
7054
7055 unlock_user_struct(target_tx, target_addr, 1);
7056 return 0;
7057}
7058
7059
Peter Maydellc0659762014-08-09 15:42:32 +01007060static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7061 abi_ulong target_addr)
7062{
7063 struct target_sigevent *target_sevp;
7064
7065 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7066 return -TARGET_EFAULT;
7067 }
7068
7069 /* This union is awkward on 64 bit systems because it has a 32 bit
7070 * integer and a pointer in it; we follow the conversion approach
7071 * used for handling sigval types in signal.c so the guest should get
7072 * the correct value back even if we did a 64 bit byteswap and it's
7073 * using the 32 bit integer.
7074 */
7075 host_sevp->sigev_value.sival_ptr =
7076 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7077 host_sevp->sigev_signo =
7078 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7079 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7080 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7081
7082 unlock_user_struct(target_sevp, target_addr, 1);
7083 return 0;
7084}
7085
Tom Musta6f6a4032014-08-12 13:53:42 -05007086#if defined(TARGET_NR_mlockall)
7087static inline int target_to_host_mlockall_arg(int arg)
7088{
7089 int result = 0;
7090
7091 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7092 result |= MCL_CURRENT;
7093 }
7094 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7095 result |= MCL_FUTURE;
7096 }
7097 return result;
7098}
7099#endif
7100
balrog6a24a772008-09-20 02:23:36 +00007101static inline abi_long host_to_target_stat64(void *cpu_env,
7102 abi_ulong target_addr,
7103 struct stat *host_st)
7104{
Alexander Graf09701192013-09-03 20:12:15 +01007105#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007106 if (((CPUARMState *)cpu_env)->eabi) {
7107 struct target_eabi_stat64 *target_st;
7108
7109 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7110 return -TARGET_EFAULT;
7111 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7112 __put_user(host_st->st_dev, &target_st->st_dev);
7113 __put_user(host_st->st_ino, &target_st->st_ino);
7114#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7115 __put_user(host_st->st_ino, &target_st->__st_ino);
7116#endif
7117 __put_user(host_st->st_mode, &target_st->st_mode);
7118 __put_user(host_st->st_nlink, &target_st->st_nlink);
7119 __put_user(host_st->st_uid, &target_st->st_uid);
7120 __put_user(host_st->st_gid, &target_st->st_gid);
7121 __put_user(host_st->st_rdev, &target_st->st_rdev);
7122 __put_user(host_st->st_size, &target_st->st_size);
7123 __put_user(host_st->st_blksize, &target_st->st_blksize);
7124 __put_user(host_st->st_blocks, &target_st->st_blocks);
7125 __put_user(host_st->st_atime, &target_st->target_st_atime);
7126 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7127 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7128 unlock_user_struct(target_st, target_addr, 1);
7129 } else
7130#endif
7131 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007132#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007133 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007134#else
7135 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007136#endif
balrog6a24a772008-09-20 02:23:36 +00007137
7138 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7139 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007140 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007141 __put_user(host_st->st_dev, &target_st->st_dev);
7142 __put_user(host_st->st_ino, &target_st->st_ino);
7143#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7144 __put_user(host_st->st_ino, &target_st->__st_ino);
7145#endif
7146 __put_user(host_st->st_mode, &target_st->st_mode);
7147 __put_user(host_st->st_nlink, &target_st->st_nlink);
7148 __put_user(host_st->st_uid, &target_st->st_uid);
7149 __put_user(host_st->st_gid, &target_st->st_gid);
7150 __put_user(host_st->st_rdev, &target_st->st_rdev);
7151 /* XXX: better use of kernel struct */
7152 __put_user(host_st->st_size, &target_st->st_size);
7153 __put_user(host_st->st_blksize, &target_st->st_blksize);
7154 __put_user(host_st->st_blocks, &target_st->st_blocks);
7155 __put_user(host_st->st_atime, &target_st->target_st_atime);
7156 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7157 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7158 unlock_user_struct(target_st, target_addr, 1);
7159 }
7160
7161 return 0;
7162}
balrog6a24a772008-09-20 02:23:36 +00007163
pbrookbd0c5662008-05-29 14:34:11 +00007164/* ??? Using host futex calls even when target atomic operations
7165 are not really atomic probably breaks things. However implementing
7166 futexes locally would make futexes shared between multiple processes
7167 tricky. However they're probably useless because guest atomic
7168 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007169static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7170 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007171{
7172 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007173 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007174
7175 /* ??? We assume FUTEX_* constants are the same on both host
7176 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007177#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007178 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007179#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007180 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007181#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007182 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007183 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007184 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007185 if (timeout) {
7186 pts = &ts;
7187 target_to_host_timespec(pts, timeout);
7188 } else {
7189 pts = NULL;
7190 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007191 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007192 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007193 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007194 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007195 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007196 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007197 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007198 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007199 case FUTEX_WAKE_OP:
7200 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7201 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7202 But the prototype takes a `struct timespec *'; insert casts
7203 to satisfy the compiler. We do not need to tswap TIMEOUT
7204 since it's not compared to guest memory. */
7205 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007206 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7207 g2h(uaddr2),
7208 (base_op == FUTEX_CMP_REQUEUE
7209 ? tswap32(val3)
7210 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007211 default:
7212 return -TARGET_ENOSYS;
7213 }
7214}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007215#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7216static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7217 abi_long handle, abi_long mount_id,
7218 abi_long flags)
7219{
7220 struct file_handle *target_fh;
7221 struct file_handle *fh;
7222 int mid = 0;
7223 abi_long ret;
7224 char *name;
7225 unsigned int size, total_size;
7226
7227 if (get_user_s32(size, handle)) {
7228 return -TARGET_EFAULT;
7229 }
7230
7231 name = lock_user_string(pathname);
7232 if (!name) {
7233 return -TARGET_EFAULT;
7234 }
7235
7236 total_size = sizeof(struct file_handle) + size;
7237 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7238 if (!target_fh) {
7239 unlock_user(name, pathname, 0);
7240 return -TARGET_EFAULT;
7241 }
7242
7243 fh = g_malloc0(total_size);
7244 fh->handle_bytes = size;
7245
7246 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7247 unlock_user(name, pathname, 0);
7248
7249 /* man name_to_handle_at(2):
7250 * Other than the use of the handle_bytes field, the caller should treat
7251 * the file_handle structure as an opaque data type
7252 */
7253
7254 memcpy(target_fh, fh, total_size);
7255 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7256 target_fh->handle_type = tswap32(fh->handle_type);
7257 g_free(fh);
7258 unlock_user(target_fh, handle, total_size);
7259
7260 if (put_user_s32(mid, mount_id)) {
7261 return -TARGET_EFAULT;
7262 }
7263
7264 return ret;
7265
7266}
7267#endif
7268
7269#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7270static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7271 abi_long flags)
7272{
7273 struct file_handle *target_fh;
7274 struct file_handle *fh;
7275 unsigned int size, total_size;
7276 abi_long ret;
7277
7278 if (get_user_s32(size, handle)) {
7279 return -TARGET_EFAULT;
7280 }
7281
7282 total_size = sizeof(struct file_handle) + size;
7283 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7284 if (!target_fh) {
7285 return -TARGET_EFAULT;
7286 }
7287
Thomas Huthe9d49d52015-10-09 17:56:38 +02007288 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007289 fh->handle_bytes = size;
7290 fh->handle_type = tswap32(target_fh->handle_type);
7291
7292 ret = get_errno(open_by_handle_at(mount_fd, fh,
7293 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7294
7295 g_free(fh);
7296
7297 unlock_user(target_fh, handle, total_size);
7298
7299 return ret;
7300}
7301#endif
pbrookbd0c5662008-05-29 14:34:11 +00007302
Laurent Viviere36800c2015-10-02 14:48:09 +02007303#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7304
7305/* signalfd siginfo conversion */
7306
7307static void
7308host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7309 const struct signalfd_siginfo *info)
7310{
7311 int sig = host_to_target_signal(info->ssi_signo);
7312
7313 /* linux/signalfd.h defines a ssi_addr_lsb
7314 * not defined in sys/signalfd.h but used by some kernels
7315 */
7316
7317#ifdef BUS_MCEERR_AO
7318 if (tinfo->ssi_signo == SIGBUS &&
7319 (tinfo->ssi_code == BUS_MCEERR_AR ||
7320 tinfo->ssi_code == BUS_MCEERR_AO)) {
7321 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7322 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7323 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7324 }
7325#endif
7326
7327 tinfo->ssi_signo = tswap32(sig);
7328 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7329 tinfo->ssi_code = tswap32(info->ssi_code);
7330 tinfo->ssi_pid = tswap32(info->ssi_pid);
7331 tinfo->ssi_uid = tswap32(info->ssi_uid);
7332 tinfo->ssi_fd = tswap32(info->ssi_fd);
7333 tinfo->ssi_tid = tswap32(info->ssi_tid);
7334 tinfo->ssi_band = tswap32(info->ssi_band);
7335 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7336 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7337 tinfo->ssi_status = tswap32(info->ssi_status);
7338 tinfo->ssi_int = tswap32(info->ssi_int);
7339 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7340 tinfo->ssi_utime = tswap64(info->ssi_utime);
7341 tinfo->ssi_stime = tswap64(info->ssi_stime);
7342 tinfo->ssi_addr = tswap64(info->ssi_addr);
7343}
7344
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007345static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007346{
7347 int i;
7348
7349 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7350 host_to_target_signalfd_siginfo(buf + i, buf + i);
7351 }
7352
7353 return len;
7354}
7355
7356static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007357 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007358};
7359
7360static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7361{
7362 int host_flags;
7363 target_sigset_t *target_mask;
7364 sigset_t host_mask;
7365 abi_long ret;
7366
7367 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7368 return -TARGET_EINVAL;
7369 }
7370 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7371 return -TARGET_EFAULT;
7372 }
7373
7374 target_to_host_sigset(&host_mask, target_mask);
7375
7376 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7377
7378 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7379 if (ret >= 0) {
7380 fd_trans_register(ret, &target_signalfd_trans);
7381 }
7382
7383 unlock_user_struct(target_mask, mask, 0);
7384
7385 return ret;
7386}
7387#endif
7388
pbrook1d9d8b52009-04-16 15:17:02 +00007389/* Map host to target signal numbers for the wait family of syscalls.
7390 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007391int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007392{
7393 if (WIFSIGNALED(status)) {
7394 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7395 }
7396 if (WIFSTOPPED(status)) {
7397 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7398 | (status & 0xff);
7399 }
7400 return status;
7401}
7402
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007403static int open_self_cmdline(void *cpu_env, int fd)
7404{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007405 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7406 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7407 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007408
Andreas Schwab58de8b92017-03-20 12:31:55 +01007409 for (i = 0; i < bprm->argc; i++) {
7410 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007411
Andreas Schwab58de8b92017-03-20 12:31:55 +01007412 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007413 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007414 }
7415 }
7416
Andreas Schwab58de8b92017-03-20 12:31:55 +01007417 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007418}
7419
Alexander Graf36c08d42011-11-02 20:23:24 +01007420static int open_self_maps(void *cpu_env, int fd)
7421{
Andreas Färber0429a972013-08-26 18:14:44 +02007422 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7423 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007424 FILE *fp;
7425 char *line = NULL;
7426 size_t len = 0;
7427 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007428
Alexander Graf1a49ef22012-05-01 16:30:28 +01007429 fp = fopen("/proc/self/maps", "r");
7430 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007431 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007432 }
7433
7434 while ((read = getline(&line, &len, fp)) != -1) {
7435 int fields, dev_maj, dev_min, inode;
7436 uint64_t min, max, offset;
7437 char flag_r, flag_w, flag_x, flag_p;
7438 char path[512] = "";
7439 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7440 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7441 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7442
7443 if ((fields < 10) || (fields > 11)) {
7444 continue;
7445 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007446 if (h2g_valid(min)) {
7447 int flags = page_get_flags(h2g(min));
7448 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
7449 if (page_check_range(h2g(min), max - min, flags) == -1) {
7450 continue;
7451 }
7452 if (h2g(min) == ts->info->stack_limit) {
7453 pstrcpy(path, sizeof(path), " [stack]");
7454 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007455 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007456 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007457 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007458 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007459 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007460 }
7461 }
7462
7463 free(line);
7464 fclose(fp);
7465
Alexander Graf36c08d42011-11-02 20:23:24 +01007466 return 0;
7467}
7468
Alexander Graf480b8e72011-11-02 20:23:25 +01007469static int open_self_stat(void *cpu_env, int fd)
7470{
Andreas Färber0429a972013-08-26 18:14:44 +02007471 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7472 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007473 abi_ulong start_stack = ts->info->start_stack;
7474 int i;
7475
7476 for (i = 0; i < 44; i++) {
7477 char buf[128];
7478 int len;
7479 uint64_t val = 0;
7480
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007481 if (i == 0) {
7482 /* pid */
7483 val = getpid();
7484 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7485 } else if (i == 1) {
7486 /* app name */
7487 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7488 } else if (i == 27) {
7489 /* stack bottom */
7490 val = start_stack;
7491 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7492 } else {
7493 /* for the rest, there is MasterCard */
7494 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007495 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007496
Alexander Graf480b8e72011-11-02 20:23:25 +01007497 len = strlen(buf);
7498 if (write(fd, buf, len) != len) {
7499 return -1;
7500 }
7501 }
7502
7503 return 0;
7504}
7505
Alexander Graf257450e2011-11-02 20:23:26 +01007506static int open_self_auxv(void *cpu_env, int fd)
7507{
Andreas Färber0429a972013-08-26 18:14:44 +02007508 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7509 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007510 abi_ulong auxv = ts->info->saved_auxv;
7511 abi_ulong len = ts->info->auxv_len;
7512 char *ptr;
7513
7514 /*
7515 * Auxiliary vector is stored in target process stack.
7516 * read in whole auxv vector and copy it to file
7517 */
7518 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7519 if (ptr != NULL) {
7520 while (len > 0) {
7521 ssize_t r;
7522 r = write(fd, ptr, len);
7523 if (r <= 0) {
7524 break;
7525 }
7526 len -= r;
7527 ptr += r;
7528 }
7529 lseek(fd, 0, SEEK_SET);
7530 unlock_user(ptr, auxv, len);
7531 }
7532
7533 return 0;
7534}
7535
Andreas Schwab463d8e72013-07-02 14:04:12 +01007536static int is_proc_myself(const char *filename, const char *entry)
7537{
7538 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7539 filename += strlen("/proc/");
7540 if (!strncmp(filename, "self/", strlen("self/"))) {
7541 filename += strlen("self/");
7542 } else if (*filename >= '1' && *filename <= '9') {
7543 char myself[80];
7544 snprintf(myself, sizeof(myself), "%d/", getpid());
7545 if (!strncmp(filename, myself, strlen(myself))) {
7546 filename += strlen(myself);
7547 } else {
7548 return 0;
7549 }
7550 } else {
7551 return 0;
7552 }
7553 if (!strcmp(filename, entry)) {
7554 return 1;
7555 }
7556 }
7557 return 0;
7558}
7559
Laurent Vivierde6b9932013-08-30 01:46:40 +02007560#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7561static int is_proc(const char *filename, const char *entry)
7562{
7563 return strcmp(filename, entry) == 0;
7564}
7565
7566static int open_net_route(void *cpu_env, int fd)
7567{
7568 FILE *fp;
7569 char *line = NULL;
7570 size_t len = 0;
7571 ssize_t read;
7572
7573 fp = fopen("/proc/net/route", "r");
7574 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007575 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007576 }
7577
7578 /* read header */
7579
7580 read = getline(&line, &len, fp);
7581 dprintf(fd, "%s", line);
7582
7583 /* read routes */
7584
7585 while ((read = getline(&line, &len, fp)) != -1) {
7586 char iface[16];
7587 uint32_t dest, gw, mask;
7588 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7589 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7590 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7591 &mask, &mtu, &window, &irtt);
7592 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7593 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7594 metric, tswap32(mask), mtu, window, irtt);
7595 }
7596
7597 free(line);
7598 fclose(fp);
7599
7600 return 0;
7601}
7602#endif
7603
Riku Voipio0b2effd2014-08-06 10:36:37 +03007604static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007605{
7606 struct fake_open {
7607 const char *filename;
7608 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007609 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007610 };
7611 const struct fake_open *fake_open;
7612 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007613 { "maps", open_self_maps, is_proc_myself },
7614 { "stat", open_self_stat, is_proc_myself },
7615 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007616 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007617#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7618 { "/proc/net/route", open_net_route, is_proc },
7619#endif
7620 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007621 };
7622
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007623 if (is_proc_myself(pathname, "exe")) {
7624 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007625 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007626 }
7627
Alexander Graf3be14d02011-11-02 20:23:23 +01007628 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007629 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007630 break;
7631 }
7632 }
7633
7634 if (fake_open->filename) {
7635 const char *tmpdir;
7636 char filename[PATH_MAX];
7637 int fd, r;
7638
7639 /* create temporary file to map stat to */
7640 tmpdir = getenv("TMPDIR");
7641 if (!tmpdir)
7642 tmpdir = "/tmp";
7643 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7644 fd = mkstemp(filename);
7645 if (fd < 0) {
7646 return fd;
7647 }
7648 unlink(filename);
7649
7650 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007651 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007652 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007653 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007654 return r;
7655 }
7656 lseek(fd, 0, SEEK_SET);
7657
7658 return fd;
7659 }
7660
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007661 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007662}
7663
Alexander Grafaecc8862014-11-10 21:33:03 +01007664#define TIMER_MAGIC 0x0caf0000
7665#define TIMER_MAGIC_MASK 0xffff0000
7666
7667/* Convert QEMU provided timer ID back to internal 16bit index format */
7668static target_timer_t get_timer_id(abi_long arg)
7669{
7670 target_timer_t timerid = arg;
7671
7672 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7673 return -TARGET_EINVAL;
7674 }
7675
7676 timerid &= 0xffff;
7677
7678 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7679 return -TARGET_EINVAL;
7680 }
7681
7682 return timerid;
7683}
7684
Laurent Vivier562a20b2017-03-01 10:37:48 +01007685static abi_long swap_data_eventfd(void *buf, size_t len)
7686{
7687 uint64_t *counter = buf;
7688 int i;
7689
7690 if (len < sizeof(uint64_t)) {
7691 return -EINVAL;
7692 }
7693
7694 for (i = 0; i < len; i += sizeof(uint64_t)) {
7695 *counter = tswap64(*counter);
7696 counter++;
7697 }
7698
7699 return len;
7700}
7701
7702static TargetFdTrans target_eventfd_trans = {
7703 .host_to_target_data = swap_data_eventfd,
7704 .target_to_host_data = swap_data_eventfd,
7705};
7706
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007707#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7708 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7709 defined(__NR_inotify_init1))
7710static abi_long host_to_target_data_inotify(void *buf, size_t len)
7711{
7712 struct inotify_event *ev;
7713 int i;
7714 uint32_t name_len;
7715
7716 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7717 ev = (struct inotify_event *)((char *)buf + i);
7718 name_len = ev->len;
7719
7720 ev->wd = tswap32(ev->wd);
7721 ev->mask = tswap32(ev->mask);
7722 ev->cookie = tswap32(ev->cookie);
7723 ev->len = tswap32(name_len);
7724 }
7725
7726 return len;
7727}
7728
7729static TargetFdTrans target_inotify_trans = {
7730 .host_to_target_data = host_to_target_data_inotify,
7731};
7732#endif
7733
Samuel Thibault2e0a8712018-01-09 21:16:43 +01007734static int target_to_host_cpu_mask(unsigned long *host_mask,
7735 size_t host_size,
7736 abi_ulong target_addr,
7737 size_t target_size)
7738{
7739 unsigned target_bits = sizeof(abi_ulong) * 8;
7740 unsigned host_bits = sizeof(*host_mask) * 8;
7741 abi_ulong *target_mask;
7742 unsigned i, j;
7743
7744 assert(host_size >= target_size);
7745
7746 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7747 if (!target_mask) {
7748 return -TARGET_EFAULT;
7749 }
7750 memset(host_mask, 0, host_size);
7751
7752 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7753 unsigned bit = i * target_bits;
7754 abi_ulong val;
7755
7756 __get_user(val, &target_mask[i]);
7757 for (j = 0; j < target_bits; j++, bit++) {
7758 if (val & (1UL << j)) {
7759 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7760 }
7761 }
7762 }
7763
7764 unlock_user(target_mask, target_addr, 0);
7765 return 0;
7766}
7767
7768static int host_to_target_cpu_mask(const unsigned long *host_mask,
7769 size_t host_size,
7770 abi_ulong target_addr,
7771 size_t target_size)
7772{
7773 unsigned target_bits = sizeof(abi_ulong) * 8;
7774 unsigned host_bits = sizeof(*host_mask) * 8;
7775 abi_ulong *target_mask;
7776 unsigned i, j;
7777
7778 assert(host_size >= target_size);
7779
7780 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7781 if (!target_mask) {
7782 return -TARGET_EFAULT;
7783 }
7784
7785 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7786 unsigned bit = i * target_bits;
7787 abi_ulong val = 0;
7788
7789 for (j = 0; j < target_bits; j++, bit++) {
7790 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7791 val |= 1UL << j;
7792 }
7793 }
7794 __put_user(val, &target_mask[i]);
7795 }
7796
7797 unlock_user(target_mask, target_addr, target_size);
7798 return 0;
7799}
7800
ths0da46a62007-10-20 20:23:07 +00007801/* do_syscall() should always have a single exit point at the end so
7802 that actions, such as logging of syscall results, can be performed.
7803 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007804abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7805 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007806 abi_long arg5, abi_long arg6, abi_long arg7,
7807 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007808{
Andreas Färber182735e2013-05-29 22:29:20 +02007809 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007810 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007811 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007812 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007813 void *p;
ths3b46e622007-09-17 08:09:54 +00007814
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007815#if defined(DEBUG_ERESTARTSYS)
7816 /* Debug-only code for exercising the syscall-restart code paths
7817 * in the per-architecture cpu main loops: restart every syscall
7818 * the guest makes once before letting it through.
7819 */
7820 {
7821 static int flag;
7822
7823 flag = !flag;
7824 if (flag) {
7825 return -TARGET_ERESTARTSYS;
7826 }
7827 }
7828#endif
7829
bellard72f03902003-02-18 23:33:18 +00007830#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007831 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007832#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007833 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007834 if(do_strace)
7835 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7836
bellard31e31b82003-02-18 22:55:36 +00007837 switch(num) {
7838 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007839 /* In old applications this may be used to implement _exit(2).
7840 However in threaded applictions it is used for thread termination,
7841 and _exit_group is used for application termination.
7842 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007843
7844 if (block_signals()) {
7845 ret = -TARGET_ERESTARTSYS;
7846 break;
7847 }
7848
Alex Bennéedd1f6342016-09-30 22:31:01 +01007849 cpu_list_lock();
7850
Andreas Färberbdc44642013-06-24 23:50:24 +02007851 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007852 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007853
Andreas Färber9b056fc2013-06-24 23:53:10 +02007854 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007855 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007856
Andreas Färber9b056fc2013-06-24 23:53:10 +02007857 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007858
Andreas Färber0429a972013-08-26 18:14:44 +02007859 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007860 if (ts->child_tidptr) {
7861 put_user_u32(0, ts->child_tidptr);
7862 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7863 NULL, NULL, 0);
7864 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007865 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007866 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007867 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007868 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007869 pthread_exit(NULL);
7870 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007871
7872 cpu_list_unlock();
Juan Quintela9788c9c2009-07-27 16:13:02 +02007873#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007874 _mcleanup();
7875#endif
bellarde9009672005-04-26 20:42:36 +00007876 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007877 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007878 ret = 0; /* avoid warning */
7879 break;
7880 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007881 if (arg3 == 0)
7882 ret = 0;
7883 else {
7884 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7885 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007886 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007887 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007888 fd_trans_host_to_target_data(arg1)) {
7889 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007890 }
aurel3238d840e2009-01-30 19:48:17 +00007891 unlock_user(p, arg2, ret);
7892 }
bellard31e31b82003-02-18 22:55:36 +00007893 break;
7894 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007895 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7896 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01007897 if (fd_trans_target_to_host_data(arg1)) {
7898 void *copy = g_malloc(arg3);
7899 memcpy(copy, p, arg3);
7900 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
7901 if (ret >= 0) {
7902 ret = get_errno(safe_write(arg1, copy, ret));
7903 }
7904 g_free(copy);
7905 } else {
7906 ret = get_errno(safe_write(arg1, p, arg3));
7907 }
pbrook53a59602006-03-25 19:31:22 +00007908 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007909 break;
Chen Gang704eff62015-08-21 05:37:33 +08007910#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007911 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007912 if (!(p = lock_user_string(arg1)))
7913 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007914 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7915 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7916 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007917 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007918 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007919 break;
Chen Gang704eff62015-08-21 05:37:33 +08007920#endif
ths82424832007-09-24 09:21:55 +00007921 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007922 if (!(p = lock_user_string(arg2)))
7923 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007924 ret = get_errno(do_openat(cpu_env, arg1, p,
7925 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7926 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007927 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007928 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007929 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007930#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7931 case TARGET_NR_name_to_handle_at:
7932 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7933 break;
7934#endif
7935#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7936 case TARGET_NR_open_by_handle_at:
7937 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007938 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007939 break;
7940#endif
bellard31e31b82003-02-18 22:55:36 +00007941 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007942 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007943 ret = get_errno(close(arg1));
7944 break;
7945 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007946 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007947 break;
Chen Gang704eff62015-08-21 05:37:33 +08007948#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007949 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01007950 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007951 break;
Chen Gang704eff62015-08-21 05:37:33 +08007952#endif
thse5febef2007-04-01 18:31:35 +00007953#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007954 case TARGET_NR_waitpid:
7955 {
pbrook53a59602006-03-25 19:31:22 +00007956 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007957 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007958 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007959 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007960 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007961 }
7962 break;
thse5febef2007-04-01 18:31:35 +00007963#endif
pbrookf0cbb612008-05-30 18:20:05 +00007964#ifdef TARGET_NR_waitid
7965 case TARGET_NR_waitid:
7966 {
7967 siginfo_t info;
7968 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007969 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007970 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007971 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00007972 goto efault;
7973 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007974 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007975 }
7976 }
7977 break;
7978#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007979#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007980 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007981 if (!(p = lock_user_string(arg1)))
7982 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007983 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007984 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007985 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007986 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007987#endif
Chen Gang704eff62015-08-21 05:37:33 +08007988#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007989 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007990 {
7991 void * p2;
7992 p = lock_user_string(arg1);
7993 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007994 if (!p || !p2)
7995 ret = -TARGET_EFAULT;
7996 else
7997 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007998 unlock_user(p2, arg2, 0);
7999 unlock_user(p, arg1, 0);
8000 }
bellard31e31b82003-02-18 22:55:36 +00008001 break;
Chen Gang704eff62015-08-21 05:37:33 +08008002#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008003#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008004 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008005 {
8006 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008007 if (!arg2 || !arg4)
8008 goto efault;
ths64f0ce42007-09-24 09:25:06 +00008009 p = lock_user_string(arg2);
8010 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008011 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008012 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008013 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008014 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008015 unlock_user(p, arg2, 0);
8016 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008017 }
8018 break;
8019#endif
Chen Gang704eff62015-08-21 05:37:33 +08008020#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008021 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008022 if (!(p = lock_user_string(arg1)))
8023 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008024 ret = get_errno(unlink(p));
8025 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008026 break;
Chen Gang704eff62015-08-21 05:37:33 +08008027#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008028#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008029 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008030 if (!(p = lock_user_string(arg2)))
8031 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008032 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008033 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00008034 break;
balrogb7d35e62007-12-12 00:40:24 +00008035#endif
bellard31e31b82003-02-18 22:55:36 +00008036 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008037 {
8038 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008039 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008040 abi_ulong gp;
8041 abi_ulong guest_argp;
8042 abi_ulong guest_envp;
8043 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008044 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008045 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008046
bellardf7341ff2003-03-30 21:00:25 +00008047 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008048 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008049 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008050 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008051 goto efault;
ths03aa1972007-12-02 06:28:08 +00008052 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008053 break;
bellard7854b052003-03-29 17:22:23 +00008054 argc++;
bellard2f619692007-11-16 10:46:05 +00008055 }
bellardf7341ff2003-03-30 21:00:25 +00008056 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008057 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008058 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008059 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008060 goto efault;
ths03aa1972007-12-02 06:28:08 +00008061 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008062 break;
bellard7854b052003-03-29 17:22:23 +00008063 envc++;
bellard2f619692007-11-16 10:46:05 +00008064 }
bellard7854b052003-03-29 17:22:23 +00008065
Prasad J Panditb936cb52017-03-07 12:51:47 +05308066 argp = g_new0(char *, argc + 1);
8067 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008068
pbrookda94d262008-05-30 18:24:00 +00008069 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008070 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008071 if (get_user_ual(addr, gp))
8072 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008073 if (!addr)
8074 break;
bellard2f619692007-11-16 10:46:05 +00008075 if (!(*q = lock_user_string(addr)))
8076 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008077 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008078 }
bellardf7341ff2003-03-30 21:00:25 +00008079 *q = NULL;
8080
pbrookda94d262008-05-30 18:24:00 +00008081 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008082 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008083 if (get_user_ual(addr, gp))
8084 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008085 if (!addr)
8086 break;
bellard2f619692007-11-16 10:46:05 +00008087 if (!(*q = lock_user_string(addr)))
8088 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008089 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008090 }
bellardf7341ff2003-03-30 21:00:25 +00008091 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008092
bellard2f619692007-11-16 10:46:05 +00008093 if (!(p = lock_user_string(arg1)))
8094 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008095 /* Although execve() is not an interruptible syscall it is
8096 * a special case where we must use the safe_syscall wrapper:
8097 * if we allow a signal to happen before we make the host
8098 * syscall then we will 'lose' it, because at the point of
8099 * execve the process leaves QEMU's control. So we use the
8100 * safe syscall wrapper to ensure that we either take the
8101 * signal as a guest signal, or else it does not happen
8102 * before the execve completes and makes it the other
8103 * program's problem.
8104 */
8105 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008106 unlock_user(p, arg1, 0);
8107
bellard2f619692007-11-16 10:46:05 +00008108 goto execve_end;
8109
8110 execve_efault:
8111 ret = -TARGET_EFAULT;
8112
8113 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008114 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008115 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008116 if (get_user_ual(addr, gp)
8117 || !addr)
8118 break;
pbrook53a59602006-03-25 19:31:22 +00008119 unlock_user(*q, addr, 0);
8120 }
8121 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008122 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008123 if (get_user_ual(addr, gp)
8124 || !addr)
8125 break;
pbrook53a59602006-03-25 19:31:22 +00008126 unlock_user(*q, addr, 0);
8127 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308128
8129 g_free(argp);
8130 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008131 }
bellard31e31b82003-02-18 22:55:36 +00008132 break;
8133 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008134 if (!(p = lock_user_string(arg1)))
8135 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008136 ret = get_errno(chdir(p));
8137 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008138 break;
bellarda315a142005-01-30 22:59:18 +00008139#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008140 case TARGET_NR_time:
8141 {
pbrook53a59602006-03-25 19:31:22 +00008142 time_t host_time;
8143 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008144 if (!is_error(ret)
8145 && arg1
8146 && put_user_sal(host_time, arg1))
8147 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008148 }
8149 break;
bellarda315a142005-01-30 22:59:18 +00008150#endif
Chen Gang704eff62015-08-21 05:37:33 +08008151#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008152 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008153 if (!(p = lock_user_string(arg1)))
8154 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008155 ret = get_errno(mknod(p, arg2, arg3));
8156 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008157 break;
Chen Gang704eff62015-08-21 05:37:33 +08008158#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008159#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008160 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008161 if (!(p = lock_user_string(arg2)))
8162 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008163 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008164 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008165 break;
8166#endif
Chen Gang704eff62015-08-21 05:37:33 +08008167#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008168 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008169 if (!(p = lock_user_string(arg1)))
8170 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008171 ret = get_errno(chmod(p, arg2));
8172 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008173 break;
Chen Gang704eff62015-08-21 05:37:33 +08008174#endif
bellardebc05482003-09-30 21:08:41 +00008175#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008176 case TARGET_NR_break:
8177 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008178#endif
8179#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008180 case TARGET_NR_oldstat:
8181 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008182#endif
bellard31e31b82003-02-18 22:55:36 +00008183 case TARGET_NR_lseek:
8184 ret = get_errno(lseek(arg1, arg2, arg3));
8185 break;
Richard Henderson92317332010-05-03 10:07:53 -07008186#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8187 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008188 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008189 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008190 ret = get_errno(getpid());
8191 break;
Richard Henderson92317332010-05-03 10:07:53 -07008192#endif
8193#ifdef TARGET_NR_getpid
8194 case TARGET_NR_getpid:
8195 ret = get_errno(getpid());
8196 break;
8197#endif
bellard31e31b82003-02-18 22:55:36 +00008198 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008199 {
8200 /* need to look at the data field */
8201 void *p2, *p3;
8202
8203 if (arg1) {
8204 p = lock_user_string(arg1);
8205 if (!p) {
8206 goto efault;
8207 }
8208 } else {
8209 p = NULL;
8210 }
8211
8212 p2 = lock_user_string(arg2);
8213 if (!p2) {
8214 if (arg1) {
8215 unlock_user(p, arg1, 0);
8216 }
8217 goto efault;
8218 }
8219
8220 if (arg3) {
8221 p3 = lock_user_string(arg3);
8222 if (!p3) {
8223 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008224 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008225 }
8226 unlock_user(p2, arg2, 0);
8227 goto efault;
8228 }
8229 } else {
8230 p3 = NULL;
8231 }
8232
8233 /* FIXME - arg5 should be locked, but it isn't clear how to
8234 * do that since it's not guaranteed to be a NULL-terminated
8235 * string.
8236 */
8237 if (!arg5) {
8238 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8239 } else {
8240 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8241 }
8242 ret = get_errno(ret);
8243
8244 if (arg1) {
8245 unlock_user(p, arg1, 0);
8246 }
8247 unlock_user(p2, arg2, 0);
8248 if (arg3) {
8249 unlock_user(p3, arg3, 0);
8250 }
8251 }
8252 break;
thse5febef2007-04-01 18:31:35 +00008253#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008254 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008255 if (!(p = lock_user_string(arg1)))
8256 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008257 ret = get_errno(umount(p));
8258 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008259 break;
thse5febef2007-04-01 18:31:35 +00008260#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008261#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008262 case TARGET_NR_stime:
8263 {
pbrook53a59602006-03-25 19:31:22 +00008264 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008265 if (get_user_sal(host_time, arg1))
8266 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008267 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008268 }
8269 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008270#endif
bellard31e31b82003-02-18 22:55:36 +00008271 case TARGET_NR_ptrace:
8272 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008273#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008274 case TARGET_NR_alarm:
8275 ret = alarm(arg1);
8276 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008277#endif
bellardebc05482003-09-30 21:08:41 +00008278#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008279 case TARGET_NR_oldfstat:
8280 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008281#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008282#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008283 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008284 if (!block_signals()) {
8285 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8286 }
8287 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008288 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008289#endif
thse5febef2007-04-01 18:31:35 +00008290#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008291 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008292 {
pbrook53a59602006-03-25 19:31:22 +00008293 struct utimbuf tbuf, *host_tbuf;
8294 struct target_utimbuf *target_tbuf;
8295 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008296 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8297 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008298 tbuf.actime = tswapal(target_tbuf->actime);
8299 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008300 unlock_user_struct(target_tbuf, arg2, 0);
8301 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008302 } else {
pbrook53a59602006-03-25 19:31:22 +00008303 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008304 }
bellard579a97f2007-11-11 14:26:47 +00008305 if (!(p = lock_user_string(arg1)))
8306 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008307 ret = get_errno(utime(p, host_tbuf));
8308 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008309 }
8310 break;
thse5febef2007-04-01 18:31:35 +00008311#endif
Chen Gang704eff62015-08-21 05:37:33 +08008312#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008313 case TARGET_NR_utimes:
8314 {
bellard978a66f2004-12-06 22:58:05 +00008315 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008316 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008317 if (copy_from_user_timeval(&tv[0], arg2)
8318 || copy_from_user_timeval(&tv[1],
8319 arg2 + sizeof(struct target_timeval)))
8320 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008321 tvp = tv;
8322 } else {
8323 tvp = NULL;
8324 }
bellard579a97f2007-11-11 14:26:47 +00008325 if (!(p = lock_user_string(arg1)))
8326 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008327 ret = get_errno(utimes(p, tvp));
8328 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008329 }
8330 break;
Chen Gang704eff62015-08-21 05:37:33 +08008331#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008332#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008333 case TARGET_NR_futimesat:
8334 {
8335 struct timeval *tvp, tv[2];
8336 if (arg3) {
8337 if (copy_from_user_timeval(&tv[0], arg3)
8338 || copy_from_user_timeval(&tv[1],
8339 arg3 + sizeof(struct target_timeval)))
8340 goto efault;
8341 tvp = tv;
8342 } else {
8343 tvp = NULL;
8344 }
8345 if (!(p = lock_user_string(arg2)))
8346 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008347 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008348 unlock_user(p, arg2, 0);
8349 }
8350 break;
8351#endif
bellardebc05482003-09-30 21:08:41 +00008352#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008353 case TARGET_NR_stty:
8354 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008355#endif
8356#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008357 case TARGET_NR_gtty:
8358 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008359#endif
Chen Gang704eff62015-08-21 05:37:33 +08008360#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008361 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008362 if (!(p = lock_user_string(arg1)))
8363 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008364 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008365 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008366 break;
Chen Gang704eff62015-08-21 05:37:33 +08008367#endif
ths92a34c12007-09-24 09:27:49 +00008368#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8369 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008370 if (!(p = lock_user_string(arg2)))
8371 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008372 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008373 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008374 break;
8375#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008376#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008377 case TARGET_NR_nice:
8378 ret = get_errno(nice(arg1));
8379 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008380#endif
bellardebc05482003-09-30 21:08:41 +00008381#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008382 case TARGET_NR_ftime:
8383 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008384#endif
bellard31e31b82003-02-18 22:55:36 +00008385 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008386 sync();
8387 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008388 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008389#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8390 case TARGET_NR_syncfs:
8391 ret = get_errno(syncfs(arg1));
8392 break;
8393#endif
bellard31e31b82003-02-18 22:55:36 +00008394 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008395 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008396 break;
Chen Gang704eff62015-08-21 05:37:33 +08008397#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008398 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008399 {
8400 void *p2;
8401 p = lock_user_string(arg1);
8402 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008403 if (!p || !p2)
8404 ret = -TARGET_EFAULT;
8405 else
8406 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008407 unlock_user(p2, arg2, 0);
8408 unlock_user(p, arg1, 0);
8409 }
bellard31e31b82003-02-18 22:55:36 +00008410 break;
Chen Gang704eff62015-08-21 05:37:33 +08008411#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008412#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008413 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008414 {
bellard579a97f2007-11-11 14:26:47 +00008415 void *p2;
ths722183f2007-09-24 09:24:37 +00008416 p = lock_user_string(arg2);
8417 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008418 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008419 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008420 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008421 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008422 unlock_user(p2, arg4, 0);
8423 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008424 }
8425 break;
8426#endif
Chen Gang704eff62015-08-21 05:37:33 +08008427#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008428 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008429 if (!(p = lock_user_string(arg1)))
8430 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008431 ret = get_errno(mkdir(p, arg2));
8432 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008433 break;
Chen Gang704eff62015-08-21 05:37:33 +08008434#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008435#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008436 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008437 if (!(p = lock_user_string(arg2)))
8438 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008439 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008440 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008441 break;
8442#endif
Chen Gang704eff62015-08-21 05:37:33 +08008443#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008444 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008445 if (!(p = lock_user_string(arg1)))
8446 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008447 ret = get_errno(rmdir(p));
8448 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008449 break;
Chen Gang704eff62015-08-21 05:37:33 +08008450#endif
bellard31e31b82003-02-18 22:55:36 +00008451 case TARGET_NR_dup:
8452 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008453 if (ret >= 0) {
8454 fd_trans_dup(arg1, ret);
8455 }
bellard31e31b82003-02-18 22:55:36 +00008456 break;
Chen Gang704eff62015-08-21 05:37:33 +08008457#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008458 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008459 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008460 break;
Chen Gang704eff62015-08-21 05:37:33 +08008461#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008462#ifdef TARGET_NR_pipe2
8463 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008464 ret = do_pipe(cpu_env, arg1,
8465 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008466 break;
8467#endif
bellard31e31b82003-02-18 22:55:36 +00008468 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008469 {
pbrook53a59602006-03-25 19:31:22 +00008470 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008471 struct tms tms;
8472 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008473 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008474 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8475 if (!tmsp)
8476 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008477 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8478 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8479 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8480 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008481 }
bellardc596ed12003-07-13 17:32:31 +00008482 if (!is_error(ret))
8483 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008484 }
8485 break;
bellardebc05482003-09-30 21:08:41 +00008486#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008487 case TARGET_NR_prof:
8488 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008489#endif
thse5febef2007-04-01 18:31:35 +00008490#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008491 case TARGET_NR_signal:
8492 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008493#endif
bellard31e31b82003-02-18 22:55:36 +00008494 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008495 if (arg1 == 0) {
8496 ret = get_errno(acct(NULL));
8497 } else {
8498 if (!(p = lock_user_string(arg1)))
8499 goto efault;
8500 ret = get_errno(acct(path(p)));
8501 unlock_user(p, arg1, 0);
8502 }
pbrook24836682006-04-16 14:14:53 +00008503 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008504#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008505 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008506 if (!(p = lock_user_string(arg1)))
8507 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008508 ret = get_errno(umount2(p, arg2));
8509 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008510 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008511#endif
bellardebc05482003-09-30 21:08:41 +00008512#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008513 case TARGET_NR_lock:
8514 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008515#endif
bellard31e31b82003-02-18 22:55:36 +00008516 case TARGET_NR_ioctl:
8517 ret = do_ioctl(arg1, arg2, arg3);
8518 break;
8519 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008520 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008521 break;
bellardebc05482003-09-30 21:08:41 +00008522#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008523 case TARGET_NR_mpx:
8524 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008525#endif
bellard31e31b82003-02-18 22:55:36 +00008526 case TARGET_NR_setpgid:
8527 ret = get_errno(setpgid(arg1, arg2));
8528 break;
bellardebc05482003-09-30 21:08:41 +00008529#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008530 case TARGET_NR_ulimit:
8531 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008532#endif
8533#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008534 case TARGET_NR_oldolduname:
8535 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008536#endif
bellard31e31b82003-02-18 22:55:36 +00008537 case TARGET_NR_umask:
8538 ret = get_errno(umask(arg1));
8539 break;
8540 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008541 if (!(p = lock_user_string(arg1)))
8542 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008543 ret = get_errno(chroot(p));
8544 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008545 break;
Chen Gang704eff62015-08-21 05:37:33 +08008546#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008547 case TARGET_NR_ustat:
8548 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008549#endif
8550#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008551 case TARGET_NR_dup2:
8552 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008553 if (ret >= 0) {
8554 fd_trans_dup(arg1, arg2);
8555 }
bellard31e31b82003-02-18 22:55:36 +00008556 break;
Chen Gang704eff62015-08-21 05:37:33 +08008557#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008558#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8559 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008560 {
8561 int host_flags;
8562
8563 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8564 return -EINVAL;
8565 }
8566 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8567 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008568 if (ret >= 0) {
8569 fd_trans_dup(arg1, arg2);
8570 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008571 break;
Peter Maydell10fa9932017-12-15 15:18:00 +00008572 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008573#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008574#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008575 case TARGET_NR_getppid:
8576 ret = get_errno(getppid());
8577 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008578#endif
Chen Gang704eff62015-08-21 05:37:33 +08008579#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008580 case TARGET_NR_getpgrp:
8581 ret = get_errno(getpgrp());
8582 break;
Chen Gang704eff62015-08-21 05:37:33 +08008583#endif
bellard31e31b82003-02-18 22:55:36 +00008584 case TARGET_NR_setsid:
8585 ret = get_errno(setsid());
8586 break;
thse5febef2007-04-01 18:31:35 +00008587#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008588 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008589 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008590#if defined(TARGET_ALPHA)
8591 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008592 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008593 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008594 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8595 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008596 act._sa_handler = old_act->_sa_handler;
8597 target_siginitset(&act.sa_mask, old_act->sa_mask);
8598 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008599 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008600 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008601 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008602 }
8603 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008604 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008605 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8606 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008607 old_act->_sa_handler = oact._sa_handler;
8608 old_act->sa_mask = oact.sa_mask.sig[0];
8609 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008610 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008611 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008612#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008613 struct target_sigaction act, oact, *pact, *old_act;
8614
8615 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008616 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8617 goto efault;
bellard106ec872006-06-27 21:08:10 +00008618 act._sa_handler = old_act->_sa_handler;
8619 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8620 act.sa_flags = old_act->sa_flags;
8621 unlock_user_struct(old_act, arg2, 0);
8622 pact = &act;
8623 } else {
8624 pact = NULL;
8625 }
8626
8627 ret = get_errno(do_sigaction(arg1, pact, &oact));
8628
8629 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008630 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8631 goto efault;
bellard106ec872006-06-27 21:08:10 +00008632 old_act->_sa_handler = oact._sa_handler;
8633 old_act->sa_flags = oact.sa_flags;
8634 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8635 old_act->sa_mask.sig[1] = 0;
8636 old_act->sa_mask.sig[2] = 0;
8637 old_act->sa_mask.sig[3] = 0;
8638 unlock_user_struct(old_act, arg3, 1);
8639 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008640#else
8641 struct target_old_sigaction *old_act;
8642 struct target_sigaction act, oact, *pact;
8643 if (arg2) {
8644 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8645 goto efault;
8646 act._sa_handler = old_act->_sa_handler;
8647 target_siginitset(&act.sa_mask, old_act->sa_mask);
8648 act.sa_flags = old_act->sa_flags;
8649 act.sa_restorer = old_act->sa_restorer;
8650 unlock_user_struct(old_act, arg2, 0);
8651 pact = &act;
8652 } else {
8653 pact = NULL;
8654 }
8655 ret = get_errno(do_sigaction(arg1, pact, &oact));
8656 if (!is_error(ret) && arg3) {
8657 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8658 goto efault;
8659 old_act->_sa_handler = oact._sa_handler;
8660 old_act->sa_mask = oact.sa_mask.sig[0];
8661 old_act->sa_flags = oact.sa_flags;
8662 old_act->sa_restorer = oact.sa_restorer;
8663 unlock_user_struct(old_act, arg3, 1);
8664 }
ths388bb212007-05-13 13:58:00 +00008665#endif
bellard31e31b82003-02-18 22:55:36 +00008666 }
8667 break;
thse5febef2007-04-01 18:31:35 +00008668#endif
bellard66fb9762003-03-23 01:06:05 +00008669 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008670 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008671#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008672 /* For Alpha and SPARC this is a 5 argument syscall, with
8673 * a 'restorer' parameter which must be copied into the
8674 * sa_restorer field of the sigaction struct.
8675 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8676 * and arg5 is the sigsetsize.
8677 * Alpha also has a separate rt_sigaction struct that it uses
8678 * here; SPARC uses the usual sigaction struct.
8679 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008680 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008681 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008682
8683 if (arg4 != sizeof(target_sigset_t)) {
8684 ret = -TARGET_EINVAL;
8685 break;
8686 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008687 if (arg2) {
8688 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8689 goto efault;
8690 act._sa_handler = rt_act->_sa_handler;
8691 act.sa_mask = rt_act->sa_mask;
8692 act.sa_flags = rt_act->sa_flags;
8693 act.sa_restorer = arg5;
8694 unlock_user_struct(rt_act, arg2, 0);
8695 pact = &act;
8696 }
8697 ret = get_errno(do_sigaction(arg1, pact, &oact));
8698 if (!is_error(ret) && arg3) {
8699 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8700 goto efault;
8701 rt_act->_sa_handler = oact._sa_handler;
8702 rt_act->sa_mask = oact.sa_mask;
8703 rt_act->sa_flags = oact.sa_flags;
8704 unlock_user_struct(rt_act, arg3, 1);
8705 }
8706#else
Peter Maydell78bfef72017-11-06 18:33:26 +00008707#ifdef TARGET_SPARC
8708 target_ulong restorer = arg4;
8709 target_ulong sigsetsize = arg5;
8710#else
8711 target_ulong sigsetsize = arg4;
8712#endif
pbrook53a59602006-03-25 19:31:22 +00008713 struct target_sigaction *act;
8714 struct target_sigaction *oact;
8715
Peter Maydell78bfef72017-11-06 18:33:26 +00008716 if (sigsetsize != sizeof(target_sigset_t)) {
Peter Maydellc8157012016-06-30 14:23:24 +01008717 ret = -TARGET_EINVAL;
8718 break;
8719 }
bellard579a97f2007-11-11 14:26:47 +00008720 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00008721 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
bellard579a97f2007-11-11 14:26:47 +00008722 goto efault;
Peter Maydell78bfef72017-11-06 18:33:26 +00008723 }
8724#ifdef TARGET_SPARC
8725 act->sa_restorer = restorer;
8726#endif
8727 } else {
pbrook53a59602006-03-25 19:31:22 +00008728 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00008729 }
bellard579a97f2007-11-11 14:26:47 +00008730 if (arg3) {
8731 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8732 ret = -TARGET_EFAULT;
8733 goto rt_sigaction_fail;
8734 }
8735 } else
pbrook53a59602006-03-25 19:31:22 +00008736 oact = NULL;
8737 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008738 rt_sigaction_fail:
8739 if (act)
pbrook53a59602006-03-25 19:31:22 +00008740 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008741 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008742 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008743#endif
pbrook53a59602006-03-25 19:31:22 +00008744 }
bellard66fb9762003-03-23 01:06:05 +00008745 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008746#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008747 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008748 {
8749 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008750 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008751 ret = do_sigprocmask(0, NULL, &cur_set);
8752 if (!ret) {
8753 host_to_target_old_sigset(&target_set, &cur_set);
8754 ret = target_set;
8755 }
bellard66fb9762003-03-23 01:06:05 +00008756 }
8757 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008758#endif
8759#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008760 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008761 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02008762 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00008763 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00008764 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008765 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8766 if (!ret) {
8767 host_to_target_old_sigset(&target_set, &oset);
8768 ret = target_set;
8769 }
bellard66fb9762003-03-23 01:06:05 +00008770 }
8771 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008772#endif
thse5febef2007-04-01 18:31:35 +00008773#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008774 case TARGET_NR_sigprocmask:
8775 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008776#if defined(TARGET_ALPHA)
8777 sigset_t set, oldset;
8778 abi_ulong mask;
8779 int how;
8780
8781 switch (arg1) {
8782 case TARGET_SIG_BLOCK:
8783 how = SIG_BLOCK;
8784 break;
8785 case TARGET_SIG_UNBLOCK:
8786 how = SIG_UNBLOCK;
8787 break;
8788 case TARGET_SIG_SETMASK:
8789 how = SIG_SETMASK;
8790 break;
8791 default:
8792 ret = -TARGET_EINVAL;
8793 goto fail;
8794 }
8795 mask = arg2;
8796 target_to_host_old_sigset(&set, &mask);
8797
Peter Maydell3d3efba2016-05-27 15:51:49 +01008798 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008799 if (!is_error(ret)) {
8800 host_to_target_old_sigset(&mask, &oldset);
8801 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008802 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008803 }
8804#else
bellard66fb9762003-03-23 01:06:05 +00008805 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008806 int how;
ths3b46e622007-09-17 08:09:54 +00008807
pbrook53a59602006-03-25 19:31:22 +00008808 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008809 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008810 case TARGET_SIG_BLOCK:
8811 how = SIG_BLOCK;
8812 break;
8813 case TARGET_SIG_UNBLOCK:
8814 how = SIG_UNBLOCK;
8815 break;
8816 case TARGET_SIG_SETMASK:
8817 how = SIG_SETMASK;
8818 break;
8819 default:
ths0da46a62007-10-20 20:23:07 +00008820 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008821 goto fail;
8822 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008823 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008824 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008825 target_to_host_old_sigset(&set, p);
8826 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008827 set_ptr = &set;
8828 } else {
8829 how = 0;
8830 set_ptr = NULL;
8831 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008832 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008833 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008834 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008835 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008836 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008837 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008838 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008839#endif
bellard66fb9762003-03-23 01:06:05 +00008840 }
8841 break;
thse5febef2007-04-01 18:31:35 +00008842#endif
bellard66fb9762003-03-23 01:06:05 +00008843 case TARGET_NR_rt_sigprocmask:
8844 {
8845 int how = arg1;
8846 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008847
Peter Maydellc8157012016-06-30 14:23:24 +01008848 if (arg4 != sizeof(target_sigset_t)) {
8849 ret = -TARGET_EINVAL;
8850 break;
8851 }
8852
pbrook53a59602006-03-25 19:31:22 +00008853 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008854 switch(how) {
8855 case TARGET_SIG_BLOCK:
8856 how = SIG_BLOCK;
8857 break;
8858 case TARGET_SIG_UNBLOCK:
8859 how = SIG_UNBLOCK;
8860 break;
8861 case TARGET_SIG_SETMASK:
8862 how = SIG_SETMASK;
8863 break;
8864 default:
ths0da46a62007-10-20 20:23:07 +00008865 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008866 goto fail;
8867 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008868 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008869 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008870 target_to_host_sigset(&set, p);
8871 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008872 set_ptr = &set;
8873 } else {
8874 how = 0;
8875 set_ptr = NULL;
8876 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008877 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008878 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008879 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008880 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008881 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008882 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008883 }
8884 }
8885 break;
thse5febef2007-04-01 18:31:35 +00008886#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008887 case TARGET_NR_sigpending:
8888 {
8889 sigset_t set;
8890 ret = get_errno(sigpending(&set));
8891 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008892 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008893 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008894 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008895 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008896 }
8897 }
8898 break;
thse5febef2007-04-01 18:31:35 +00008899#endif
bellard66fb9762003-03-23 01:06:05 +00008900 case TARGET_NR_rt_sigpending:
8901 {
8902 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008903
8904 /* Yes, this check is >, not != like most. We follow the kernel's
8905 * logic and it does it like this because it implements
8906 * NR_sigpending through the same code path, and in that case
8907 * the old_sigset_t is smaller in size.
8908 */
8909 if (arg2 > sizeof(target_sigset_t)) {
8910 ret = -TARGET_EINVAL;
8911 break;
8912 }
8913
bellard66fb9762003-03-23 01:06:05 +00008914 ret = get_errno(sigpending(&set));
8915 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008916 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008917 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008918 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008919 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008920 }
8921 }
8922 break;
thse5febef2007-04-01 18:31:35 +00008923#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008924 case TARGET_NR_sigsuspend:
8925 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008926 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008927#if defined(TARGET_ALPHA)
8928 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008929 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008930#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008931 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008932 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008933 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008934 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008935#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008936 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8937 SIGSET_T_SIZE));
8938 if (ret != -TARGET_ERESTARTSYS) {
8939 ts->in_sigsuspend = 1;
8940 }
bellard66fb9762003-03-23 01:06:05 +00008941 }
8942 break;
thse5febef2007-04-01 18:31:35 +00008943#endif
bellard66fb9762003-03-23 01:06:05 +00008944 case TARGET_NR_rt_sigsuspend:
8945 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008946 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008947
8948 if (arg2 != sizeof(target_sigset_t)) {
8949 ret = -TARGET_EINVAL;
8950 break;
8951 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008952 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008953 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008954 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008955 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008956 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8957 SIGSET_T_SIZE));
8958 if (ret != -TARGET_ERESTARTSYS) {
8959 ts->in_sigsuspend = 1;
8960 }
bellard66fb9762003-03-23 01:06:05 +00008961 }
8962 break;
8963 case TARGET_NR_rt_sigtimedwait:
8964 {
bellard66fb9762003-03-23 01:06:05 +00008965 sigset_t set;
8966 struct timespec uts, *puts;
8967 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008968
Peter Maydellc8157012016-06-30 14:23:24 +01008969 if (arg4 != sizeof(target_sigset_t)) {
8970 ret = -TARGET_EINVAL;
8971 break;
8972 }
8973
Anthony Liguoric227f092009-10-01 16:12:16 -05008974 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008975 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008976 target_to_host_sigset(&set, p);
8977 unlock_user(p, arg1, 0);
8978 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008979 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008980 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008981 } else {
8982 puts = NULL;
8983 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008984 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8985 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008986 if (!is_error(ret)) {
8987 if (arg2) {
8988 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8989 0);
8990 if (!p) {
8991 goto efault;
8992 }
8993 host_to_target_siginfo(p, &uinfo);
8994 unlock_user(p, arg2, sizeof(target_siginfo_t));
8995 }
8996 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008997 }
8998 }
8999 break;
9000 case TARGET_NR_rt_sigqueueinfo:
9001 {
9002 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009003
9004 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9005 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00009006 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01009007 }
pbrook53a59602006-03-25 19:31:22 +00009008 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009009 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009010 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9011 }
9012 break;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009013 case TARGET_NR_rt_tgsigqueueinfo:
9014 {
9015 siginfo_t uinfo;
9016
9017 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9018 if (!p) {
9019 goto efault;
9020 }
9021 target_to_host_siginfo(&uinfo, p);
9022 unlock_user(p, arg4, 0);
9023 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9024 }
9025 break;
thse5febef2007-04-01 18:31:35 +00009026#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009027 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009028 if (block_signals()) {
9029 ret = -TARGET_ERESTARTSYS;
9030 } else {
9031 ret = do_sigreturn(cpu_env);
9032 }
bellard66fb9762003-03-23 01:06:05 +00009033 break;
thse5febef2007-04-01 18:31:35 +00009034#endif
bellard66fb9762003-03-23 01:06:05 +00009035 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009036 if (block_signals()) {
9037 ret = -TARGET_ERESTARTSYS;
9038 } else {
9039 ret = do_rt_sigreturn(cpu_env);
9040 }
bellard66fb9762003-03-23 01:06:05 +00009041 break;
bellard31e31b82003-02-18 22:55:36 +00009042 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009043 if (!(p = lock_user_string(arg1)))
9044 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009045 ret = get_errno(sethostname(p, arg2));
9046 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009047 break;
9048 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009049 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009050 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009051 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009052 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009053 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
9054 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009055 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9056 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009057 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00009058 ret = get_errno(setrlimit(resource, &rlim));
9059 }
9060 break;
bellard31e31b82003-02-18 22:55:36 +00009061 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009062 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009063 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009064 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009065 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009066
bellard9de5e442003-03-23 16:49:39 +00009067 ret = get_errno(getrlimit(resource, &rlim));
9068 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009069 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9070 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009071 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9072 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009073 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009074 }
9075 }
9076 break;
bellard31e31b82003-02-18 22:55:36 +00009077 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009078 {
9079 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009080 ret = get_errno(getrusage(arg1, &rusage));
9081 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009082 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009083 }
9084 }
9085 break;
bellard31e31b82003-02-18 22:55:36 +00009086 case TARGET_NR_gettimeofday:
9087 {
bellard31e31b82003-02-18 22:55:36 +00009088 struct timeval tv;
9089 ret = get_errno(gettimeofday(&tv, NULL));
9090 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00009091 if (copy_to_user_timeval(arg1, &tv))
9092 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009093 }
9094 }
9095 break;
9096 case TARGET_NR_settimeofday:
9097 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009098 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009099 struct timezone tz, *ptz = NULL;
9100
Paul Burtonb67d8032014-06-22 11:25:41 +01009101 if (arg1) {
9102 if (copy_from_user_timeval(&tv, arg1)) {
9103 goto efault;
9104 }
9105 ptv = &tv;
9106 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009107
9108 if (arg2) {
9109 if (copy_from_user_timezone(&tz, arg2)) {
9110 goto efault;
9111 }
9112 ptz = &tz;
9113 }
9114
Paul Burtonb67d8032014-06-22 11:25:41 +01009115 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009116 }
9117 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009118#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009119 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009120#if defined(TARGET_WANT_NI_OLD_SELECT)
9121 /* some architectures used to have old_select here
9122 * but now ENOSYS it.
9123 */
9124 ret = -TARGET_ENOSYS;
9125#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9126 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009127#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009128 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009129#endif
bellardf2674e32003-07-09 12:26:09 +00009130 break;
bellard048f6b42005-11-26 18:47:20 +00009131#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009132#ifdef TARGET_NR_pselect6
9133 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04009134 {
9135 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
9136 fd_set rfds, wfds, efds;
9137 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
9138 struct timespec ts, *ts_ptr;
9139
9140 /*
9141 * The 6th arg is actually two args smashed together,
9142 * so we cannot use the C library.
9143 */
9144 sigset_t set;
9145 struct {
9146 sigset_t *set;
9147 size_t size;
9148 } sig, *sig_ptr;
9149
9150 abi_ulong arg_sigset, arg_sigsize, *arg7;
9151 target_sigset_t *target_sigset;
9152
9153 n = arg1;
9154 rfd_addr = arg2;
9155 wfd_addr = arg3;
9156 efd_addr = arg4;
9157 ts_addr = arg5;
9158
9159 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9160 if (ret) {
9161 goto fail;
9162 }
9163 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9164 if (ret) {
9165 goto fail;
9166 }
9167 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9168 if (ret) {
9169 goto fail;
9170 }
9171
9172 /*
9173 * This takes a timespec, and not a timeval, so we cannot
9174 * use the do_select() helper ...
9175 */
9176 if (ts_addr) {
9177 if (target_to_host_timespec(&ts, ts_addr)) {
9178 goto efault;
9179 }
9180 ts_ptr = &ts;
9181 } else {
9182 ts_ptr = NULL;
9183 }
9184
9185 /* Extract the two packed args for the sigset */
9186 if (arg6) {
9187 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009188 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009189
9190 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9191 if (!arg7) {
9192 goto efault;
9193 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009194 arg_sigset = tswapal(arg7[0]);
9195 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009196 unlock_user(arg7, arg6, 0);
9197
9198 if (arg_sigset) {
9199 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009200 if (arg_sigsize != sizeof(*target_sigset)) {
9201 /* Like the kernel, we enforce correct size sigsets */
9202 ret = -TARGET_EINVAL;
9203 goto fail;
9204 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009205 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9206 sizeof(*target_sigset), 1);
9207 if (!target_sigset) {
9208 goto efault;
9209 }
9210 target_to_host_sigset(&set, target_sigset);
9211 unlock_user(target_sigset, arg_sigset, 0);
9212 } else {
9213 sig.set = NULL;
9214 }
9215 } else {
9216 sig_ptr = NULL;
9217 }
9218
Peter Maydell6df9d382016-05-12 18:47:51 +01009219 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9220 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009221
9222 if (!is_error(ret)) {
9223 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9224 goto efault;
9225 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9226 goto efault;
9227 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9228 goto efault;
9229
9230 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9231 goto efault;
9232 }
9233 }
9234 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009235#endif
Chen Gang704eff62015-08-21 05:37:33 +08009236#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009237 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009238 {
9239 void *p2;
9240 p = lock_user_string(arg1);
9241 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009242 if (!p || !p2)
9243 ret = -TARGET_EFAULT;
9244 else
9245 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009246 unlock_user(p2, arg2, 0);
9247 unlock_user(p, arg1, 0);
9248 }
bellard31e31b82003-02-18 22:55:36 +00009249 break;
Chen Gang704eff62015-08-21 05:37:33 +08009250#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009251#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009252 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009253 {
bellard579a97f2007-11-11 14:26:47 +00009254 void *p2;
thsf0b62432007-09-24 09:25:40 +00009255 p = lock_user_string(arg1);
9256 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009257 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009258 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009259 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009260 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009261 unlock_user(p2, arg3, 0);
9262 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009263 }
9264 break;
9265#endif
bellardebc05482003-09-30 21:08:41 +00009266#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009267 case TARGET_NR_oldlstat:
9268 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009269#endif
Chen Gang704eff62015-08-21 05:37:33 +08009270#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009271 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009272 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009273 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009274 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009275 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009276 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009277 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009278 } else if (!arg3) {
9279 /* Short circuit this for the magic exe check. */
9280 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009281 } else if (is_proc_myself((const char *)p, "exe")) {
9282 char real[PATH_MAX], *temp;
9283 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009284 /* Return value is # of bytes that we wrote to the buffer. */
9285 if (temp == NULL) {
9286 ret = get_errno(-1);
9287 } else {
9288 /* Don't worry about sign mismatch as earlier mapping
9289 * logic would have thrown a bad address error. */
9290 ret = MIN(strlen(real), arg3);
9291 /* We cannot NUL terminate the string. */
9292 memcpy(p2, real, ret);
9293 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009294 } else {
9295 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009296 }
pbrook53a59602006-03-25 19:31:22 +00009297 unlock_user(p2, arg2, ret);
9298 unlock_user(p, arg1, 0);
9299 }
bellard31e31b82003-02-18 22:55:36 +00009300 break;
Chen Gang704eff62015-08-21 05:37:33 +08009301#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009302#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009303 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009304 {
bellard579a97f2007-11-11 14:26:47 +00009305 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009306 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009307 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009308 if (!p || !p2) {
9309 ret = -TARGET_EFAULT;
9310 } else if (is_proc_myself((const char *)p, "exe")) {
9311 char real[PATH_MAX], *temp;
9312 temp = realpath(exec_path, real);
9313 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9314 snprintf((char *)p2, arg4, "%s", real);
9315 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009316 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009317 }
bellard579a97f2007-11-11 14:26:47 +00009318 unlock_user(p2, arg3, ret);
9319 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009320 }
9321 break;
9322#endif
thse5febef2007-04-01 18:31:35 +00009323#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009324 case TARGET_NR_uselib:
9325 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009326#endif
9327#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009328 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009329 if (!(p = lock_user_string(arg1)))
9330 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009331 ret = get_errno(swapon(p, arg2));
9332 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009333 break;
thse5febef2007-04-01 18:31:35 +00009334#endif
bellard31e31b82003-02-18 22:55:36 +00009335 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009336 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9337 /* arg4 must be ignored in all other cases */
9338 p = lock_user_string(arg4);
9339 if (!p) {
9340 goto efault;
9341 }
9342 ret = get_errno(reboot(arg1, arg2, arg3, p));
9343 unlock_user(p, arg4, 0);
9344 } else {
9345 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9346 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009347 break;
thse5febef2007-04-01 18:31:35 +00009348#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009349 case TARGET_NR_readdir:
9350 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009351#endif
9352#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009353 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009354#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9355 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009356 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9357 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009358 {
blueswir1992f48a2007-10-14 16:27:31 +00009359 abi_ulong *v;
9360 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009361 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9362 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009363 v1 = tswapal(v[0]);
9364 v2 = tswapal(v[1]);
9365 v3 = tswapal(v[2]);
9366 v4 = tswapal(v[3]);
9367 v5 = tswapal(v[4]);
9368 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009369 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009370 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009371 target_to_host_bitmask(v4, mmap_flags_tbl),
9372 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009373 }
bellard31e31b82003-02-18 22:55:36 +00009374#else
ths5fafdf22007-09-16 21:08:06 +00009375 ret = get_errno(target_mmap(arg1, arg2, arg3,
9376 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009377 arg5,
9378 arg6));
bellard31e31b82003-02-18 22:55:36 +00009379#endif
bellard6fb883e2003-07-09 17:12:39 +00009380 break;
thse5febef2007-04-01 18:31:35 +00009381#endif
bellarda315a142005-01-30 22:59:18 +00009382#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009383 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009384#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009385#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009386#endif
ths5fafdf22007-09-16 21:08:06 +00009387 ret = get_errno(target_mmap(arg1, arg2, arg3,
9388 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009389 arg5,
bellardc573ff62004-01-04 15:51:36 +00009390 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009391 break;
bellarda315a142005-01-30 22:59:18 +00009392#endif
bellard31e31b82003-02-18 22:55:36 +00009393 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009394 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009395 break;
bellard9de5e442003-03-23 16:49:39 +00009396 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009397 {
Andreas Färber0429a972013-08-26 18:14:44 +02009398 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009399 /* Special hack to detect libc making the stack executable. */
9400 if ((arg3 & PROT_GROWSDOWN)
9401 && arg1 >= ts->info->stack_limit
9402 && arg1 <= ts->info->start_stack) {
9403 arg3 &= ~PROT_GROWSDOWN;
9404 arg2 = arg2 + arg1 - ts->info->stack_limit;
9405 arg1 = ts->info->stack_limit;
9406 }
9407 }
bellard54936002003-05-13 00:25:15 +00009408 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009409 break;
thse5febef2007-04-01 18:31:35 +00009410#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009411 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009412 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009413 break;
thse5febef2007-04-01 18:31:35 +00009414#endif
pbrook53a59602006-03-25 19:31:22 +00009415 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009416#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009417 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009418 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009419 break;
thse5febef2007-04-01 18:31:35 +00009420#endif
9421#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009422 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009423 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009424 break;
thse5febef2007-04-01 18:31:35 +00009425#endif
9426#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009427 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009428 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009429 break;
thse5febef2007-04-01 18:31:35 +00009430#endif
9431#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009432 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009433 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009434 break;
thse5febef2007-04-01 18:31:35 +00009435#endif
9436#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009437 case TARGET_NR_munlockall:
9438 ret = get_errno(munlockall());
9439 break;
thse5febef2007-04-01 18:31:35 +00009440#endif
bellard31e31b82003-02-18 22:55:36 +00009441 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009442 if (!(p = lock_user_string(arg1)))
9443 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009444 ret = get_errno(truncate(p, arg2));
9445 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009446 break;
9447 case TARGET_NR_ftruncate:
9448 ret = get_errno(ftruncate(arg1, arg2));
9449 break;
9450 case TARGET_NR_fchmod:
9451 ret = get_errno(fchmod(arg1, arg2));
9452 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009453#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009454 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009455 if (!(p = lock_user_string(arg2)))
9456 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009457 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009458 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009459 break;
9460#endif
bellard31e31b82003-02-18 22:55:36 +00009461 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009462 /* Note that negative values are valid for getpriority, so we must
9463 differentiate based on errno settings. */
9464 errno = 0;
9465 ret = getpriority(arg1, arg2);
9466 if (ret == -1 && errno != 0) {
9467 ret = -host_to_target_errno(errno);
9468 break;
9469 }
9470#ifdef TARGET_ALPHA
9471 /* Return value is the unbiased priority. Signal no error. */
9472 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9473#else
9474 /* Return value is a biased priority to avoid negative numbers. */
9475 ret = 20 - ret;
9476#endif
bellard31e31b82003-02-18 22:55:36 +00009477 break;
9478 case TARGET_NR_setpriority:
9479 ret = get_errno(setpriority(arg1, arg2, arg3));
9480 break;
bellardebc05482003-09-30 21:08:41 +00009481#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009482 case TARGET_NR_profil:
9483 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009484#endif
bellard31e31b82003-02-18 22:55:36 +00009485 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009486 if (!(p = lock_user_string(arg1)))
9487 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009488 ret = get_errno(statfs(path(p), &stfs));
9489 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009490 convert_statfs:
9491 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009492 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009493
bellard579a97f2007-11-11 14:26:47 +00009494 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9495 goto efault;
9496 __put_user(stfs.f_type, &target_stfs->f_type);
9497 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9498 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9499 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9500 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9501 __put_user(stfs.f_files, &target_stfs->f_files);
9502 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9503 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9504 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9505 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009506 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9507 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009508 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009509 }
9510 break;
9511 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009512 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009513 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009514#ifdef TARGET_NR_statfs64
9515 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009516 if (!(p = lock_user_string(arg1)))
9517 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009518 ret = get_errno(statfs(path(p), &stfs));
9519 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009520 convert_statfs64:
9521 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009522 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009523
bellard579a97f2007-11-11 14:26:47 +00009524 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9525 goto efault;
9526 __put_user(stfs.f_type, &target_stfs->f_type);
9527 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9528 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9529 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9530 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9531 __put_user(stfs.f_files, &target_stfs->f_files);
9532 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9533 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9534 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9535 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009536 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9537 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009538 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009539 }
9540 break;
9541 case TARGET_NR_fstatfs64:
9542 ret = get_errno(fstatfs(arg1, &stfs));
9543 goto convert_statfs64;
9544#endif
bellardebc05482003-09-30 21:08:41 +00009545#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009546 case TARGET_NR_ioperm:
9547 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009548#endif
thse5febef2007-04-01 18:31:35 +00009549#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009550 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009551 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009552 break;
thse5febef2007-04-01 18:31:35 +00009553#endif
bellard3532fa72006-06-24 15:06:03 +00009554#ifdef TARGET_NR_accept
9555 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009556 ret = do_accept4(arg1, arg2, arg3, 0);
9557 break;
9558#endif
9559#ifdef TARGET_NR_accept4
9560 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009561 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009562 break;
9563#endif
9564#ifdef TARGET_NR_bind
9565 case TARGET_NR_bind:
9566 ret = do_bind(arg1, arg2, arg3);
9567 break;
9568#endif
9569#ifdef TARGET_NR_connect
9570 case TARGET_NR_connect:
9571 ret = do_connect(arg1, arg2, arg3);
9572 break;
9573#endif
9574#ifdef TARGET_NR_getpeername
9575 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009576 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009577 break;
9578#endif
9579#ifdef TARGET_NR_getsockname
9580 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009581 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009582 break;
9583#endif
9584#ifdef TARGET_NR_getsockopt
9585 case TARGET_NR_getsockopt:
9586 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9587 break;
9588#endif
9589#ifdef TARGET_NR_listen
9590 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009591 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009592 break;
9593#endif
9594#ifdef TARGET_NR_recv
9595 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009596 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009597 break;
9598#endif
9599#ifdef TARGET_NR_recvfrom
9600 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009601 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009602 break;
9603#endif
9604#ifdef TARGET_NR_recvmsg
9605 case TARGET_NR_recvmsg:
9606 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9607 break;
9608#endif
9609#ifdef TARGET_NR_send
9610 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009611 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009612 break;
9613#endif
9614#ifdef TARGET_NR_sendmsg
9615 case TARGET_NR_sendmsg:
9616 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9617 break;
9618#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009619#ifdef TARGET_NR_sendmmsg
9620 case TARGET_NR_sendmmsg:
9621 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9622 break;
9623 case TARGET_NR_recvmmsg:
9624 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9625 break;
9626#endif
bellard3532fa72006-06-24 15:06:03 +00009627#ifdef TARGET_NR_sendto
9628 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009629 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009630 break;
9631#endif
9632#ifdef TARGET_NR_shutdown
9633 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009634 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009635 break;
9636#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009637#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9638 case TARGET_NR_getrandom:
9639 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9640 if (!p) {
9641 goto efault;
9642 }
9643 ret = get_errno(getrandom(p, arg2, arg3));
9644 unlock_user(p, arg1, ret);
9645 break;
9646#endif
bellard3532fa72006-06-24 15:06:03 +00009647#ifdef TARGET_NR_socket
9648 case TARGET_NR_socket:
9649 ret = do_socket(arg1, arg2, arg3);
9650 break;
9651#endif
9652#ifdef TARGET_NR_socketpair
9653 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009654 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009655 break;
9656#endif
9657#ifdef TARGET_NR_setsockopt
9658 case TARGET_NR_setsockopt:
9659 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9660 break;
9661#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009662#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009663 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009664 {
9665 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009666
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009667 switch (arg1) {
9668 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9669 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9670 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9671 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9672 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9673 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9674 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9675 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9676 {
9677 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9678 }
9679 break;
9680 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9681 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9682 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9683 {
9684 ret = -TARGET_EINVAL;
9685 if (len < 0) {
9686 goto fail;
9687 }
9688 ret = 0;
9689 if (len == 0) {
9690 break;
9691 }
9692 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9693 if (!p) {
9694 ret = -TARGET_EFAULT;
9695 goto fail;
9696 }
9697 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9698 unlock_user(p, arg2, arg3);
9699 }
9700 break;
9701 default:
9702 ret = -EINVAL;
9703 break;
9704 }
9705 }
9706 break;
9707#endif
bellard31e31b82003-02-18 22:55:36 +00009708 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009709 {
bellard66fb9762003-03-23 01:06:05 +00009710 struct itimerval value, ovalue, *pvalue;
9711
pbrook53a59602006-03-25 19:31:22 +00009712 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009713 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009714 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9715 || copy_from_user_timeval(&pvalue->it_value,
9716 arg2 + sizeof(struct target_timeval)))
9717 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009718 } else {
9719 pvalue = NULL;
9720 }
9721 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009722 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009723 if (copy_to_user_timeval(arg3,
9724 &ovalue.it_interval)
9725 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9726 &ovalue.it_value))
9727 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009728 }
9729 }
9730 break;
bellard31e31b82003-02-18 22:55:36 +00009731 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009732 {
bellard66fb9762003-03-23 01:06:05 +00009733 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009734
bellard66fb9762003-03-23 01:06:05 +00009735 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009736 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009737 if (copy_to_user_timeval(arg2,
9738 &value.it_interval)
9739 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9740 &value.it_value))
9741 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009742 }
9743 }
9744 break;
Chen Gang704eff62015-08-21 05:37:33 +08009745#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009746 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009747 if (!(p = lock_user_string(arg1)))
9748 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009749 ret = get_errno(stat(path(p), &st));
9750 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009751 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009752#endif
9753#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009754 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009755 if (!(p = lock_user_string(arg1)))
9756 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009757 ret = get_errno(lstat(path(p), &st));
9758 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009759 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009760#endif
bellard31e31b82003-02-18 22:55:36 +00009761 case TARGET_NR_fstat:
9762 {
9763 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009764#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009765 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009766#endif
bellard31e31b82003-02-18 22:55:36 +00009767 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009768 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009769
bellard579a97f2007-11-11 14:26:47 +00009770 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9771 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009772 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009773 __put_user(st.st_dev, &target_st->st_dev);
9774 __put_user(st.st_ino, &target_st->st_ino);
9775 __put_user(st.st_mode, &target_st->st_mode);
9776 __put_user(st.st_uid, &target_st->st_uid);
9777 __put_user(st.st_gid, &target_st->st_gid);
9778 __put_user(st.st_nlink, &target_st->st_nlink);
9779 __put_user(st.st_rdev, &target_st->st_rdev);
9780 __put_user(st.st_size, &target_st->st_size);
9781 __put_user(st.st_blksize, &target_st->st_blksize);
9782 __put_user(st.st_blocks, &target_st->st_blocks);
9783 __put_user(st.st_atime, &target_st->target_st_atime);
9784 __put_user(st.st_mtime, &target_st->target_st_mtime);
9785 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009786 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009787 }
9788 }
9789 break;
bellardebc05482003-09-30 21:08:41 +00009790#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009791 case TARGET_NR_olduname:
9792 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009793#endif
9794#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009795 case TARGET_NR_iopl:
9796 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009797#endif
bellard31e31b82003-02-18 22:55:36 +00009798 case TARGET_NR_vhangup:
9799 ret = get_errno(vhangup());
9800 break;
bellardebc05482003-09-30 21:08:41 +00009801#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009802 case TARGET_NR_idle:
9803 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009804#endif
bellard42ad6ae2005-01-03 22:48:11 +00009805#ifdef TARGET_NR_syscall
9806 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009807 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9808 arg6, arg7, arg8, 0);
9809 break;
bellard42ad6ae2005-01-03 22:48:11 +00009810#endif
bellard31e31b82003-02-18 22:55:36 +00009811 case TARGET_NR_wait4:
9812 {
9813 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009814 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009815 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009816 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009817 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009818 if (target_rusage)
9819 rusage_ptr = &rusage;
9820 else
9821 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009822 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009823 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009824 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009825 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009826 if (put_user_s32(status, status_ptr))
9827 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009828 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009829 if (target_rusage) {
9830 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9831 if (rusage_err) {
9832 ret = rusage_err;
9833 }
9834 }
bellard31e31b82003-02-18 22:55:36 +00009835 }
9836 }
9837 break;
thse5febef2007-04-01 18:31:35 +00009838#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009839 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009840 if (!(p = lock_user_string(arg1)))
9841 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009842 ret = get_errno(swapoff(p));
9843 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009844 break;
thse5febef2007-04-01 18:31:35 +00009845#endif
bellard31e31b82003-02-18 22:55:36 +00009846 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009847 {
pbrook53a59602006-03-25 19:31:22 +00009848 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009849 struct sysinfo value;
9850 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009851 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009852 {
bellard579a97f2007-11-11 14:26:47 +00009853 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9854 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009855 __put_user(value.uptime, &target_value->uptime);
9856 __put_user(value.loads[0], &target_value->loads[0]);
9857 __put_user(value.loads[1], &target_value->loads[1]);
9858 __put_user(value.loads[2], &target_value->loads[2]);
9859 __put_user(value.totalram, &target_value->totalram);
9860 __put_user(value.freeram, &target_value->freeram);
9861 __put_user(value.sharedram, &target_value->sharedram);
9862 __put_user(value.bufferram, &target_value->bufferram);
9863 __put_user(value.totalswap, &target_value->totalswap);
9864 __put_user(value.freeswap, &target_value->freeswap);
9865 __put_user(value.procs, &target_value->procs);
9866 __put_user(value.totalhigh, &target_value->totalhigh);
9867 __put_user(value.freehigh, &target_value->freehigh);
9868 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009869 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009870 }
9871 }
9872 break;
thse5febef2007-04-01 18:31:35 +00009873#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009874 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +01009875 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
9876 break;
thse5febef2007-04-01 18:31:35 +00009877#endif
aurel32e5289082009-04-18 16:16:12 +00009878#ifdef TARGET_NR_semget
9879 case TARGET_NR_semget:
9880 ret = get_errno(semget(arg1, arg2, arg3));
9881 break;
9882#endif
9883#ifdef TARGET_NR_semop
9884 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009885 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009886 break;
9887#endif
9888#ifdef TARGET_NR_semctl
9889 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009890 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009891 break;
9892#endif
aurel32eeb438c2008-10-13 21:08:55 +00009893#ifdef TARGET_NR_msgctl
9894 case TARGET_NR_msgctl:
9895 ret = do_msgctl(arg1, arg2, arg3);
9896 break;
9897#endif
9898#ifdef TARGET_NR_msgget
9899 case TARGET_NR_msgget:
9900 ret = get_errno(msgget(arg1, arg2));
9901 break;
9902#endif
9903#ifdef TARGET_NR_msgrcv
9904 case TARGET_NR_msgrcv:
9905 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9906 break;
9907#endif
9908#ifdef TARGET_NR_msgsnd
9909 case TARGET_NR_msgsnd:
9910 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9911 break;
9912#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009913#ifdef TARGET_NR_shmget
9914 case TARGET_NR_shmget:
9915 ret = get_errno(shmget(arg1, arg2, arg3));
9916 break;
9917#endif
9918#ifdef TARGET_NR_shmctl
9919 case TARGET_NR_shmctl:
9920 ret = do_shmctl(arg1, arg2, arg3);
9921 break;
9922#endif
9923#ifdef TARGET_NR_shmat
9924 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +01009925 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009926 break;
9927#endif
9928#ifdef TARGET_NR_shmdt
9929 case TARGET_NR_shmdt:
9930 ret = do_shmdt(arg1);
9931 break;
9932#endif
bellard31e31b82003-02-18 22:55:36 +00009933 case TARGET_NR_fsync:
9934 ret = get_errno(fsync(arg1));
9935 break;
bellard31e31b82003-02-18 22:55:36 +00009936 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009937 /* Linux manages to have three different orderings for its
9938 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9939 * match the kernel's CONFIG_CLONE_* settings.
9940 * Microblaze is further special in that it uses a sixth
9941 * implicit argument to clone for the TLS pointer.
9942 */
9943#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009944 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009945#elif defined(TARGET_CLONE_BACKWARDS)
9946 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9947#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009948 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009949#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009950 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009951#endif
bellard1b6b0292003-03-22 17:31:38 +00009952 break;
bellardec86b0f2003-04-11 00:15:04 +00009953#ifdef __NR_exit_group
9954 /* new thread calls */
9955 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02009956#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00009957 _mcleanup();
9958#endif
bellarde9009672005-04-26 20:42:36 +00009959 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00009960 ret = get_errno(exit_group(arg1));
9961 break;
9962#endif
bellard31e31b82003-02-18 22:55:36 +00009963 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009964 if (!(p = lock_user_string(arg1)))
9965 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009966 ret = get_errno(setdomainname(p, arg2));
9967 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009968 break;
9969 case TARGET_NR_uname:
9970 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009971 {
9972 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009973
bellard579a97f2007-11-11 14:26:47 +00009974 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
9975 goto efault;
bellard29e619b2004-09-13 21:41:04 +00009976 ret = get_errno(sys_uname(buf));
9977 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009978 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009979 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01009980 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00009981 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009982 if (qemu_uname_release && *qemu_uname_release) {
9983 g_strlcpy(buf->release, qemu_uname_release,
9984 sizeof(buf->release));
9985 }
bellard29e619b2004-09-13 21:41:04 +00009986 }
pbrook53a59602006-03-25 19:31:22 +00009987 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009988 }
bellard31e31b82003-02-18 22:55:36 +00009989 break;
bellard6dbad632003-03-16 18:05:05 +00009990#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009991 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00009992 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00009993 break;
j_mayer84409dd2007-04-06 08:56:50 +00009994#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009995 case TARGET_NR_vm86old:
9996 goto unimplemented;
9997 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00009998 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009999 break;
10000#endif
j_mayer84409dd2007-04-06 08:56:50 +000010001#endif
bellard31e31b82003-02-18 22:55:36 +000010002 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010003 {
10004 struct timex host_buf;
10005
10006 if (target_to_host_timex(&host_buf, arg1) != 0) {
10007 goto efault;
10008 }
10009 ret = get_errno(adjtimex(&host_buf));
10010 if (!is_error(ret)) {
10011 if (host_to_target_timex(arg1, &host_buf) != 0) {
10012 goto efault;
10013 }
10014 }
10015 }
10016 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010017#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10018 case TARGET_NR_clock_adjtime:
10019 {
10020 struct timex htx, *phtx = &htx;
10021
10022 if (target_to_host_timex(phtx, arg2) != 0) {
10023 goto efault;
10024 }
10025 ret = get_errno(clock_adjtime(arg1, phtx));
10026 if (!is_error(ret) && phtx) {
10027 if (host_to_target_timex(arg2, phtx) != 0) {
10028 goto efault;
10029 }
10030 }
10031 }
10032 break;
10033#endif
thse5febef2007-04-01 18:31:35 +000010034#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +000010035 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +000010036#endif
bellard31e31b82003-02-18 22:55:36 +000010037 case TARGET_NR_init_module:
10038 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +000010039#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +000010040 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +000010041#endif
bellard31e31b82003-02-18 22:55:36 +000010042 goto unimplemented;
10043 case TARGET_NR_quotactl:
10044 goto unimplemented;
10045 case TARGET_NR_getpgid:
10046 ret = get_errno(getpgid(arg1));
10047 break;
10048 case TARGET_NR_fchdir:
10049 ret = get_errno(fchdir(arg1));
10050 break;
j_mayer84409dd2007-04-06 08:56:50 +000010051#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +000010052 case TARGET_NR_bdflush:
10053 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +000010054#endif
thse5febef2007-04-01 18:31:35 +000010055#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +000010056 case TARGET_NR_sysfs:
10057 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010058#endif
bellard31e31b82003-02-18 22:55:36 +000010059 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +000010060 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +000010061 break;
thse5febef2007-04-01 18:31:35 +000010062#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +000010063 case TARGET_NR_afs_syscall:
10064 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010065#endif
j_mayer7a3148a2007-04-05 07:13:51 +000010066#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010067 case TARGET_NR__llseek:
10068 {
10069 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010070#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010071 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010072 if (res == -1) {
10073 ret = get_errno(res);
10074 } else {
10075 ret = 0;
10076 }
10077#else
bellard31e31b82003-02-18 22:55:36 +000010078 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010079#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010080 if ((ret == 0) && put_user_s64(res, arg4)) {
10081 goto efault;
10082 }
bellard31e31b82003-02-18 22:55:36 +000010083 }
10084 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010085#endif
Chen Gang704eff62015-08-21 05:37:33 +080010086#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010087 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +010010088#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010089#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010090 {
pbrook53a59602006-03-25 19:31:22 +000010091 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010092 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010093 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010094
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010095 dirp = g_try_malloc(count);
10096 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +000010097 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010098 goto fail;
10099 }
ths3b46e622007-09-17 08:09:54 +000010100
bellard4add45b2003-06-05 01:52:59 +000010101 ret = get_errno(sys_getdents(arg1, dirp, count));
10102 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010103 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010104 struct target_dirent *tde;
10105 int len = ret;
10106 int reclen, treclen;
10107 int count1, tnamelen;
10108
10109 count1 = 0;
10110 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010111 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10112 goto efault;
bellard4add45b2003-06-05 01:52:59 +000010113 tde = target_dirp;
10114 while (len > 0) {
10115 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010116 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10117 assert(tnamelen >= 0);
10118 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10119 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010120 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010121 tde->d_ino = tswapal(de->d_ino);
10122 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010123 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010124 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010125 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010126 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010127 count1 += treclen;
10128 }
10129 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010130 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010131 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010132 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010133 }
10134#else
bellard31e31b82003-02-18 22:55:36 +000010135 {
aurel326556a832008-10-13 21:08:17 +000010136 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010137 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010138
bellard579a97f2007-11-11 14:26:47 +000010139 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10140 goto efault;
bellard72f03902003-02-18 23:33:18 +000010141 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010142 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010143 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010144 int len = ret;
10145 int reclen;
10146 de = dirp;
10147 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010148 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010149 if (reclen > len)
10150 break;
bellard8083a3e2003-03-24 23:12:16 +000010151 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010152 tswapls(&de->d_ino);
10153 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010154 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010155 len -= reclen;
10156 }
10157 }
pbrook53a59602006-03-25 19:31:22 +000010158 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010159 }
bellard4add45b2003-06-05 01:52:59 +000010160#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010161#else
10162 /* Implement getdents in terms of getdents64 */
10163 {
10164 struct linux_dirent64 *dirp;
10165 abi_long count = arg3;
10166
10167 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10168 if (!dirp) {
10169 goto efault;
10170 }
10171 ret = get_errno(sys_getdents64(arg1, dirp, count));
10172 if (!is_error(ret)) {
10173 /* Convert the dirent64 structs to target dirent. We do this
10174 * in-place, since we can guarantee that a target_dirent is no
10175 * larger than a dirent64; however this means we have to be
10176 * careful to read everything before writing in the new format.
10177 */
10178 struct linux_dirent64 *de;
10179 struct target_dirent *tde;
10180 int len = ret;
10181 int tlen = 0;
10182
10183 de = dirp;
10184 tde = (struct target_dirent *)dirp;
10185 while (len > 0) {
10186 int namelen, treclen;
10187 int reclen = de->d_reclen;
10188 uint64_t ino = de->d_ino;
10189 int64_t off = de->d_off;
10190 uint8_t type = de->d_type;
10191
10192 namelen = strlen(de->d_name);
10193 treclen = offsetof(struct target_dirent, d_name)
10194 + namelen + 2;
10195 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10196
10197 memmove(tde->d_name, de->d_name, namelen + 1);
10198 tde->d_ino = tswapal(ino);
10199 tde->d_off = tswapal(off);
10200 tde->d_reclen = tswap16(treclen);
10201 /* The target_dirent type is in what was formerly a padding
10202 * byte at the end of the structure:
10203 */
10204 *(((char *)tde) + treclen - 1) = type;
10205
10206 de = (struct linux_dirent64 *)((char *)de + reclen);
10207 tde = (struct target_dirent *)((char *)tde + treclen);
10208 len -= reclen;
10209 tlen += treclen;
10210 }
10211 ret = tlen;
10212 }
10213 unlock_user(dirp, arg2, ret);
10214 }
10215#endif
bellard31e31b82003-02-18 22:55:36 +000010216 break;
Chen Gang704eff62015-08-21 05:37:33 +080010217#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010218#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010219 case TARGET_NR_getdents64:
10220 {
aurel326556a832008-10-13 21:08:17 +000010221 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010222 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010223 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10224 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010225 ret = get_errno(sys_getdents64(arg1, dirp, count));
10226 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010227 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010228 int len = ret;
10229 int reclen;
10230 de = dirp;
10231 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010232 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010233 if (reclen > len)
10234 break;
bellard8083a3e2003-03-24 23:12:16 +000010235 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010236 tswap64s((uint64_t *)&de->d_ino);
10237 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010238 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010239 len -= reclen;
10240 }
10241 }
pbrook53a59602006-03-25 19:31:22 +000010242 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010243 }
10244 break;
bellarda541f292004-04-12 20:39:29 +000010245#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010246#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010247 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010248 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010249 break;
thse5febef2007-04-01 18:31:35 +000010250#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010251#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10252# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010253 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010254# endif
10255# ifdef TARGET_NR_ppoll
10256 case TARGET_NR_ppoll:
10257# endif
bellard9de5e442003-03-23 16:49:39 +000010258 {
pbrook53a59602006-03-25 19:31:22 +000010259 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010260 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010261 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010262 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010263
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010264 pfd = NULL;
10265 target_pfd = NULL;
10266 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010267 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10268 ret = -TARGET_EINVAL;
10269 break;
10270 }
10271
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010272 target_pfd = lock_user(VERIFY_WRITE, arg1,
10273 sizeof(struct target_pollfd) * nfds, 1);
10274 if (!target_pfd) {
10275 goto efault;
10276 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010277
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010278 pfd = alloca(sizeof(struct pollfd) * nfds);
10279 for (i = 0; i < nfds; i++) {
10280 pfd[i].fd = tswap32(target_pfd[i].fd);
10281 pfd[i].events = tswap16(target_pfd[i].events);
10282 }
bellard9de5e442003-03-23 16:49:39 +000010283 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010284
Peter Maydella6130232016-06-06 19:58:10 +010010285 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010286# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010287 case TARGET_NR_ppoll:
10288 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010289 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10290 target_sigset_t *target_set;
10291 sigset_t _set, *set = &_set;
10292
10293 if (arg3) {
10294 if (target_to_host_timespec(timeout_ts, arg3)) {
10295 unlock_user(target_pfd, arg1, 0);
10296 goto efault;
10297 }
10298 } else {
10299 timeout_ts = NULL;
10300 }
10301
10302 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010303 if (arg5 != sizeof(target_sigset_t)) {
10304 unlock_user(target_pfd, arg1, 0);
10305 ret = -TARGET_EINVAL;
10306 break;
10307 }
10308
Mike Frysingerd8035d42011-02-07 01:05:51 -050010309 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10310 if (!target_set) {
10311 unlock_user(target_pfd, arg1, 0);
10312 goto efault;
10313 }
10314 target_to_host_sigset(set, target_set);
10315 } else {
10316 set = NULL;
10317 }
10318
Peter Maydella6130232016-06-06 19:58:10 +010010319 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10320 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010321
10322 if (!is_error(ret) && arg3) {
10323 host_to_target_timespec(arg3, timeout_ts);
10324 }
10325 if (arg4) {
10326 unlock_user(target_set, arg4, 0);
10327 }
Peter Maydella6130232016-06-06 19:58:10 +010010328 break;
10329 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010330# endif
Peter Maydella6130232016-06-06 19:58:10 +010010331# ifdef TARGET_NR_poll
10332 case TARGET_NR_poll:
10333 {
10334 struct timespec ts, *pts;
10335
10336 if (arg3 >= 0) {
10337 /* Convert ms to secs, ns */
10338 ts.tv_sec = arg3 / 1000;
10339 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10340 pts = &ts;
10341 } else {
10342 /* -ve poll() timeout means "infinite" */
10343 pts = NULL;
10344 }
10345 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10346 break;
10347 }
10348# endif
10349 default:
10350 g_assert_not_reached();
10351 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010352
bellard9de5e442003-03-23 16:49:39 +000010353 if (!is_error(ret)) {
10354 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010355 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010356 }
10357 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010358 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010359 }
10360 break;
thse5febef2007-04-01 18:31:35 +000010361#endif
bellard31e31b82003-02-18 22:55:36 +000010362 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010363 /* NOTE: the flock constant seems to be the same for every
10364 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010365 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010366 break;
10367 case TARGET_NR_readv:
10368 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010369 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10370 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010371 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010372 unlock_iovec(vec, arg2, arg3, 1);
10373 } else {
10374 ret = -host_to_target_errno(errno);
10375 }
bellard31e31b82003-02-18 22:55:36 +000010376 }
10377 break;
10378 case TARGET_NR_writev:
10379 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010380 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10381 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010382 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010383 unlock_iovec(vec, arg2, arg3, 0);
10384 } else {
10385 ret = -host_to_target_errno(errno);
10386 }
bellard31e31b82003-02-18 22:55:36 +000010387 }
10388 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010389#if defined(TARGET_NR_preadv)
10390 case TARGET_NR_preadv:
10391 {
10392 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10393 if (vec != NULL) {
10394 ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
10395 unlock_iovec(vec, arg2, arg3, 1);
10396 } else {
10397 ret = -host_to_target_errno(errno);
10398 }
10399 }
10400 break;
10401#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010402#if defined(TARGET_NR_pwritev)
10403 case TARGET_NR_pwritev:
10404 {
10405 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10406 if (vec != NULL) {
10407 ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
10408 unlock_iovec(vec, arg2, arg3, 0);
10409 } else {
10410 ret = -host_to_target_errno(errno);
10411 }
10412 }
10413 break;
10414#endif
bellard31e31b82003-02-18 22:55:36 +000010415 case TARGET_NR_getsid:
10416 ret = get_errno(getsid(arg1));
10417 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010418#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010419 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010420 ret = get_errno(fdatasync(arg1));
10421 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010422#endif
Chen Gang704eff62015-08-21 05:37:33 +080010423#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010424 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010425 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010426 return value. */
ths0da46a62007-10-20 20:23:07 +000010427 ret = -TARGET_ENOTDIR;
10428 break;
Chen Gang704eff62015-08-21 05:37:33 +080010429#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010430 case TARGET_NR_sched_getaffinity:
10431 {
10432 unsigned int mask_size;
10433 unsigned long *mask;
10434
10435 /*
10436 * sched_getaffinity needs multiples of ulong, so need to take
10437 * care of mismatches between target ulong and host ulong sizes.
10438 */
10439 if (arg2 & (sizeof(abi_ulong) - 1)) {
10440 ret = -TARGET_EINVAL;
10441 break;
10442 }
10443 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10444
10445 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010446 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010447 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10448
10449 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010450 if (ret > arg2) {
10451 /* More data returned than the caller's buffer will fit.
10452 * This only happens if sizeof(abi_long) < sizeof(long)
10453 * and the caller passed us a buffer holding an odd number
10454 * of abi_longs. If the host kernel is actually using the
10455 * extra 4 bytes then fail EINVAL; otherwise we can just
10456 * ignore them and only copy the interesting part.
10457 */
10458 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10459 if (numcpus > arg2 * 8) {
10460 ret = -TARGET_EINVAL;
10461 break;
10462 }
10463 ret = arg2;
10464 }
10465
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010466 ret = host_to_target_cpu_mask(mask, mask_size, arg3, arg2);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010467 }
10468 }
10469 break;
10470 case TARGET_NR_sched_setaffinity:
10471 {
10472 unsigned int mask_size;
10473 unsigned long *mask;
10474
10475 /*
10476 * sched_setaffinity needs multiples of ulong, so need to take
10477 * care of mismatches between target ulong and host ulong sizes.
10478 */
10479 if (arg2 & (sizeof(abi_ulong) - 1)) {
10480 ret = -TARGET_EINVAL;
10481 break;
10482 }
10483 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010484 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010485
10486 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10487 if (ret) {
10488 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010489 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010490
10491 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10492 }
10493 break;
bellard31e31b82003-02-18 22:55:36 +000010494 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010495 {
pbrook53a59602006-03-25 19:31:22 +000010496 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010497 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010498
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010499 if (arg2 == 0) {
10500 return -TARGET_EINVAL;
10501 }
bellard579a97f2007-11-11 14:26:47 +000010502 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10503 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010504 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010505 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010506 ret = get_errno(sched_setparam(arg1, &schp));
10507 }
10508 break;
bellard31e31b82003-02-18 22:55:36 +000010509 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010510 {
pbrook53a59602006-03-25 19:31:22 +000010511 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010512 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010513
10514 if (arg2 == 0) {
10515 return -TARGET_EINVAL;
10516 }
bellard5cd43932003-03-29 16:54:36 +000010517 ret = get_errno(sched_getparam(arg1, &schp));
10518 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010519 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10520 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010521 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010522 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010523 }
10524 }
10525 break;
bellard31e31b82003-02-18 22:55:36 +000010526 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010527 {
pbrook53a59602006-03-25 19:31:22 +000010528 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010529 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010530 if (arg3 == 0) {
10531 return -TARGET_EINVAL;
10532 }
bellard579a97f2007-11-11 14:26:47 +000010533 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10534 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010535 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010536 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010537 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10538 }
10539 break;
bellard31e31b82003-02-18 22:55:36 +000010540 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010541 ret = get_errno(sched_getscheduler(arg1));
10542 break;
bellard31e31b82003-02-18 22:55:36 +000010543 case TARGET_NR_sched_yield:
10544 ret = get_errno(sched_yield());
10545 break;
10546 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010547 ret = get_errno(sched_get_priority_max(arg1));
10548 break;
bellard31e31b82003-02-18 22:55:36 +000010549 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010550 ret = get_errno(sched_get_priority_min(arg1));
10551 break;
bellard31e31b82003-02-18 22:55:36 +000010552 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010553 {
bellard5cd43932003-03-29 16:54:36 +000010554 struct timespec ts;
10555 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10556 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010557 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010558 }
10559 }
10560 break;
bellard31e31b82003-02-18 22:55:36 +000010561 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010562 {
bellard1b6b0292003-03-22 17:31:38 +000010563 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010564 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010565 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010566 if (is_error(ret) && arg2) {
10567 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010568 }
10569 }
10570 break;
thse5febef2007-04-01 18:31:35 +000010571#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010572 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010573 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010574#endif
10575#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010576 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010577 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010578#endif
bellard31e31b82003-02-18 22:55:36 +000010579 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010580 switch (arg1) {
10581 case PR_GET_PDEATHSIG:
10582 {
10583 int deathsig;
10584 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10585 if (!is_error(ret) && arg2
10586 && put_user_ual(deathsig, arg2)) {
10587 goto efault;
thse5574482007-02-11 20:03:13 +000010588 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010589 break;
10590 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010591#ifdef PR_GET_NAME
10592 case PR_GET_NAME:
10593 {
10594 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10595 if (!name) {
10596 goto efault;
10597 }
10598 ret = get_errno(prctl(arg1, (unsigned long)name,
10599 arg3, arg4, arg5));
10600 unlock_user(name, arg2, 16);
10601 break;
10602 }
10603 case PR_SET_NAME:
10604 {
10605 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10606 if (!name) {
10607 goto efault;
10608 }
10609 ret = get_errno(prctl(arg1, (unsigned long)name,
10610 arg3, arg4, arg5));
10611 unlock_user(name, arg2, 0);
10612 break;
10613 }
10614#endif
James Cowgilla8b154a2017-11-06 18:03:51 +000010615 case PR_GET_SECCOMP:
10616 case PR_SET_SECCOMP:
10617 /* Disable seccomp to prevent the target disabling syscalls we
10618 * need. */
10619 ret = -TARGET_EINVAL;
10620 break;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010621 default:
10622 /* Most prctl options have no pointer arguments */
10623 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10624 break;
10625 }
ths39b9aae2007-02-11 18:36:44 +000010626 break;
bellardd2fd1af2007-11-14 18:08:56 +000010627#ifdef TARGET_NR_arch_prctl
10628 case TARGET_NR_arch_prctl:
10629#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10630 ret = do_arch_prctl(cpu_env, arg1, arg2);
10631 break;
10632#else
10633 goto unimplemented;
10634#endif
10635#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010636#ifdef TARGET_NR_pread64
10637 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010638 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010639 arg4 = arg5;
10640 arg5 = arg6;
10641 }
aurel32f2c7ba12008-03-28 22:32:06 +000010642 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10643 goto efault;
10644 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10645 unlock_user(p, arg2, ret);
10646 break;
10647 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010648 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010649 arg4 = arg5;
10650 arg5 = arg6;
10651 }
aurel32f2c7ba12008-03-28 22:32:06 +000010652 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10653 goto efault;
10654 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10655 unlock_user(p, arg2, 0);
10656 break;
10657#endif
bellard31e31b82003-02-18 22:55:36 +000010658 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010659 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10660 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010661 ret = get_errno(sys_getcwd1(p, arg2));
10662 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010663 break;
10664 case TARGET_NR_capget:
10665 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010666 {
10667 struct target_user_cap_header *target_header;
10668 struct target_user_cap_data *target_data = NULL;
10669 struct __user_cap_header_struct header;
10670 struct __user_cap_data_struct data[2];
10671 struct __user_cap_data_struct *dataptr = NULL;
10672 int i, target_datalen;
10673 int data_items = 1;
10674
10675 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10676 goto efault;
10677 }
10678 header.version = tswap32(target_header->version);
10679 header.pid = tswap32(target_header->pid);
10680
Peter Maydellec864872014-03-19 16:07:30 +000010681 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010682 /* Version 2 and up takes pointer to two user_data structs */
10683 data_items = 2;
10684 }
10685
10686 target_datalen = sizeof(*target_data) * data_items;
10687
10688 if (arg2) {
10689 if (num == TARGET_NR_capget) {
10690 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10691 } else {
10692 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10693 }
10694 if (!target_data) {
10695 unlock_user_struct(target_header, arg1, 0);
10696 goto efault;
10697 }
10698
10699 if (num == TARGET_NR_capset) {
10700 for (i = 0; i < data_items; i++) {
10701 data[i].effective = tswap32(target_data[i].effective);
10702 data[i].permitted = tswap32(target_data[i].permitted);
10703 data[i].inheritable = tswap32(target_data[i].inheritable);
10704 }
10705 }
10706
10707 dataptr = data;
10708 }
10709
10710 if (num == TARGET_NR_capget) {
10711 ret = get_errno(capget(&header, dataptr));
10712 } else {
10713 ret = get_errno(capset(&header, dataptr));
10714 }
10715
10716 /* The kernel always updates version for both capget and capset */
10717 target_header->version = tswap32(header.version);
10718 unlock_user_struct(target_header, arg1, 1);
10719
10720 if (arg2) {
10721 if (num == TARGET_NR_capget) {
10722 for (i = 0; i < data_items; i++) {
10723 target_data[i].effective = tswap32(data[i].effective);
10724 target_data[i].permitted = tswap32(data[i].permitted);
10725 target_data[i].inheritable = tswap32(data[i].inheritable);
10726 }
10727 unlock_user(target_data, arg2, target_datalen);
10728 } else {
10729 unlock_user(target_data, arg2, 0);
10730 }
10731 }
10732 break;
10733 }
bellard31e31b82003-02-18 22:55:36 +000010734 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010735 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010736 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010737
10738#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010739 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010740 {
10741 off_t *offp = NULL;
10742 off_t off;
10743 if (arg3) {
10744 ret = get_user_sal(off, arg3);
10745 if (is_error(ret)) {
10746 break;
10747 }
10748 offp = &off;
10749 }
10750 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10751 if (!is_error(ret) && arg3) {
10752 abi_long ret2 = put_user_sal(off, arg3);
10753 if (is_error(ret2)) {
10754 ret = ret2;
10755 }
10756 }
10757 break;
10758 }
10759#ifdef TARGET_NR_sendfile64
10760 case TARGET_NR_sendfile64:
10761 {
10762 off_t *offp = NULL;
10763 off_t off;
10764 if (arg3) {
10765 ret = get_user_s64(off, arg3);
10766 if (is_error(ret)) {
10767 break;
10768 }
10769 offp = &off;
10770 }
10771 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10772 if (!is_error(ret) && arg3) {
10773 abi_long ret2 = put_user_s64(off, arg3);
10774 if (is_error(ret2)) {
10775 ret = ret2;
10776 }
10777 }
10778 break;
10779 }
10780#endif
10781#else
10782 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010783#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010784 case TARGET_NR_sendfile64:
10785#endif
bellard5cd43932003-03-29 16:54:36 +000010786 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010787#endif
10788
bellardebc05482003-09-30 21:08:41 +000010789#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010790 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010791 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010792#endif
10793#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010794 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010795 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010796#endif
bellard048f6b42005-11-26 18:47:20 +000010797#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010798 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010010799 ret = get_errno(do_fork(cpu_env,
10800 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000010801 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010802 break;
bellard048f6b42005-11-26 18:47:20 +000010803#endif
bellardebc05482003-09-30 21:08:41 +000010804#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010805 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010806 {
10807 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010808 int resource = target_to_host_resource(arg1);
10809 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010810 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010811 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010812 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10813 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010814 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10815 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010816 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010817 }
10818 break;
10819 }
bellardebc05482003-09-30 21:08:41 +000010820#endif
bellarda315a142005-01-30 22:59:18 +000010821#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010822 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010823 if (!(p = lock_user_string(arg1)))
10824 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010825 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10826 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010827 break;
bellarda315a142005-01-30 22:59:18 +000010828#endif
10829#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010830 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010831 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010832 break;
bellarda315a142005-01-30 22:59:18 +000010833#endif
10834#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010835 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010836 if (!(p = lock_user_string(arg1)))
10837 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010838 ret = get_errno(stat(path(p), &st));
10839 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010840 if (!is_error(ret))
10841 ret = host_to_target_stat64(cpu_env, arg2, &st);
10842 break;
bellarda315a142005-01-30 22:59:18 +000010843#endif
10844#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010845 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010846 if (!(p = lock_user_string(arg1)))
10847 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010848 ret = get_errno(lstat(path(p), &st));
10849 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010850 if (!is_error(ret))
10851 ret = host_to_target_stat64(cpu_env, arg2, &st);
10852 break;
bellarda315a142005-01-30 22:59:18 +000010853#endif
10854#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010855 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010856 ret = get_errno(fstat(arg1, &st));
10857 if (!is_error(ret))
10858 ret = host_to_target_stat64(cpu_env, arg2, &st);
10859 break;
bellardec86b0f2003-04-11 00:15:04 +000010860#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010861#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010862#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010863 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010864#endif
10865#ifdef TARGET_NR_newfstatat
10866 case TARGET_NR_newfstatat:
10867#endif
balrog6a24a772008-09-20 02:23:36 +000010868 if (!(p = lock_user_string(arg2)))
10869 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010870 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010871 if (!is_error(ret))
10872 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010873 break;
bellarda315a142005-01-30 22:59:18 +000010874#endif
Chen Gang704eff62015-08-21 05:37:33 +080010875#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010876 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010877 if (!(p = lock_user_string(arg1)))
10878 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010879 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10880 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010881 break;
Chen Gang704eff62015-08-21 05:37:33 +080010882#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010883#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010884 case TARGET_NR_getuid:
10885 ret = get_errno(high2lowuid(getuid()));
10886 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010887#endif
10888#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010889 case TARGET_NR_getgid:
10890 ret = get_errno(high2lowgid(getgid()));
10891 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010892#endif
10893#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010894 case TARGET_NR_geteuid:
10895 ret = get_errno(high2lowuid(geteuid()));
10896 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010897#endif
10898#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010899 case TARGET_NR_getegid:
10900 ret = get_errno(high2lowgid(getegid()));
10901 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010902#endif
bellard67867302003-11-23 17:05:30 +000010903 case TARGET_NR_setreuid:
10904 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
10905 break;
10906 case TARGET_NR_setregid:
10907 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
10908 break;
10909 case TARGET_NR_getgroups:
10910 {
10911 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010912 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010913 gid_t *grouplist;
10914 int i;
10915
10916 grouplist = alloca(gidsetsize * sizeof(gid_t));
10917 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010918 if (gidsetsize == 0)
10919 break;
bellard67867302003-11-23 17:05:30 +000010920 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010921 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010922 if (!target_grouplist)
10923 goto efault;
balroga2155fc2008-09-20 02:12:08 +000010924 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010925 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010926 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010927 }
10928 }
10929 break;
10930 case TARGET_NR_setgroups:
10931 {
10932 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010933 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010934 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010935 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010936 if (gidsetsize) {
10937 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010938 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010939 if (!target_grouplist) {
10940 ret = -TARGET_EFAULT;
10941 goto fail;
10942 }
10943 for (i = 0; i < gidsetsize; i++) {
10944 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10945 }
10946 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010947 }
bellard67867302003-11-23 17:05:30 +000010948 ret = get_errno(setgroups(gidsetsize, grouplist));
10949 }
10950 break;
10951 case TARGET_NR_fchown:
10952 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
10953 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010954#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010955 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010956 if (!(p = lock_user_string(arg2)))
10957 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010958 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10959 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010960 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000010961 break;
10962#endif
bellard67867302003-11-23 17:05:30 +000010963#ifdef TARGET_NR_setresuid
10964 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010965 ret = get_errno(sys_setresuid(low2highuid(arg1),
10966 low2highuid(arg2),
10967 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010968 break;
10969#endif
10970#ifdef TARGET_NR_getresuid
10971 case TARGET_NR_getresuid:
10972 {
pbrook53a59602006-03-25 19:31:22 +000010973 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010974 ret = get_errno(getresuid(&ruid, &euid, &suid));
10975 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010976 if (put_user_id(high2lowuid(ruid), arg1)
10977 || put_user_id(high2lowuid(euid), arg2)
10978 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000010979 goto efault;
bellard67867302003-11-23 17:05:30 +000010980 }
10981 }
10982 break;
10983#endif
10984#ifdef TARGET_NR_getresgid
10985 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010986 ret = get_errno(sys_setresgid(low2highgid(arg1),
10987 low2highgid(arg2),
10988 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010989 break;
10990#endif
10991#ifdef TARGET_NR_getresgid
10992 case TARGET_NR_getresgid:
10993 {
pbrook53a59602006-03-25 19:31:22 +000010994 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010995 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10996 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010997 if (put_user_id(high2lowgid(rgid), arg1)
10998 || put_user_id(high2lowgid(egid), arg2)
10999 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000011000 goto efault;
bellard67867302003-11-23 17:05:30 +000011001 }
11002 }
11003 break;
11004#endif
Chen Gang704eff62015-08-21 05:37:33 +080011005#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011006 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011007 if (!(p = lock_user_string(arg1)))
11008 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011009 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11010 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011011 break;
Chen Gang704eff62015-08-21 05:37:33 +080011012#endif
bellard67867302003-11-23 17:05:30 +000011013 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011014 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011015 break;
11016 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011017 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011018 break;
11019 case TARGET_NR_setfsuid:
11020 ret = get_errno(setfsuid(arg1));
11021 break;
11022 case TARGET_NR_setfsgid:
11023 ret = get_errno(setfsgid(arg1));
11024 break;
bellard67867302003-11-23 17:05:30 +000011025
bellarda315a142005-01-30 22:59:18 +000011026#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011027 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011028 if (!(p = lock_user_string(arg1)))
11029 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011030 ret = get_errno(lchown(p, arg2, arg3));
11031 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011032 break;
bellarda315a142005-01-30 22:59:18 +000011033#endif
11034#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011035 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000011036 ret = get_errno(getuid());
11037 break;
bellarda315a142005-01-30 22:59:18 +000011038#endif
aurel3264b4d282008-11-14 17:20:15 +000011039
11040#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11041 /* Alpha specific */
11042 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011043 {
11044 uid_t euid;
11045 euid=geteuid();
11046 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11047 }
aurel3264b4d282008-11-14 17:20:15 +000011048 ret = get_errno(getuid());
11049 break;
11050#endif
11051#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11052 /* Alpha specific */
11053 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011054 {
11055 uid_t egid;
11056 egid=getegid();
11057 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11058 }
aurel3264b4d282008-11-14 17:20:15 +000011059 ret = get_errno(getgid());
11060 break;
11061#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011062#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11063 /* Alpha specific */
11064 case TARGET_NR_osf_getsysinfo:
11065 ret = -TARGET_EOPNOTSUPP;
11066 switch (arg1) {
11067 case TARGET_GSI_IEEE_FP_CONTROL:
11068 {
11069 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
11070
11071 /* Copied from linux ieee_fpcr_to_swcr. */
11072 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
11073 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
11074 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
11075 | SWCR_TRAP_ENABLE_DZE
11076 | SWCR_TRAP_ENABLE_OVF);
11077 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
11078 | SWCR_TRAP_ENABLE_INE);
11079 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
11080 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
11081
11082 if (put_user_u64 (swcr, arg2))
11083 goto efault;
11084 ret = 0;
11085 }
11086 break;
11087
11088 /* case GSI_IEEE_STATE_AT_SIGNAL:
11089 -- Not implemented in linux kernel.
11090 case GSI_UACPROC:
11091 -- Retrieves current unaligned access state; not much used.
11092 case GSI_PROC_TYPE:
11093 -- Retrieves implver information; surely not used.
11094 case GSI_GET_HWRPB:
11095 -- Grabs a copy of the HWRPB; surely not used.
11096 */
11097 }
11098 break;
11099#endif
11100#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11101 /* Alpha specific */
11102 case TARGET_NR_osf_setsysinfo:
11103 ret = -TARGET_EOPNOTSUPP;
11104 switch (arg1) {
11105 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011106 {
11107 uint64_t swcr, fpcr, orig_fpcr;
11108
Richard Henderson6e06d512012-06-01 09:08:21 -070011109 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080011110 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070011111 }
11112 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011113 fpcr = orig_fpcr & FPCR_DYN_MASK;
11114
11115 /* Copied from linux ieee_swcr_to_fpcr. */
11116 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
11117 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
11118 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
11119 | SWCR_TRAP_ENABLE_DZE
11120 | SWCR_TRAP_ENABLE_OVF)) << 48;
11121 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
11122 | SWCR_TRAP_ENABLE_INE)) << 57;
11123 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
11124 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
11125
Richard Henderson6e06d512012-06-01 09:08:21 -070011126 cpu_alpha_store_fpcr(cpu_env, fpcr);
11127 ret = 0;
11128 }
11129 break;
11130
11131 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11132 {
11133 uint64_t exc, fpcr, orig_fpcr;
11134 int si_code;
11135
11136 if (get_user_u64(exc, arg2)) {
11137 goto efault;
11138 }
11139
11140 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
11141
11142 /* We only add to the exception status here. */
11143 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
11144
11145 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011146 ret = 0;
11147
Richard Henderson6e06d512012-06-01 09:08:21 -070011148 /* Old exceptions are not signaled. */
11149 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011150
Richard Henderson6e06d512012-06-01 09:08:21 -070011151 /* If any exceptions set by this call,
11152 and are unmasked, send a signal. */
11153 si_code = 0;
11154 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11155 si_code = TARGET_FPE_FLTRES;
11156 }
11157 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11158 si_code = TARGET_FPE_FLTUND;
11159 }
11160 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11161 si_code = TARGET_FPE_FLTOVF;
11162 }
11163 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11164 si_code = TARGET_FPE_FLTDIV;
11165 }
11166 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11167 si_code = TARGET_FPE_FLTINV;
11168 }
11169 if (si_code != 0) {
11170 target_siginfo_t info;
11171 info.si_signo = SIGFPE;
11172 info.si_errno = 0;
11173 info.si_code = si_code;
11174 info._sifields._sigfault._addr
11175 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011176 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11177 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011178 }
11179 }
11180 break;
11181
11182 /* case SSI_NVPAIRS:
11183 -- Used with SSIN_UACPROC to enable unaligned accesses.
11184 case SSI_IEEE_STATE_AT_SIGNAL:
11185 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11186 -- Not implemented in linux kernel
11187 */
11188 }
11189 break;
11190#endif
11191#ifdef TARGET_NR_osf_sigprocmask
11192 /* Alpha specific. */
11193 case TARGET_NR_osf_sigprocmask:
11194 {
11195 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011196 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011197 sigset_t set, oldset;
11198
11199 switch(arg1) {
11200 case TARGET_SIG_BLOCK:
11201 how = SIG_BLOCK;
11202 break;
11203 case TARGET_SIG_UNBLOCK:
11204 how = SIG_UNBLOCK;
11205 break;
11206 case TARGET_SIG_SETMASK:
11207 how = SIG_SETMASK;
11208 break;
11209 default:
11210 ret = -TARGET_EINVAL;
11211 goto fail;
11212 }
11213 mask = arg2;
11214 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011215 ret = do_sigprocmask(how, &set, &oldset);
11216 if (!ret) {
11217 host_to_target_old_sigset(&mask, &oldset);
11218 ret = mask;
11219 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011220 }
11221 break;
11222#endif
aurel3264b4d282008-11-14 17:20:15 +000011223
bellarda315a142005-01-30 22:59:18 +000011224#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011225 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011226 ret = get_errno(getgid());
11227 break;
bellarda315a142005-01-30 22:59:18 +000011228#endif
11229#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011230 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011231 ret = get_errno(geteuid());
11232 break;
bellarda315a142005-01-30 22:59:18 +000011233#endif
11234#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011235 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011236 ret = get_errno(getegid());
11237 break;
bellarda315a142005-01-30 22:59:18 +000011238#endif
11239#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011240 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011241 ret = get_errno(setreuid(arg1, arg2));
11242 break;
bellarda315a142005-01-30 22:59:18 +000011243#endif
11244#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011245 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011246 ret = get_errno(setregid(arg1, arg2));
11247 break;
bellarda315a142005-01-30 22:59:18 +000011248#endif
11249#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011250 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011251 {
11252 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011253 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011254 gid_t *grouplist;
11255 int i;
11256
11257 grouplist = alloca(gidsetsize * sizeof(gid_t));
11258 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011259 if (gidsetsize == 0)
11260 break;
bellard99c475a2005-01-31 20:45:13 +000011261 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011262 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11263 if (!target_grouplist) {
11264 ret = -TARGET_EFAULT;
11265 goto fail;
11266 }
balroga2155fc2008-09-20 02:12:08 +000011267 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011268 target_grouplist[i] = tswap32(grouplist[i]);
11269 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011270 }
11271 }
11272 break;
bellarda315a142005-01-30 22:59:18 +000011273#endif
11274#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011275 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011276 {
11277 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011278 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011279 gid_t *grouplist;
11280 int i;
ths3b46e622007-09-17 08:09:54 +000011281
bellard99c475a2005-01-31 20:45:13 +000011282 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011283 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11284 if (!target_grouplist) {
11285 ret = -TARGET_EFAULT;
11286 goto fail;
11287 }
bellard99c475a2005-01-31 20:45:13 +000011288 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011289 grouplist[i] = tswap32(target_grouplist[i]);
11290 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011291 ret = get_errno(setgroups(gidsetsize, grouplist));
11292 }
11293 break;
bellarda315a142005-01-30 22:59:18 +000011294#endif
11295#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011296 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011297 ret = get_errno(fchown(arg1, arg2, arg3));
11298 break;
bellarda315a142005-01-30 22:59:18 +000011299#endif
11300#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011301 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011302 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011303 break;
bellarda315a142005-01-30 22:59:18 +000011304#endif
11305#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011306 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011307 {
pbrook53a59602006-03-25 19:31:22 +000011308 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011309 ret = get_errno(getresuid(&ruid, &euid, &suid));
11310 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011311 if (put_user_u32(ruid, arg1)
11312 || put_user_u32(euid, arg2)
11313 || put_user_u32(suid, arg3))
11314 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011315 }
11316 }
11317 break;
bellarda315a142005-01-30 22:59:18 +000011318#endif
11319#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011320 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011321 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011322 break;
bellarda315a142005-01-30 22:59:18 +000011323#endif
11324#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011325 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011326 {
pbrook53a59602006-03-25 19:31:22 +000011327 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011328 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11329 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011330 if (put_user_u32(rgid, arg1)
11331 || put_user_u32(egid, arg2)
11332 || put_user_u32(sgid, arg3))
11333 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011334 }
11335 }
11336 break;
bellarda315a142005-01-30 22:59:18 +000011337#endif
11338#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011339 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011340 if (!(p = lock_user_string(arg1)))
11341 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011342 ret = get_errno(chown(p, arg2, arg3));
11343 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011344 break;
bellarda315a142005-01-30 22:59:18 +000011345#endif
11346#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011347 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011348 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011349 break;
bellarda315a142005-01-30 22:59:18 +000011350#endif
11351#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011352 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011353 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011354 break;
bellarda315a142005-01-30 22:59:18 +000011355#endif
11356#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011357 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011358 ret = get_errno(setfsuid(arg1));
11359 break;
bellarda315a142005-01-30 22:59:18 +000011360#endif
11361#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011362 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011363 ret = get_errno(setfsgid(arg1));
11364 break;
bellarda315a142005-01-30 22:59:18 +000011365#endif
bellard67867302003-11-23 17:05:30 +000011366
bellard31e31b82003-02-18 22:55:36 +000011367 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011368 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011369#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011370 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011371 {
11372 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011373 ret = -TARGET_ENOMEM;
11374 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11375 if (!a) {
11376 goto fail;
11377 }
aurel3204bb9ac2008-10-01 21:46:41 +000011378 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011379 p = lock_user_string(arg3);
11380 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011381 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011382 }
aurel3204bb9ac2008-10-01 21:46:41 +000011383 ret = get_errno(mincore(a, arg2, p));
11384 unlock_user(p, arg3, ret);
11385 mincore_fail:
11386 unlock_user(a, arg1, 0);
11387 }
11388 break;
bellardffa65c32004-01-04 23:57:22 +000011389#endif
aurel32408321b2008-10-01 21:46:32 +000011390#ifdef TARGET_NR_arm_fadvise64_64
11391 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011392 /* arm_fadvise64_64 looks like fadvise64_64 but
11393 * with different argument order: fd, advice, offset, len
11394 * rather than the usual fd, offset, len, advice.
11395 * Note that offset and len are both 64-bit so appear as
11396 * pairs of 32-bit registers.
11397 */
11398 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11399 target_offset64(arg5, arg6), arg2);
11400 ret = -host_to_target_errno(ret);
11401 break;
aurel32408321b2008-10-01 21:46:32 +000011402#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011403
11404#if TARGET_ABI_BITS == 32
11405
11406#ifdef TARGET_NR_fadvise64_64
11407 case TARGET_NR_fadvise64_64:
Laurent Vivier43046b52017-03-02 01:11:45 +010011408#if defined(TARGET_PPC)
11409 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11410 ret = arg2;
11411 arg2 = arg3;
11412 arg3 = arg4;
11413 arg4 = arg5;
11414 arg5 = arg6;
11415 arg6 = ret;
11416#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011417 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011418 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011419 /* offset is in (3,4), len in (5,6) and advice in 7 */
11420 arg2 = arg3;
11421 arg3 = arg4;
11422 arg4 = arg5;
11423 arg5 = arg6;
11424 arg6 = arg7;
11425 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011426#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011427 ret = -host_to_target_errno(posix_fadvise(arg1,
11428 target_offset64(arg2, arg3),
11429 target_offset64(arg4, arg5),
11430 arg6));
11431 break;
11432#endif
11433
11434#ifdef TARGET_NR_fadvise64
11435 case TARGET_NR_fadvise64:
11436 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011437 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011438 /* offset is in (3,4), len in 5 and advice in 6 */
11439 arg2 = arg3;
11440 arg3 = arg4;
11441 arg4 = arg5;
11442 arg5 = arg6;
11443 }
11444 ret = -host_to_target_errno(posix_fadvise(arg1,
11445 target_offset64(arg2, arg3),
11446 arg4, arg5));
11447 break;
11448#endif
11449
11450#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011451#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011452#ifdef TARGET_NR_fadvise64_64
11453 case TARGET_NR_fadvise64_64:
11454#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011455#ifdef TARGET_NR_fadvise64
11456 case TARGET_NR_fadvise64:
11457#endif
11458#ifdef TARGET_S390X
11459 switch (arg4) {
11460 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11461 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11462 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11463 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11464 default: break;
11465 }
11466#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011467 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11468 break;
aurel32408321b2008-10-01 21:46:32 +000011469#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011470#endif /* end of 64-bit ABI fadvise handling */
11471
bellardffa65c32004-01-04 23:57:22 +000011472#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011473 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011474 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011475 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011476 This will break MADV_DONTNEED.
11477 This is a hint, so ignoring and returning success is ok. */
11478 ret = get_errno(0);
11479 break;
bellardffa65c32004-01-04 23:57:22 +000011480#endif
blueswir1992f48a2007-10-14 16:27:31 +000011481#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011482 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011483 {
thsb1e341e2007-03-20 21:50:52 +000011484 int cmd;
bellard77e46722003-04-29 20:39:06 +000011485 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011486 from_flock64_fn *copyfrom = copy_from_user_flock64;
11487 to_flock64_fn *copyto = copy_to_user_flock64;
11488
pbrookce4defa2006-02-09 16:49:55 +000011489#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010011490 if (((CPUARMState *)cpu_env)->eabi) {
11491 copyfrom = copy_from_user_eabi_flock64;
11492 copyto = copy_to_user_eabi_flock64;
11493 }
pbrookce4defa2006-02-09 16:49:55 +000011494#endif
bellard77e46722003-04-29 20:39:06 +000011495
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011496 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011497 if (cmd == -TARGET_EINVAL) {
11498 ret = cmd;
11499 break;
11500 }
thsb1e341e2007-03-20 21:50:52 +000011501
bellard60cd49d2003-03-16 22:53:56 +000011502 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011503 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011504 ret = copyfrom(&fl, arg3);
11505 if (ret) {
11506 break;
ths58134272007-03-31 18:59:32 +000011507 }
thsb1e341e2007-03-20 21:50:52 +000011508 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011509 if (ret == 0) {
11510 ret = copyto(arg3, &fl);
11511 }
bellard77e46722003-04-29 20:39:06 +000011512 break;
11513
thsb1e341e2007-03-20 21:50:52 +000011514 case TARGET_F_SETLK64:
11515 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011516 ret = copyfrom(&fl, arg3);
11517 if (ret) {
11518 break;
pbrookce4defa2006-02-09 16:49:55 +000011519 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011520 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011521 break;
bellard60cd49d2003-03-16 22:53:56 +000011522 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011523 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011524 break;
11525 }
bellard77e46722003-04-29 20:39:06 +000011526 break;
11527 }
bellard60cd49d2003-03-16 22:53:56 +000011528#endif
ths7d600c82006-12-08 01:32:58 +000011529#ifdef TARGET_NR_cacheflush
11530 case TARGET_NR_cacheflush:
11531 /* self-modifying code is handled automatically, so nothing needed */
11532 ret = 0;
11533 break;
11534#endif
bellardebc05482003-09-30 21:08:41 +000011535#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011536 case TARGET_NR_security:
11537 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011538#endif
bellardc573ff62004-01-04 15:51:36 +000011539#ifdef TARGET_NR_getpagesize
11540 case TARGET_NR_getpagesize:
11541 ret = TARGET_PAGE_SIZE;
11542 break;
11543#endif
bellard31e31b82003-02-18 22:55:36 +000011544 case TARGET_NR_gettid:
11545 ret = get_errno(gettid());
11546 break;
thse5febef2007-04-01 18:31:35 +000011547#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011548 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011549#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011550 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011551 arg2 = arg3;
11552 arg3 = arg4;
11553 arg4 = arg5;
11554 }
Lena Djokic77c68502016-11-24 17:08:56 +010011555 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011556#else
11557 ret = get_errno(readahead(arg1, arg2, arg3));
11558#endif
11559 break;
thse5febef2007-04-01 18:31:35 +000011560#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011561#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011562#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011563 case TARGET_NR_listxattr:
11564 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011565 {
11566 void *p, *b = 0;
11567 if (arg2) {
11568 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11569 if (!b) {
11570 ret = -TARGET_EFAULT;
11571 break;
11572 }
11573 }
11574 p = lock_user_string(arg1);
11575 if (p) {
11576 if (num == TARGET_NR_listxattr) {
11577 ret = get_errno(listxattr(p, b, arg3));
11578 } else {
11579 ret = get_errno(llistxattr(p, b, arg3));
11580 }
11581 } else {
11582 ret = -TARGET_EFAULT;
11583 }
11584 unlock_user(p, arg1, 0);
11585 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011586 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011587 }
11588 case TARGET_NR_flistxattr:
11589 {
11590 void *b = 0;
11591 if (arg2) {
11592 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11593 if (!b) {
11594 ret = -TARGET_EFAULT;
11595 break;
11596 }
11597 }
11598 ret = get_errno(flistxattr(arg1, b, arg3));
11599 unlock_user(b, arg2, arg3);
11600 break;
11601 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011602 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011603 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011604 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011605 void *p, *n, *v = 0;
11606 if (arg3) {
11607 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11608 if (!v) {
11609 ret = -TARGET_EFAULT;
11610 break;
11611 }
11612 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011613 p = lock_user_string(arg1);
11614 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011615 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011616 if (num == TARGET_NR_setxattr) {
11617 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11618 } else {
11619 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11620 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011621 } else {
11622 ret = -TARGET_EFAULT;
11623 }
11624 unlock_user(p, arg1, 0);
11625 unlock_user(n, arg2, 0);
11626 unlock_user(v, arg3, 0);
11627 }
11628 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011629 case TARGET_NR_fsetxattr:
11630 {
11631 void *n, *v = 0;
11632 if (arg3) {
11633 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11634 if (!v) {
11635 ret = -TARGET_EFAULT;
11636 break;
11637 }
11638 }
11639 n = lock_user_string(arg2);
11640 if (n) {
11641 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11642 } else {
11643 ret = -TARGET_EFAULT;
11644 }
11645 unlock_user(n, arg2, 0);
11646 unlock_user(v, arg3, 0);
11647 }
11648 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011649 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011650 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011651 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011652 void *p, *n, *v = 0;
11653 if (arg3) {
11654 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11655 if (!v) {
11656 ret = -TARGET_EFAULT;
11657 break;
11658 }
11659 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011660 p = lock_user_string(arg1);
11661 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011662 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011663 if (num == TARGET_NR_getxattr) {
11664 ret = get_errno(getxattr(p, n, v, arg4));
11665 } else {
11666 ret = get_errno(lgetxattr(p, n, v, arg4));
11667 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011668 } else {
11669 ret = -TARGET_EFAULT;
11670 }
11671 unlock_user(p, arg1, 0);
11672 unlock_user(n, arg2, 0);
11673 unlock_user(v, arg3, arg4);
11674 }
11675 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011676 case TARGET_NR_fgetxattr:
11677 {
11678 void *n, *v = 0;
11679 if (arg3) {
11680 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11681 if (!v) {
11682 ret = -TARGET_EFAULT;
11683 break;
11684 }
11685 }
11686 n = lock_user_string(arg2);
11687 if (n) {
11688 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11689 } else {
11690 ret = -TARGET_EFAULT;
11691 }
11692 unlock_user(n, arg2, 0);
11693 unlock_user(v, arg3, arg4);
11694 }
11695 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011696 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011697 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011698 {
11699 void *p, *n;
11700 p = lock_user_string(arg1);
11701 n = lock_user_string(arg2);
11702 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011703 if (num == TARGET_NR_removexattr) {
11704 ret = get_errno(removexattr(p, n));
11705 } else {
11706 ret = get_errno(lremovexattr(p, n));
11707 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011708 } else {
11709 ret = -TARGET_EFAULT;
11710 }
11711 unlock_user(p, arg1, 0);
11712 unlock_user(n, arg2, 0);
11713 }
11714 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011715 case TARGET_NR_fremovexattr:
11716 {
11717 void *n;
11718 n = lock_user_string(arg2);
11719 if (n) {
11720 ret = get_errno(fremovexattr(arg1, n));
11721 } else {
11722 ret = -TARGET_EFAULT;
11723 }
11724 unlock_user(n, arg2, 0);
11725 }
11726 break;
bellardebc05482003-09-30 21:08:41 +000011727#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011728#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011729#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011730 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011731#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011732 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011733 ret = 0;
11734 break;
edgar_iglef967792009-01-07 14:19:38 +000011735#elif defined(TARGET_CRIS)
11736 if (arg1 & 0xff)
11737 ret = -TARGET_EINVAL;
11738 else {
11739 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11740 ret = 0;
11741 }
11742 break;
bellard8d18e892007-11-14 15:18:40 +000011743#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11744 ret = do_set_thread_area(cpu_env, arg1);
11745 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011746#elif defined(TARGET_M68K)
11747 {
Andreas Färber0429a972013-08-26 18:14:44 +020011748 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011749 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011750 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011751 break;
11752 }
ths6f5b89a2007-03-02 20:48:00 +000011753#else
11754 goto unimplemented_nowarn;
11755#endif
11756#endif
11757#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011758 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011759#if defined(TARGET_I386) && defined(TARGET_ABI32)
11760 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011761 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011762#elif defined(TARGET_M68K)
11763 {
Andreas Färber0429a972013-08-26 18:14:44 +020011764 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011765 ret = ts->tp_value;
11766 break;
11767 }
bellard8d18e892007-11-14 15:18:40 +000011768#else
bellard5cd43932003-03-29 16:54:36 +000011769 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011770#endif
bellard8d18e892007-11-14 15:18:40 +000011771#endif
bellard48dc41e2006-06-21 18:15:50 +000011772#ifdef TARGET_NR_getdomainname
11773 case TARGET_NR_getdomainname:
11774 goto unimplemented_nowarn;
11775#endif
ths6f5b89a2007-03-02 20:48:00 +000011776
thsb5906f92007-03-19 13:32:45 +000011777#ifdef TARGET_NR_clock_gettime
11778 case TARGET_NR_clock_gettime:
11779 {
11780 struct timespec ts;
11781 ret = get_errno(clock_gettime(arg1, &ts));
11782 if (!is_error(ret)) {
11783 host_to_target_timespec(arg2, &ts);
11784 }
11785 break;
11786 }
11787#endif
11788#ifdef TARGET_NR_clock_getres
11789 case TARGET_NR_clock_getres:
11790 {
11791 struct timespec ts;
11792 ret = get_errno(clock_getres(arg1, &ts));
11793 if (!is_error(ret)) {
11794 host_to_target_timespec(arg2, &ts);
11795 }
11796 break;
11797 }
11798#endif
pbrook63d76512008-05-29 13:43:29 +000011799#ifdef TARGET_NR_clock_nanosleep
11800 case TARGET_NR_clock_nanosleep:
11801 {
11802 struct timespec ts;
11803 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011804 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11805 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011806 if (arg4)
11807 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011808
11809#if defined(TARGET_PPC)
11810 /* clock_nanosleep is odd in that it returns positive errno values.
11811 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011812 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011813 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11814 }
11815#endif
pbrook63d76512008-05-29 13:43:29 +000011816 break;
11817 }
11818#endif
thsb5906f92007-03-19 13:32:45 +000011819
ths6f5b89a2007-03-02 20:48:00 +000011820#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11821 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011822 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11823 break;
ths6f5b89a2007-03-02 20:48:00 +000011824#endif
11825
ths4cae1d12007-07-12 11:06:53 +000011826 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011827 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011828 break;
ths4cae1d12007-07-12 11:06:53 +000011829
ths71455572007-06-21 21:45:30 +000011830 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011831 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011832 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011833 break;
ths71455572007-06-21 21:45:30 +000011834
ths4f2b1fe2007-06-21 21:57:12 +000011835#ifdef TARGET_NR_set_robust_list
11836 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011837 case TARGET_NR_get_robust_list:
11838 /* The ABI for supporting robust futexes has userspace pass
11839 * the kernel a pointer to a linked list which is updated by
11840 * userspace after the syscall; the list is walked by the kernel
11841 * when the thread exits. Since the linked list in QEMU guest
11842 * memory isn't a valid linked list for the host and we have
11843 * no way to reliably intercept the thread-death event, we can't
11844 * support these. Silently return ENOSYS so that guest userspace
11845 * falls back to a non-robust futex implementation (which should
11846 * be OK except in the corner case of the guest crashing while
11847 * holding a mutex that is shared with another process via
11848 * shared memory).
11849 */
11850 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011851#endif
11852
Peter Maydell1acae9f2013-07-02 14:04:12 +010011853#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011854 case TARGET_NR_utimensat:
11855 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011856 struct timespec *tsp, ts[2];
11857 if (!arg3) {
11858 tsp = NULL;
11859 } else {
11860 target_to_host_timespec(ts, arg3);
11861 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11862 tsp = ts;
11863 }
ths9007f0e2007-09-25 17:50:37 +000011864 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011865 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011866 else {
bellard579a97f2007-11-11 14:26:47 +000011867 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011868 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011869 goto fail;
11870 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011871 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011872 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011873 }
11874 }
11875 break;
11876#endif
pbrookbd0c5662008-05-29 14:34:11 +000011877 case TARGET_NR_futex:
11878 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11879 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011880#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011881 case TARGET_NR_inotify_init:
11882 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011883 if (ret >= 0) {
11884 fd_trans_register(ret, &target_inotify_trans);
11885 }
aurel3239b59762008-10-01 21:46:50 +000011886 break;
11887#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011888#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011889#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11890 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010011891 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
11892 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011893 if (ret >= 0) {
11894 fd_trans_register(ret, &target_inotify_trans);
11895 }
Riku Voipioc05c7a72010-03-26 15:25:11 +000011896 break;
11897#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011898#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011899#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011900 case TARGET_NR_inotify_add_watch:
11901 p = lock_user_string(arg2);
11902 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11903 unlock_user(p, arg2, 0);
11904 break;
11905#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011906#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011907 case TARGET_NR_inotify_rm_watch:
11908 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
11909 break;
11910#endif
ths9007f0e2007-09-25 17:50:37 +000011911
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011912#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011913 case TARGET_NR_mq_open:
11914 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011915 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010011916 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011917 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000011918
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011919 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010011920 pposix_mq_attr = NULL;
11921 if (arg4) {
11922 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
11923 goto efault;
11924 }
11925 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050011926 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011927 p = lock_user_string(arg1 - 1);
11928 if (!p) {
11929 goto efault;
11930 }
Lena Djokic26400772016-11-24 17:08:58 +010011931 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000011932 unlock_user (p, arg1, 0);
11933 }
11934 break;
11935
11936 case TARGET_NR_mq_unlink:
11937 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010011938 if (!p) {
11939 ret = -TARGET_EFAULT;
11940 break;
11941 }
aurel3224e10032009-04-15 16:11:43 +000011942 ret = get_errno(mq_unlink(p));
11943 unlock_user (p, arg1, 0);
11944 break;
11945
11946 case TARGET_NR_mq_timedsend:
11947 {
11948 struct timespec ts;
11949
11950 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11951 if (arg5 != 0) {
11952 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011953 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011954 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011955 } else {
11956 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011957 }
aurel3224e10032009-04-15 16:11:43 +000011958 unlock_user (p, arg2, arg3);
11959 }
11960 break;
11961
11962 case TARGET_NR_mq_timedreceive:
11963 {
11964 struct timespec ts;
11965 unsigned int prio;
11966
11967 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11968 if (arg5 != 0) {
11969 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011970 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11971 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011972 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011973 } else {
11974 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11975 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011976 }
aurel3224e10032009-04-15 16:11:43 +000011977 unlock_user (p, arg2, arg3);
11978 if (arg4 != 0)
11979 put_user_u32(prio, arg4);
11980 }
11981 break;
11982
11983 /* Not implemented for now... */
11984/* case TARGET_NR_mq_notify: */
11985/* break; */
11986
11987 case TARGET_NR_mq_getsetattr:
11988 {
11989 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11990 ret = 0;
11991 if (arg3 != 0) {
11992 ret = mq_getattr(arg1, &posix_mq_attr_out);
11993 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11994 }
11995 if (arg2 != 0) {
11996 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
11997 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
11998 }
11999
12000 }
12001 break;
12002#endif
12003
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012004#ifdef CONFIG_SPLICE
12005#ifdef TARGET_NR_tee
12006 case TARGET_NR_tee:
12007 {
12008 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12009 }
12010 break;
12011#endif
12012#ifdef TARGET_NR_splice
12013 case TARGET_NR_splice:
12014 {
12015 loff_t loff_in, loff_out;
12016 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012017 if (arg2) {
12018 if (get_user_u64(loff_in, arg2)) {
12019 goto efault;
12020 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012021 ploff_in = &loff_in;
12022 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012023 if (arg4) {
12024 if (get_user_u64(loff_out, arg4)) {
12025 goto efault;
12026 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012027 ploff_out = &loff_out;
12028 }
12029 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012030 if (arg2) {
12031 if (put_user_u64(loff_in, arg2)) {
12032 goto efault;
12033 }
12034 }
12035 if (arg4) {
12036 if (put_user_u64(loff_out, arg4)) {
12037 goto efault;
12038 }
12039 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012040 }
12041 break;
12042#endif
12043#ifdef TARGET_NR_vmsplice
12044 case TARGET_NR_vmsplice:
12045 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012046 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12047 if (vec != NULL) {
12048 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12049 unlock_iovec(vec, arg2, arg3, 0);
12050 } else {
12051 ret = -host_to_target_errno(errno);
12052 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012053 }
12054 break;
12055#endif
12056#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012057#ifdef CONFIG_EVENTFD
12058#if defined(TARGET_NR_eventfd)
12059 case TARGET_NR_eventfd:
12060 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012061 if (ret >= 0) {
12062 fd_trans_register(ret, &target_eventfd_trans);
12063 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012064 break;
12065#endif
12066#if defined(TARGET_NR_eventfd2)
12067 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012068 {
12069 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12070 if (arg2 & TARGET_O_NONBLOCK) {
12071 host_flags |= O_NONBLOCK;
12072 }
12073 if (arg2 & TARGET_O_CLOEXEC) {
12074 host_flags |= O_CLOEXEC;
12075 }
12076 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012077 if (ret >= 0) {
12078 fd_trans_register(ret, &target_eventfd_trans);
12079 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012080 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012081 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012082#endif
12083#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012084#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12085 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012086#if TARGET_ABI_BITS == 32
12087 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12088 target_offset64(arg5, arg6)));
12089#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012090 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012091#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030012092 break;
12093#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012094#if defined(CONFIG_SYNC_FILE_RANGE)
12095#if defined(TARGET_NR_sync_file_range)
12096 case TARGET_NR_sync_file_range:
12097#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012098#if defined(TARGET_MIPS)
12099 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12100 target_offset64(arg5, arg6), arg7));
12101#else
Peter Maydellc727f472011-01-06 11:05:10 +000012102 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12103 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012104#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012105#else
12106 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12107#endif
12108 break;
12109#endif
12110#if defined(TARGET_NR_sync_file_range2)
12111 case TARGET_NR_sync_file_range2:
12112 /* This is like sync_file_range but the arguments are reordered */
12113#if TARGET_ABI_BITS == 32
12114 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12115 target_offset64(arg5, arg6), arg2));
12116#else
12117 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12118#endif
12119 break;
12120#endif
12121#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012122#if defined(TARGET_NR_signalfd4)
12123 case TARGET_NR_signalfd4:
12124 ret = do_signalfd4(arg1, arg2, arg4);
12125 break;
12126#endif
12127#if defined(TARGET_NR_signalfd)
12128 case TARGET_NR_signalfd:
12129 ret = do_signalfd4(arg1, arg2, 0);
12130 break;
12131#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012132#if defined(CONFIG_EPOLL)
12133#if defined(TARGET_NR_epoll_create)
12134 case TARGET_NR_epoll_create:
12135 ret = get_errno(epoll_create(arg1));
12136 break;
12137#endif
12138#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12139 case TARGET_NR_epoll_create1:
12140 ret = get_errno(epoll_create1(arg1));
12141 break;
12142#endif
12143#if defined(TARGET_NR_epoll_ctl)
12144 case TARGET_NR_epoll_ctl:
12145 {
12146 struct epoll_event ep;
12147 struct epoll_event *epp = 0;
12148 if (arg4) {
12149 struct target_epoll_event *target_ep;
12150 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
12151 goto efault;
12152 }
12153 ep.events = tswap32(target_ep->events);
12154 /* The epoll_data_t union is just opaque data to the kernel,
12155 * so we transfer all 64 bits across and need not worry what
12156 * actual data type it is.
12157 */
12158 ep.data.u64 = tswap64(target_ep->data.u64);
12159 unlock_user_struct(target_ep, arg4, 0);
12160 epp = &ep;
12161 }
12162 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12163 break;
12164 }
12165#endif
12166
Peter Maydell227f0212016-06-06 19:58:11 +010012167#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012168#if defined(TARGET_NR_epoll_wait)
12169 case TARGET_NR_epoll_wait:
12170#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012171#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012172 case TARGET_NR_epoll_pwait:
12173#endif
12174 {
12175 struct target_epoll_event *target_ep;
12176 struct epoll_event *ep;
12177 int epfd = arg1;
12178 int maxevents = arg3;
12179 int timeout = arg4;
12180
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012181 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12182 ret = -TARGET_EINVAL;
12183 break;
12184 }
12185
Peter Maydell3b6edd12011-02-15 18:35:05 +000012186 target_ep = lock_user(VERIFY_WRITE, arg2,
12187 maxevents * sizeof(struct target_epoll_event), 1);
12188 if (!target_ep) {
12189 goto efault;
12190 }
12191
Peter Maydell04c95f42016-07-18 15:36:00 +010012192 ep = g_try_new(struct epoll_event, maxevents);
12193 if (!ep) {
12194 unlock_user(target_ep, arg2, 0);
12195 ret = -TARGET_ENOMEM;
12196 break;
12197 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012198
12199 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012200#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012201 case TARGET_NR_epoll_pwait:
12202 {
12203 target_sigset_t *target_set;
12204 sigset_t _set, *set = &_set;
12205
12206 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012207 if (arg6 != sizeof(target_sigset_t)) {
12208 ret = -TARGET_EINVAL;
12209 break;
12210 }
12211
Peter Maydell3b6edd12011-02-15 18:35:05 +000012212 target_set = lock_user(VERIFY_READ, arg5,
12213 sizeof(target_sigset_t), 1);
12214 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012215 ret = -TARGET_EFAULT;
12216 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012217 }
12218 target_to_host_sigset(set, target_set);
12219 unlock_user(target_set, arg5, 0);
12220 } else {
12221 set = NULL;
12222 }
12223
Peter Maydell227f0212016-06-06 19:58:11 +010012224 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12225 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012226 break;
12227 }
12228#endif
12229#if defined(TARGET_NR_epoll_wait)
12230 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012231 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12232 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012233 break;
12234#endif
12235 default:
12236 ret = -TARGET_ENOSYS;
12237 }
12238 if (!is_error(ret)) {
12239 int i;
12240 for (i = 0; i < ret; i++) {
12241 target_ep[i].events = tswap32(ep[i].events);
12242 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12243 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012244 unlock_user(target_ep, arg2,
12245 ret * sizeof(struct target_epoll_event));
12246 } else {
12247 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012248 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012249 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012250 break;
12251 }
12252#endif
12253#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012254#ifdef TARGET_NR_prlimit64
12255 case TARGET_NR_prlimit64:
12256 {
12257 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12258 struct target_rlimit64 *target_rnew, *target_rold;
12259 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012260 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012261 if (arg3) {
12262 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12263 goto efault;
12264 }
12265 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12266 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12267 unlock_user_struct(target_rnew, arg3, 0);
12268 rnewp = &rnew;
12269 }
12270
Felix Janda95018012014-12-02 22:11:17 +010012271 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012272 if (!is_error(ret) && arg4) {
12273 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12274 goto efault;
12275 }
12276 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12277 target_rold->rlim_max = tswap64(rold.rlim_max);
12278 unlock_user_struct(target_rold, arg4, 1);
12279 }
12280 break;
12281 }
12282#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012283#ifdef TARGET_NR_gethostname
12284 case TARGET_NR_gethostname:
12285 {
12286 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12287 if (name) {
12288 ret = get_errno(gethostname(name, arg2));
12289 unlock_user(name, arg1, arg2);
12290 } else {
12291 ret = -TARGET_EFAULT;
12292 }
12293 break;
12294 }
12295#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012296#ifdef TARGET_NR_atomic_cmpxchg_32
12297 case TARGET_NR_atomic_cmpxchg_32:
12298 {
12299 /* should use start_exclusive from main.c */
12300 abi_ulong mem_value;
12301 if (get_user_u32(mem_value, arg6)) {
12302 target_siginfo_t info;
12303 info.si_signo = SIGSEGV;
12304 info.si_errno = 0;
12305 info.si_code = TARGET_SEGV_MAPERR;
12306 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012307 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12308 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012309 ret = 0xdeadbeef;
12310
12311 }
12312 if (mem_value == arg2)
12313 put_user_u32(arg1, arg6);
12314 ret = mem_value;
12315 break;
12316 }
12317#endif
12318#ifdef TARGET_NR_atomic_barrier
12319 case TARGET_NR_atomic_barrier:
12320 {
12321 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012322 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012323 break;
12324 }
12325#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012326
12327#ifdef TARGET_NR_timer_create
12328 case TARGET_NR_timer_create:
12329 {
12330 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12331
12332 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012333
12334 int clkid = arg1;
12335 int timer_index = next_free_host_timer();
12336
12337 if (timer_index < 0) {
12338 ret = -TARGET_EAGAIN;
12339 } else {
12340 timer_t *phtimer = g_posix_timers + timer_index;
12341
12342 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012343 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012344 ret = target_to_host_sigevent(phost_sevp, arg2);
12345 if (ret != 0) {
12346 break;
12347 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012348 }
12349
12350 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12351 if (ret) {
12352 phtimer = NULL;
12353 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012354 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012355 goto efault;
12356 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012357 }
12358 }
12359 break;
12360 }
12361#endif
12362
12363#ifdef TARGET_NR_timer_settime
12364 case TARGET_NR_timer_settime:
12365 {
12366 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12367 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012368 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012369
Alexander Grafaecc8862014-11-10 21:33:03 +010012370 if (timerid < 0) {
12371 ret = timerid;
12372 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012373 ret = -TARGET_EINVAL;
12374 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012375 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012376 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12377
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012378 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12379 goto efault;
12380 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012381 ret = get_errno(
12382 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012383 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12384 goto efault;
12385 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012386 }
12387 break;
12388 }
12389#endif
12390
12391#ifdef TARGET_NR_timer_gettime
12392 case TARGET_NR_timer_gettime:
12393 {
12394 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012395 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012396
Alexander Grafaecc8862014-11-10 21:33:03 +010012397 if (timerid < 0) {
12398 ret = timerid;
12399 } else if (!arg2) {
12400 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012401 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012402 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012403 struct itimerspec hspec;
12404 ret = get_errno(timer_gettime(htimer, &hspec));
12405
12406 if (host_to_target_itimerspec(arg2, &hspec)) {
12407 ret = -TARGET_EFAULT;
12408 }
12409 }
12410 break;
12411 }
12412#endif
12413
12414#ifdef TARGET_NR_timer_getoverrun
12415 case TARGET_NR_timer_getoverrun:
12416 {
12417 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012418 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012419
Alexander Grafaecc8862014-11-10 21:33:03 +010012420 if (timerid < 0) {
12421 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012422 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012423 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012424 ret = get_errno(timer_getoverrun(htimer));
12425 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012426 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012427 break;
12428 }
12429#endif
12430
12431#ifdef TARGET_NR_timer_delete
12432 case TARGET_NR_timer_delete:
12433 {
12434 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012435 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012436
Alexander Grafaecc8862014-11-10 21:33:03 +010012437 if (timerid < 0) {
12438 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012439 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012440 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012441 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012442 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012443 }
12444 break;
12445 }
12446#endif
12447
Riku Voipio51834342014-06-22 11:25:42 +010012448#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12449 case TARGET_NR_timerfd_create:
12450 ret = get_errno(timerfd_create(arg1,
12451 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12452 break;
12453#endif
12454
12455#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12456 case TARGET_NR_timerfd_gettime:
12457 {
12458 struct itimerspec its_curr;
12459
12460 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12461
12462 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12463 goto efault;
12464 }
12465 }
12466 break;
12467#endif
12468
12469#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12470 case TARGET_NR_timerfd_settime:
12471 {
12472 struct itimerspec its_new, its_old, *p_new;
12473
12474 if (arg3) {
12475 if (target_to_host_itimerspec(&its_new, arg3)) {
12476 goto efault;
12477 }
12478 p_new = &its_new;
12479 } else {
12480 p_new = NULL;
12481 }
12482
12483 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12484
12485 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12486 goto efault;
12487 }
12488 }
12489 break;
12490#endif
12491
Paul Burtonab31cda2014-06-22 11:25:43 +010012492#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12493 case TARGET_NR_ioprio_get:
12494 ret = get_errno(ioprio_get(arg1, arg2));
12495 break;
12496#endif
12497
12498#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12499 case TARGET_NR_ioprio_set:
12500 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12501 break;
12502#endif
12503
Riku Voipio9af5c902014-08-12 15:58:57 +030012504#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12505 case TARGET_NR_setns:
12506 ret = get_errno(setns(arg1, arg2));
12507 break;
12508#endif
12509#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12510 case TARGET_NR_unshare:
12511 ret = get_errno(unshare(arg1));
12512 break;
12513#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012514#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12515 case TARGET_NR_kcmp:
12516 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12517 break;
12518#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012519
bellard31e31b82003-02-18 22:55:36 +000012520 default:
12521 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000012522 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012523#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 +000012524 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012525#endif
ths0da46a62007-10-20 20:23:07 +000012526 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012527 break;
12528 }
bellard579a97f2007-11-11 14:26:47 +000012529fail:
bellardc573ff62004-01-04 15:51:36 +000012530#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012531 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012532#endif
thsb92c47c2007-11-01 00:07:38 +000012533 if(do_strace)
12534 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020012535 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012536 return ret;
bellard579a97f2007-11-11 14:26:47 +000012537efault:
12538 ret = -TARGET_EFAULT;
12539 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012540}